Compare commits
No commits in common. "cd035198f5d1f0d8079bbb76a9e2e7638383dc3a" and "9715d958ae2a439b55a08115411397f545aa7c4d" have entirely different histories.
cd035198f5
...
9715d958ae
361
CHANGELOG.md
361
CHANGELOG.md
@ -1,361 +0,0 @@
|
|||||||
# **AI Notes – Changelog**
|
|
||||||
|
|
||||||
## **Tim Pengembang**
|
|
||||||
|
|
||||||
* Dendi Yogia Pratama
|
|
||||||
* Raihan Ariq Muzakki
|
|
||||||
* Fazri Abdurrahman
|
|
||||||
|
|
||||||
# **Version 1.0.0 – Initial Release**
|
|
||||||
|
|
||||||
## **Sprint 1: Struktur Dasar Aplikasi**
|
|
||||||
|
|
||||||
### **Struktur & Navigation**
|
|
||||||
* **Setup navigation system** - Implementasi routing antar halaman (Beranda, Arsip, Sampah)
|
|
||||||
* **Menu Drawer** - Navigation drawer dengan list menu (Beranda, Berbintang, Arsip, Sampah)
|
|
||||||
* **Bottom Navigation** - Home & AI Helper tabs dengan icon navigation
|
|
||||||
* **Top App Bar** - Menu hamburger dan search icon dengan Material3 styling
|
|
||||||
* **Screen Architecture** - Pembuatan screen Arsip, Sampah, Berbintang, AI Helper
|
|
||||||
|
|
||||||
### **Theme & Styling**
|
|
||||||
* **Material3 Dark Theme** - Setup color scheme dengan dark mode default
|
|
||||||
* **Color System** - Primary/Secondary colors dengan gradient presets (8 kombinasi warna)
|
|
||||||
* **Consistent Design** - Rounded corners (12dp, 16dp, 20dp), shadow, elevation
|
|
||||||
* **Smooth Animations** - Drawer slide, FAB scale, card transitions dengan spring animations
|
|
||||||
* **Typography System** - Optimasi font sizes dan line heights untuk readability
|
|
||||||
|
|
||||||
### **Category Management**
|
|
||||||
* **Category Model** - Data class dengan gradient colors dan timestamp
|
|
||||||
* **Category Dialog** - Form tambah/edit kategori dengan nama + gradient picker
|
|
||||||
* **Category Card** - Design dengan icon folder, nama, jumlah catatan, gradient background
|
|
||||||
* **Staggered Grid Layout** - 2 kolom responsive dengan LazyVerticalStaggeredGrid
|
|
||||||
* **Category Actions** - Menu dropdown (⋮) untuk edit dan delete kategori
|
|
||||||
* **Empty State** - Pesan "Buat kategori pertama Anda" dengan icon
|
|
||||||
|
|
||||||
### **Note Management**
|
|
||||||
* **Note Model** - Data class dengan title, content, timestamp, isPinned, isArchived
|
|
||||||
* **Note Dialog** - Form dengan judul, deskripsi, simpan, batal, hapus
|
|
||||||
* **Note Card** - Preview dengan judul, deskripsi, timestamp, pin icon
|
|
||||||
* **Full-screen Editor** - Editable note view dengan auto-save dan actions
|
|
||||||
* **Pin Feature** - Toggle pin/unpin untuk catatan penting dengan sorting priority
|
|
||||||
* **Archive & Delete** - Actions untuk arsip dan soft delete notes
|
|
||||||
* **Search Functionality** - Real-time search berdasarkan judul dan isi (case-insensitive)
|
|
||||||
* **Smart Sorting** - Berdasarkan pin status dan timestamp (descending)
|
|
||||||
|
|
||||||
### **AI Assistant**
|
|
||||||
* **Gemini AI Integration** - Setup Google Generative AI SDK dengan gemini-2.5-flash
|
|
||||||
* **AI Helper Screen** - Layout chat interface dengan header dan statistics
|
|
||||||
* **Category Context Selector** - Dropdown untuk filter konteks AI berdasarkan kategori
|
|
||||||
* **Statistics Display** - Total catatan, pinned notes, jumlah kategori
|
|
||||||
* **Chat Interface** - User & AI bubble dengan different styling dan timestamp
|
|
||||||
* **Prompt Engineering** - Context builder dengan data catatan user (max 10 terbaru)
|
|
||||||
* **Suggestion Chips** - Quick question templates untuk user guidance
|
|
||||||
* **Copy to Clipboard** - Copy jawaban AI dengan confirmation feedback
|
|
||||||
* **Loading & Error States** - Circular progress indicator dan error messages
|
|
||||||
* **API Configuration** - Temperature 0.8, topK 40, topP 0.95, maxOutputTokens 4096
|
|
||||||
* **Auto-scroll Chat** - Scroll ke bottom otomatis dengan LaunchedEffect
|
|
||||||
|
|
||||||
### **Data Persistence**
|
|
||||||
* **DataStore Implementation** - Preferences DataStore untuk local storage
|
|
||||||
* **DataStoreManager Class** - Centralized dengan categoriesFlow & notesFlow
|
|
||||||
* **Auto-save dengan Debounce** - 500ms delay untuk optimize I/O operations
|
|
||||||
* **Flow-based Loading** - Reactive data loading dengan Flow collection
|
|
||||||
* **Error Handling** - Try-catch untuk semua I/O operations
|
|
||||||
* **Serializable Models** - JSON serialization dengan extension functions
|
|
||||||
|
|
||||||
### **UI/UX Enhancements**
|
|
||||||
* **Visual Feedback** - Click ripples, copy confirmation, loading states
|
|
||||||
* **Empty States** - Icon + descriptive messages untuk setiap screen
|
|
||||||
* **Confirmation Dialogs** - AlertDialog untuk arsip, hapus, delete actions
|
|
||||||
* **Search Empty State** - "Tidak ada hasil" message saat search kosong
|
|
||||||
* **Custom TextField** - Styled text input dengan consistent design
|
|
||||||
* **Date Formatter Utility** - Format timestamp ke readable Indonesian format
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **Sprint 2: Project Restructuring & Advanced Features**
|
|
||||||
|
|
||||||
### **Project Architecture**
|
|
||||||
* **Clean Architecture Migration** - Dari 3 file monolith ke modular structure
|
|
||||||
* **Data Layer Separation** - Models ke `data/model/` (Category, Note, ChatMessage)
|
|
||||||
* **Local Storage Layer** - DataStoreManager ke `data/local/` dengan PreferencesKeys
|
|
||||||
* **Component Extraction** - Screen components ke folder terpisah (main, starred, archive, trash)
|
|
||||||
* **Utilities Creation** - Constants.kt, DateFormatter.kt, Extensions.kt untuk reusability
|
|
||||||
* **Import Optimization** - Update semua import sesuai package structure baru
|
|
||||||
|
|
||||||
### **Search & Filter**
|
|
||||||
* **Beranda Search** - Real-time search kategori berdasarkan nama
|
|
||||||
* **Category Notes Search** - Search catatan di dalam kategori (judul & isi)
|
|
||||||
* **Search Filtering** - Live filtering saat user mengetik
|
|
||||||
* **Search Empty State** - Descriptive message dengan alternative suggestions
|
|
||||||
|
|
||||||
### **Category Features**
|
|
||||||
* **Edit Category** - Dialog untuk ubah nama dan gradient dengan pre-filled form
|
|
||||||
* **Delete Category** - Menu dropdown dengan confirmation dialog
|
|
||||||
* **Category Actions Menu** - Icon ⋮ untuk access edit & delete options
|
|
||||||
* **Gradient Preview** - Visual preview saat edit kategori
|
|
||||||
|
|
||||||
### **Trash System**
|
|
||||||
* **Soft Delete Implementation** - isDeleted flag untuk Category dan Note
|
|
||||||
* **Trash Screen** - Tampilkan kategori & notes yang terhapus
|
|
||||||
* **TrashCategoryCard Component** - Card khusus dengan restore & delete permanent actions
|
|
||||||
* **Restore Feature** - Pulihkan kategori beserta semua notes di dalamnya
|
|
||||||
* **Permanent Delete** - Hapus kategori dan notes secara irreversible dengan confirmation
|
|
||||||
* **Counter Display** - Jumlah items terhapus di trash
|
|
||||||
* **Global Filter** - Filter `!isDeleted` di semua screen untuk hide deleted items
|
|
||||||
|
|
||||||
### **Bug Fixes & Optimization**
|
|
||||||
* **Runtime Error Debugging** - Fix NotImplementedError & FATAL EXCEPTION issues
|
|
||||||
* **Google Play Services Handling** - Error handling untuk GMS dependencies
|
|
||||||
* **Component Migration** - Update deprecated Divider ke HorizontalDivider
|
|
||||||
* **Gradle Optimization** - Cleanup unnecessary dependencies
|
|
||||||
* **State Management** - Proper state hoisting dan recomposition optimization
|
|
||||||
|
|
||||||
### **Documentation**
|
|
||||||
* **Migration Guide** - Step-by-step panduan untuk project restructuring
|
|
||||||
* **Debugging Guide** - Troubleshooting common issues dan error handling
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# **Version 1.1.0 – AI Helper Screen Enhancement & UI Refinement**
|
|
||||||
|
|
||||||
## **Sprint 3: AI Helper Screen Features & Modern UI Redesign**
|
|
||||||
|
|
||||||
### **AI Assistant Enhancements**
|
|
||||||
* **History Chat AI dengan Drawer Menu** - Riwayat percakapan AI tersimpan permanen, dikelompokkan per kategori
|
|
||||||
* **Chat History Management** - Load previous chat, delete history, start new chat dengan auto-save
|
|
||||||
* **Markdown Parser untuk AI Response** - Support bold, italic, code blocks, headers, lists, quotes, links
|
|
||||||
* **Improved Error Handling** - User-friendly error messages untuk quota, network, API issues
|
|
||||||
* **Gemini Model Update** - Switch ke gemini-1.5-flash untuk stabilitas optimal
|
|
||||||
|
|
||||||
### **Theme System**
|
|
||||||
* **Dark/Light Theme Toggle** - Dual theme dengan persistent storage di drawer menu
|
|
||||||
* **Reactive Color System** - Dynamic color switching untuk semua components
|
|
||||||
* **Complete Color Palette** - DarkColors dan LightColors objects untuk consistency
|
|
||||||
|
|
||||||
### **UI/UX Modernization**
|
|
||||||
* **Floating Design System** - TopBar dan BottomBar dengan floating style, rounded corners, shadow
|
|
||||||
* **Consistent Component Style** - Unified design language dengan CircleShape buttons
|
|
||||||
* **Optimized Layouts** - Better spacing dan vertical action stack untuk maximize content space
|
|
||||||
|
|
||||||
### **Data & Navigation**
|
|
||||||
* **Note Edit & Delete from Card** - Menu dropdown pada NoteCard untuk quick actions
|
|
||||||
* **Race Condition Fix** - Guard flags dan lifecycle-aware auto-save untuk data persistence
|
|
||||||
* **Simplified Navigation** - Unified drawer menu, remove redundant back buttons
|
|
||||||
* **Extended DataStore** - Support chat history, theme preference, improved error handling
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **Sprint 4: Rich Text Editor Core Features & AI Chat History UI/UX Improvements**
|
|
||||||
|
|
||||||
### **Rich Text Editing**
|
|
||||||
* **Hybrid Rich Text Editor (WYSIWYG)** – Edit teks dengan format langsung tanpa syntax markdown terlihat
|
|
||||||
* **Bold, Italic, Underline** – Formatting bersifat toggle dan tetap aktif sampai dimatikan
|
|
||||||
* **Heading & Bullet List** – Support heading (H1–H3) dan bullet list tanpa konflik antar format
|
|
||||||
* **Undo / Redo** – Riwayat perubahan editor terintegrasi
|
|
||||||
|
|
||||||
### **Floating Toolbar**
|
|
||||||
* **Draggable Mini Toolbar** – Toolbar dapat dipindahkan bebas oleh user
|
|
||||||
* **Active State Indicator** – Icon toolbar menandakan format aktif (Bold, Italic, dll)
|
|
||||||
* **Minimal UI** – Toolbar kecil agar tidak mengganggu area pengetikan
|
|
||||||
* **Keyboard-Aware Positioning** – Posisi toolbar menyesuaikan saat keyboard muncul
|
|
||||||
|
|
||||||
### **Cursor & Editing Stability**
|
|
||||||
* **Stable Cursor & Selection** – Insertion point dan selection handle akurat saat mengetik
|
|
||||||
* **IME & Keyboard Safe** – Editor tetap stabil saat keyboard resize / rotate
|
|
||||||
* **Auto Bring-Into-View** – Cursor selalu terlihat saat mengetik di area bawah layar
|
|
||||||
|
|
||||||
### **Data Persistence**
|
|
||||||
* **Format Tersimpan Permanen** – Rich text tidak hilang setelah save atau reopen
|
|
||||||
* **Auto Save Lifecycle-Aware** – Catatan otomatis tersimpan saat app background / keluar
|
|
||||||
* **Markdown Compatibility** – Support import & export markdown secara aman
|
|
||||||
|
|
||||||
### **Chat History Enhancements**
|
|
||||||
* **Compact Modern Design** - Item lebih kecil dengan horizontal layout dan 30 karakter limit
|
|
||||||
* **Search & Filter System** - Real-time search dengan category dropdown filtering
|
|
||||||
* **Date Grouping** - Auto-group: "Hari Ini", "Kemarin", "Minggu Ini", "Lebih Lama"
|
|
||||||
* **Edit Title with Markdown** - Custom title support: **bold**, *italic*, `code`, ~~strike~~
|
|
||||||
* **Context Menu** - Three-dot menu (⋮) untuk Edit dan Delete actions
|
|
||||||
* **Live Preview** - Real-time markdown preview saat edit title
|
|
||||||
|
|
||||||
### **Technical Updates**
|
|
||||||
* **ChatHistory Model** - Added `customTitle: String?` field
|
|
||||||
* **DataStore Integration** - New `updateChatHistoryTitle()` function
|
|
||||||
* **Smart Truncation** - Auto-truncate preview ke 30 char dengan `toSafeChatPreview()`
|
|
||||||
* **Markdown Parser** - Inline markdown rendering untuk titles dengan proper styling
|
|
||||||
* **Character Counter** - Visual feedback dengan color indicator (Gray → Primary → Red)
|
|
||||||
|
|
||||||
### **User Experience**
|
|
||||||
* **Better Empty States** - Informative UI untuk empty search dan no history
|
|
||||||
* **Smooth Animations** - Slide transitions untuk dialogs
|
|
||||||
* **Input Validation** - Max 30 char dengan real-time blocking
|
|
||||||
* **Focus Management** - Seamless editing experience dengan auto-focus
|
|
||||||
|
|
||||||
> Rich Text Editor butuh dikembangkan lagi lebih advance
|
|
||||||
---
|
|
||||||
|
|
||||||
## **Sprint 5: AI Assistant Enhancements & Smart Organization Features**
|
|
||||||
|
|
||||||
### **Copy Plain Text Feature**
|
|
||||||
* **Dual Copy Options** – Dropdown menu dengan 2 pilihan: "Copy dengan Format" dan "Copy Teks Asli"
|
|
||||||
* **Smart Markdown Stripper** – Utility untuk remove bold, italic, code, headers, lists, links dari text
|
|
||||||
* **Visual Feedback** – Animated checkmark indicator dengan auto-hide setelah 2 detik
|
|
||||||
* **Format Preservation** – Copy dengan format maintain semua markdown syntax
|
|
||||||
* **Clean Output** – Plain text copy menghasilkan text bersih tanpa formatting apapun
|
|
||||||
|
|
||||||
### **Document Upload & AI Summary**
|
|
||||||
* **Multi-Format Support** – Upload PDF, TXT, dan DOCX files dengan file picker
|
|
||||||
* **Smart PDF Parser** – PDFBox Android integration untuk extract text dari PDF documents
|
|
||||||
* **Lightweight DOCX Parser** – Custom XML-based parser tanpa Apache POI dependency
|
|
||||||
* **Auto-Summary Generation** – AI auto-generate ringkasan maksimal 300 kata saat file di-upload
|
|
||||||
* **File Validation** – Maximum 10MB dengan clear error messaging untuk setiap kasus
|
|
||||||
* **Loading Integration** – Loading indicator "Membuat ringkasan..." terintegrasi di chat area
|
|
||||||
* **Chat Format** – Upload result format: "📄 Upload file: filename" dengan summary response
|
|
||||||
|
|
||||||
### **Category Pin System**
|
|
||||||
* **Pin/Unpin Toggle** – Quick access untuk kategori favorit dengan dropdown menu
|
|
||||||
* **Visual Pin Indicator** – 📌 icon dengan scale dan fade animations
|
|
||||||
* **Smart Sorting Logic** – Priority sorting: pinned categories (DESC) → timestamp (DESC)
|
|
||||||
* **Persistent Storage** – Pin status tersimpan di DataStore dengan backward compatibility
|
|
||||||
* **Multiple Pins Support** – User dapat pin multiple categories dengan proper grouping
|
|
||||||
* **Context Menu Integration** – Pin option di dropdown: "Pin Kategori" / "Lepas Pin"
|
|
||||||
|
|
||||||
### **Technical Implementation**
|
|
||||||
* **MarkdownStripper.kt** – Utility class dengan regex-based markdown removal
|
|
||||||
* **FileParser.kt** – Centralized file parsing untuk PDF, TXT, DOCX
|
|
||||||
* **Category Model Update** – Added `isPinned: Boolean` field dengan serialization support
|
|
||||||
* **FileParseResult** – Sealed class untuk type-safe file parsing results
|
|
||||||
* **PDFBoxResourceLoader** – Proper initialization dalam Application.onCreate()
|
|
||||||
* **State Management** – Combined loading states untuk chat dan file upload
|
|
||||||
|
|
||||||
### **User Experience**
|
|
||||||
* **Smooth Transitions** – Loading states dengan color differentiation (Primary vs Secondary)
|
|
||||||
* **Error Handling** – Comprehensive error messages untuk berbagai failure scenarios
|
|
||||||
* **Auto-Scroll** – Scroll to bottom saat upload file untuk show loading indicator
|
|
||||||
* **Disabled States** – Upload button hidden saat processing untuk prevent duplicate actions
|
|
||||||
* **Persistence** – Pin status dan file summary survive app restart
|
|
||||||
|
|
||||||
# **Sprint 6: Functional Testing & Documentation**
|
|
||||||
|
|
||||||
## **Testing Implementation**
|
|
||||||
|
|
||||||
### **Test Methodology Design**
|
|
||||||
* **Black-Box Functional Testing** – Pengujian dari perspektif end-user dengan verifikasi Expected vs Actual Result
|
|
||||||
* **Automated Unit Testing** – 59 automated tests untuk validasi business logic internal
|
|
||||||
* **Test Case Design** – 6 comprehensive test cases (TC-01 hingga TC-06)
|
|
||||||
* **Evidence Collection** – Screenshot documentation untuk setiap test case
|
|
||||||
* **Test Report Generation** – Structured test summary dengan metrics dan status
|
|
||||||
|
|
||||||
### **Test Infrastructure Setup**
|
|
||||||
* **JUnit 4 Framework** – Core testing framework untuk Android unit tests
|
|
||||||
* **AndroidX Test Library** – Android-specific testing utilities dan test runners
|
|
||||||
* **Kotlin Coroutines Test** – Testing library untuk asynchronous code dengan runBlocking
|
|
||||||
* **Test Isolation** – Unique DataStore instances per test untuk prevent data contamination
|
|
||||||
* **Test Execution** – Configure test runner dan gradle tasks untuk automated testing
|
|
||||||
|
|
||||||
### **Unit Test Development**
|
|
||||||
* **DataStoreManagerTest** – 8 tests untuk CRUD operations, autosave, dan pin functionality
|
|
||||||
* **TrashFunctionalityTest** – 11 tests untuk soft delete, restore, dan permanent delete
|
|
||||||
* **SearchFunctionalityTest** – 14 tests untuk realtime search dengan berbagai scenarios
|
|
||||||
* **AIChatFunctionalityTest** – 14 tests untuk context building dan chat history management
|
|
||||||
* **FileUploadFunctionalityTest** – 12 tests untuk file parsing dan summary generation
|
|
||||||
|
|
||||||
### **Test Coverage Achievement**
|
|
||||||
* **Total Test Cases** – 6 functional test cases dengan screenshot evidence
|
|
||||||
* **Total Unit Tests** – 59 automated tests covering critical business logic
|
|
||||||
* **Success Rate** – 100% pass rate untuk semua tests
|
|
||||||
* **Execution Time** – Average ~2 minutes untuk full test suite
|
|
||||||
* **Code Coverage** – 100% coverage untuk tested components (DataStore, Models, Utilities)
|
|
||||||
|
|
||||||
### **Bug Fixes & Test Iterations**
|
|
||||||
* **Test Isolation Issues** – Fixed data contamination dengan unique DataStore per test
|
|
||||||
* **Async Testing** – Resolved suspend function testing dengan proper runBlocking usage
|
|
||||||
* **Chat History Tests** – Fixed unique ID collision dengan improved test data management
|
|
||||||
* **Error Handling** – Added comprehensive error handling untuk file I/O operations
|
|
||||||
* **Test Stability** – Achieved consistent test results dengan proper setup/teardown
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **Documentation Development**
|
|
||||||
|
|
||||||
### **Technical Documentation**
|
|
||||||
* **Testing Methodology** – 16-section comprehensive document explaining black-box testing approach
|
|
||||||
* **Architecture Documentation** – Package structure, data flow, dan component relationships
|
|
||||||
* **API Documentation** – Gemini API integration, endpoints, dan configuration details
|
|
||||||
* **Code Comments** – Inline documentation untuk complex logic dan business rules
|
|
||||||
* **Setup Guide** – Step-by-step installation dan configuration instructions
|
|
||||||
|
|
||||||
### **User Documentation**
|
|
||||||
* **User Guide** – Complete panduan penggunaan dengan 7 user flows dan screenshots
|
|
||||||
* **Feature Documentation** – Detailed explanation untuk setiap fitur utama aplikasi
|
|
||||||
* **Quick Start Guide** – 6-step quick reference untuk new users
|
|
||||||
* **Troubleshooting Guide** – Common issues dan solutions untuk end-users
|
|
||||||
* **FAQ Section** – Frequently asked questions dengan clear answers
|
|
||||||
|
|
||||||
### **Project Documentation**
|
|
||||||
* **README.md** – Comprehensive project overview dengan badges, links, dan quick navigation
|
|
||||||
* **CHANGELOG.md** – Detailed version history dengan sprint breakdown dan feature tracking
|
|
||||||
* **TEST_SUMMARY_REPORT.md** – Complete test report dengan metrics, results, dan evidence
|
|
||||||
* **DEVELOPMENT_PLAN.md** – Sprint history, roadmap, dan future development planning
|
|
||||||
* **Academic Report** – 35-page formal documentation untuk course submission
|
|
||||||
|
|
||||||
### **Visual Documentation**
|
|
||||||
* **Wireframe Design** – Complete app wireframe dengan all screens dan navigation flows
|
|
||||||
* **Screenshot Collection** – 35+ screenshots documenting every feature dan user flow
|
|
||||||
* **Mockup Integration** – High-fidelity mockups embedded dalam user guide
|
|
||||||
* **Architecture Diagrams** – Visual representation of data layer, presentation layer, dan flow
|
|
||||||
* **Test Evidence** – Screenshot proof untuk setiap test case execution
|
|
||||||
|
|
||||||
### **Reference Documentation**
|
|
||||||
* **Dependencies List** – Complete list of libraries dengan version numbers
|
|
||||||
* **Tech Stack Documentation** – Detailed explanation of technology choices
|
|
||||||
* **API References** – Links to official documentation untuk Gemini, Android, Kotlin
|
|
||||||
* **Academic Citations** – Proper citation format untuk research sources (33 references)
|
|
||||||
* **Version Control** – Git workflow documentation dan branching strategy
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Fitur Utama (Core Features)
|
|
||||||
1. **Note Management System** ⭐ (PRIMARY)
|
|
||||||
|
|
||||||
* Create, Read, Update, Delete catatan
|
|
||||||
* Organize notes dalam categories
|
|
||||||
* Pin notes untuk quick access
|
|
||||||
* Archive & Trash system dengan soft delete
|
|
||||||
* Full-screen rich text editor dengan WYSIWYG
|
|
||||||
* Real-time search & filter notes
|
|
||||||
|
|
||||||
2. **AI Assistant** 🤖 (PRIMARY)
|
|
||||||
|
|
||||||
* Chat dengan AI menggunakan Gemini 2.5 Flash
|
|
||||||
* Context-aware responses berdasarkan notes user
|
|
||||||
* Chat history management dengan persistent storage
|
|
||||||
* Document upload & auto-summary (PDF, TXT, DOCX)
|
|
||||||
* Markdown support untuk AI responses
|
|
||||||
* Copy plain text atau formatted text
|
|
||||||
|
|
||||||
3. **Category Organization** 📁 (CORE)
|
|
||||||
|
|
||||||
* Create & manage categories dengan 8 gradient color presets
|
|
||||||
* Pin favorite categories untuk quick access
|
|
||||||
* Smart sorting: pinned categories → timestamp descending
|
|
||||||
* Category-based note filtering dengan statistics
|
|
||||||
* Staggered grid layout responsive
|
|
||||||
|
|
||||||
4. **Rich Text Editor** ✏️ (CORE)
|
|
||||||
|
|
||||||
* WYSIWYG (What You See Is What You Get) editing experience tanpa raw markdown
|
|
||||||
* Bold, italic, underline, headings (H1-H3), bullet lists
|
|
||||||
* Floating draggable toolbar dengan active state indicators
|
|
||||||
* Undo/Redo functionality
|
|
||||||
* Markdown compatibility untuk import/export
|
|
||||||
* Auto-save lifecycle-aware
|
|
||||||
|
|
||||||
5. **Data Persistence** 💾 (ESSENTIAL)
|
|
||||||
|
|
||||||
* Local storage dengan DataStore Preferences
|
|
||||||
* Auto-save dengan debounce (500ms delay)
|
|
||||||
* Theme preference storage (dark/light mode)
|
|
||||||
* Chat history persistence dengan serialization
|
|
||||||
* Flow-based reactive data loading
|
|
||||||
* Error handling untuk semua I/O operations
|
|
||||||
823
README.md
823
README.md
@ -1,599 +1,306 @@
|
|||||||
# 📝 NotesAI - AI-Powered Note Taking App 1.1.0
|
# **AI Notes – Changelog**
|
||||||
|
|
||||||
|
## **Tim Pengembang**
|
||||||
|
|
||||||
|
* Dendi Yogia Pratama
|
||||||
|
* Raihan Ariq Muzakki
|
||||||
|
* Fazri Abdurrahman
|
||||||
|
|
||||||

|
# **Version 1.0.0 – Initial Release**
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
**Aplikasi pencatatan cerdas berbasis AI untuk Android dengan fitur organisasi terstruktur dan AI Assistant**
|
## **Sprint 1: Struktur Dasar Aplikasi**
|
||||||
|
|
||||||
[📖 Dokumentasi Lengkap](./docs/Laporan%20Dokumentasi%20Aplikasi%20-%20Kelompok%201.pdf) | [🧪 Test Report](./TEST_SUMMARY_REPORT.md) | [📋 Changelog](./CHANGELOG.md)
|
### **Struktur & Navigation**
|
||||||
|
* **Setup navigation system** - Implementasi routing antar halaman (Beranda, Arsip, Sampah)
|
||||||
|
* **Menu Drawer** - Navigation drawer dengan list menu (Beranda, Berbintang, Arsip, Sampah)
|
||||||
|
* **Bottom Navigation** - Home & AI Helper tabs dengan icon navigation
|
||||||
|
* **Top App Bar** - Menu hamburger dan search icon dengan Material3 styling
|
||||||
|
* **Screen Architecture** - Pembuatan screen Arsip, Sampah, Berbintang, AI Helper
|
||||||
|
|
||||||
|
### **Theme & Styling**
|
||||||
|
* **Material3 Dark Theme** - Setup color scheme dengan dark mode default
|
||||||
|
* **Color System** - Primary/Secondary colors dengan gradient presets (8 kombinasi warna)
|
||||||
|
* **Consistent Design** - Rounded corners (12dp, 16dp, 20dp), shadow, elevation
|
||||||
|
* **Smooth Animations** - Drawer slide, FAB scale, card transitions dengan spring animations
|
||||||
|
* **Typography System** - Optimasi font sizes dan line heights untuk readability
|
||||||
|
|
||||||
|
### **Category Management**
|
||||||
|
* **Category Model** - Data class dengan gradient colors dan timestamp
|
||||||
|
* **Category Dialog** - Form tambah/edit kategori dengan nama + gradient picker
|
||||||
|
* **Category Card** - Design dengan icon folder, nama, jumlah catatan, gradient background
|
||||||
|
* **Staggered Grid Layout** - 2 kolom responsive dengan LazyVerticalStaggeredGrid
|
||||||
|
* **Category Actions** - Menu dropdown (⋮) untuk edit dan delete kategori
|
||||||
|
* **Empty State** - Pesan "Buat kategori pertama Anda" dengan icon
|
||||||
|
|
||||||
|
### **Note Management**
|
||||||
|
* **Note Model** - Data class dengan title, content, timestamp, isPinned, isArchived
|
||||||
|
* **Note Dialog** - Form dengan judul, deskripsi, simpan, batal, hapus
|
||||||
|
* **Note Card** - Preview dengan judul, deskripsi, timestamp, pin icon
|
||||||
|
* **Full-screen Editor** - Editable note view dengan auto-save dan actions
|
||||||
|
* **Pin Feature** - Toggle pin/unpin untuk catatan penting dengan sorting priority
|
||||||
|
* **Archive & Delete** - Actions untuk arsip dan soft delete notes
|
||||||
|
* **Search Functionality** - Real-time search berdasarkan judul dan isi (case-insensitive)
|
||||||
|
* **Smart Sorting** - Berdasarkan pin status dan timestamp (descending)
|
||||||
|
|
||||||
|
### **AI Assistant**
|
||||||
|
* **Gemini AI Integration** - Setup Google Generative AI SDK dengan gemini-2.5-flash
|
||||||
|
* **AI Helper Screen** - Layout chat interface dengan header dan statistics
|
||||||
|
* **Category Context Selector** - Dropdown untuk filter konteks AI berdasarkan kategori
|
||||||
|
* **Statistics Display** - Total catatan, pinned notes, jumlah kategori
|
||||||
|
* **Chat Interface** - User & AI bubble dengan different styling dan timestamp
|
||||||
|
* **Prompt Engineering** - Context builder dengan data catatan user (max 10 terbaru)
|
||||||
|
* **Suggestion Chips** - Quick question templates untuk user guidance
|
||||||
|
* **Copy to Clipboard** - Copy jawaban AI dengan confirmation feedback
|
||||||
|
* **Loading & Error States** - Circular progress indicator dan error messages
|
||||||
|
* **API Configuration** - Temperature 0.8, topK 40, topP 0.95, maxOutputTokens 4096
|
||||||
|
* **Auto-scroll Chat** - Scroll ke bottom otomatis dengan LaunchedEffect
|
||||||
|
|
||||||
|
### **Data Persistence**
|
||||||
|
* **DataStore Implementation** - Preferences DataStore untuk local storage
|
||||||
|
* **DataStoreManager Class** - Centralized dengan categoriesFlow & notesFlow
|
||||||
|
* **Auto-save dengan Debounce** - 500ms delay untuk optimize I/O operations
|
||||||
|
* **Flow-based Loading** - Reactive data loading dengan Flow collection
|
||||||
|
* **Error Handling** - Try-catch untuk semua I/O operations
|
||||||
|
* **Serializable Models** - JSON serialization dengan extension functions
|
||||||
|
|
||||||
|
### **UI/UX Enhancements**
|
||||||
|
* **Visual Feedback** - Click ripples, copy confirmation, loading states
|
||||||
|
* **Empty States** - Icon + descriptive messages untuk setiap screen
|
||||||
|
* **Confirmation Dialogs** - AlertDialog untuk arsip, hapus, delete actions
|
||||||
|
* **Search Empty State** - "Tidak ada hasil" message saat search kosong
|
||||||
|
* **Custom TextField** - Styled text input dengan consistent design
|
||||||
|
* **Date Formatter Utility** - Format timestamp ke readable Indonesian format
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 👥 Tim Pengembang
|
## **Sprint 2: Project Restructuring & Advanced Features**
|
||||||
|
|
||||||
**Kelompok 1 - Kelas F5A5**
|
### **Project Architecture**
|
||||||
|
* **Clean Architecture Migration** - Dari 3 file monolith ke modular structure
|
||||||
|
* **Data Layer Separation** - Models ke `data/model/` (Category, Note, ChatMessage)
|
||||||
|
* **Local Storage Layer** - DataStoreManager ke `data/local/` dengan PreferencesKeys
|
||||||
|
* **Component Extraction** - Screen components ke folder terpisah (main, starred, archive, trash)
|
||||||
|
* **Utilities Creation** - Constants.kt, DateFormatter.kt, Extensions.kt untuk reusability
|
||||||
|
* **Import Optimization** - Update semua import sesuai package structure baru
|
||||||
|
|
||||||
| Nama | NPM |
|
### **Search & Filter**
|
||||||
|------|-----|
|
* **Beranda Search** - Real-time search kategori berdasarkan nama
|
||||||
| Dendi Yogia Pratama | 202310715051 |
|
* **Category Notes Search** - Search catatan di dalam kategori (judul & isi)
|
||||||
| Raihan Ariq Muzakki | 202310715297 |
|
* **Search Filtering** - Live filtering saat user mengetik
|
||||||
| Fazri Abdurahman | 202310715082 |
|
* **Search Empty State** - Descriptive message dengan alternative suggestions
|
||||||
|
|
||||||
**Dosen Pengampu:** Arif Rifai Dwiyanto, ST., MTI
|
### **Category Features**
|
||||||
**Mata Kuliah:** Pemrograman Perangkat Bergerak
|
* **Edit Category** - Dialog untuk ubah nama dan gradient dengan pre-filled form
|
||||||
**Institusi:** Universitas Bhayangkara Jakarta Raya
|
* **Delete Category** - Menu dropdown dengan confirmation dialog
|
||||||
|
* **Category Actions Menu** - Icon ⋮ untuk access edit & delete options
|
||||||
|
* **Gradient Preview** - Visual preview saat edit kategori
|
||||||
|
|
||||||
|
### **Trash System**
|
||||||
|
* **Soft Delete Implementation** - isDeleted flag untuk Category dan Note
|
||||||
|
* **Trash Screen** - Tampilkan kategori & notes yang terhapus
|
||||||
|
* **TrashCategoryCard Component** - Card khusus dengan restore & delete permanent actions
|
||||||
|
* **Restore Feature** - Pulihkan kategori beserta semua notes di dalamnya
|
||||||
|
* **Permanent Delete** - Hapus kategori dan notes secara irreversible dengan confirmation
|
||||||
|
* **Counter Display** - Jumlah items terhapus di trash
|
||||||
|
* **Global Filter** - Filter `!isDeleted` di semua screen untuk hide deleted items
|
||||||
|
|
||||||
|
### **Bug Fixes & Optimization**
|
||||||
|
* **Runtime Error Debugging** - Fix NotImplementedError & FATAL EXCEPTION issues
|
||||||
|
* **Google Play Services Handling** - Error handling untuk GMS dependencies
|
||||||
|
* **Component Migration** - Update deprecated Divider ke HorizontalDivider
|
||||||
|
* **Gradle Optimization** - Cleanup unnecessary dependencies
|
||||||
|
* **State Management** - Proper state hoisting dan recomposition optimization
|
||||||
|
|
||||||
|
### **Documentation**
|
||||||
|
* **Migration Guide** - Step-by-step panduan untuk project restructuring
|
||||||
|
* **Debugging Guide** - Troubleshooting common issues dan error handling
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📌 Informasi Proyek
|
# **Version 1.1.0 – AI Helper Screen Enhancement & UI Refinement**
|
||||||
|
|
||||||
- **Nama Aplikasi:** NotesAI
|
## **Sprint 3: AI Helper Screen Features & Modern UI Redesign**
|
||||||
- **Repository:** [NotesAI](https://git.lab.ubharajaya.ac.id/202310715297-RAIHAN-ARIQ-MUZAKKI/NotesAI.git)
|
|
||||||
- **Platform:** Android (Minimum API 24 / Android 7.0)
|
### **AI Assistant Enhancements**
|
||||||
- **Bahasa:** Kotlin 100%
|
* **History Chat AI dengan Drawer Menu** - Riwayat percakapan AI tersimpan permanen, dikelompokkan per kategori
|
||||||
- **UI Framework:** Jetpack Compose + Material 3
|
* **Chat History Management** - Load previous chat, delete history, start new chat dengan auto-save
|
||||||
|
* **Markdown Parser untuk AI Response** - Support bold, italic, code blocks, headers, lists, quotes, links
|
||||||
|
* **Improved Error Handling** - User-friendly error messages untuk quota, network, API issues
|
||||||
|
* **Gemini Model Update** - Switch ke gemini-1.5-flash untuk stabilitas optimal
|
||||||
|
|
||||||
|
### **Theme System**
|
||||||
|
* **Dark/Light Theme Toggle** - Dual theme dengan persistent storage di drawer menu
|
||||||
|
* **Reactive Color System** - Dynamic color switching untuk semua components
|
||||||
|
* **Complete Color Palette** - DarkColors dan LightColors objects untuk consistency
|
||||||
|
|
||||||
|
### **UI/UX Modernization**
|
||||||
|
* **Floating Design System** - TopBar dan BottomBar dengan floating style, rounded corners, shadow
|
||||||
|
* **Consistent Component Style** - Unified design language dengan CircleShape buttons
|
||||||
|
* **Optimized Layouts** - Better spacing dan vertical action stack untuk maximize content space
|
||||||
|
|
||||||
|
### **Data & Navigation**
|
||||||
|
* **Note Edit & Delete from Card** - Menu dropdown pada NoteCard untuk quick actions
|
||||||
|
* **Race Condition Fix** - Guard flags dan lifecycle-aware auto-save untuk data persistence
|
||||||
|
* **Simplified Navigation** - Unified drawer menu, remove redundant back buttons
|
||||||
|
* **Extended DataStore** - Support chat history, theme preference, improved error handling
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 Tujuan dan Sasaran Aplikasi
|
## **Sprint 4: Rich Text Editor Core Features & AI Chat History UI/UX Improvements**
|
||||||
|
|
||||||
### Masalah yang Dipecahkan
|
### **Rich Text Editing**
|
||||||
1. **Catatan tidak terorganisir** - Catatan bercampur tanpa struktur yang jelas
|
* **Hybrid Rich Text Editor (WYSIWYG)** – Edit teks dengan format langsung tanpa syntax markdown terlihat
|
||||||
2. **Sulit mencari informasi** - Kehilangan waktu mencari catatan penting
|
* **Bold, Italic, Underline** – Formatting bersifat toggle dan tetap aktif sampai dimatikan
|
||||||
3. **Kurang interaktif** - Tidak ada bantuan untuk merangkum atau menganalisis catatan
|
* **Heading & Bullet List** – Support heading (H1–H3) dan bullet list tanpa konflik antar format
|
||||||
4. **Risiko kehilangan data** - Catatan terhapus permanen tanpa backup
|
* **Undo / Redo** – Riwayat perubahan editor terintegrasi
|
||||||
|
|
||||||
### Target Pengguna
|
### **Floating Toolbar**
|
||||||
- 🎓 **Mahasiswa** (18-25 tahun) - Catatan kuliah, tugas, ringkasan dokumen
|
* **Draggable Mini Toolbar** – Toolbar dapat dipindahkan bebas oleh user
|
||||||
- 💼 **Profesional** (22-40 tahun) - Meeting notes, to-do lists, catatan kerja
|
* **Active State Indicator** – Icon toolbar menandakan format aktif (Bold, Italic, dll)
|
||||||
- 👤 **Pengguna Umum** (18-40 tahun) - Catatan pribadi, jurnal, daftar belanja
|
* **Minimal UI** – Toolbar kecil agar tidak mengganggu area pengetikan
|
||||||
|
* **Keyboard-Aware Positioning** – Posisi toolbar menyesuaikan saat keyboard muncul
|
||||||
|
|
||||||
### Keunggulan NotesAI
|
### **Cursor & Editing Stability**
|
||||||
✅ **Organisasi Terstruktur** - Sistem kategori dengan visual gradien warna
|
* **Stable Cursor & Selection** – Insertion point dan selection handle akurat saat mengetik
|
||||||
✅ **AI Assistant** - Powered by Gemini 2.5 Flash untuk respons kontekstual
|
* **IME & Keyboard Safe** – Editor tetap stabil saat keyboard resize / rotate
|
||||||
✅ **Rich Text Editor** - WYSIWYG editor dengan drag-and-drop toolbar
|
* **Auto Bring-Into-View** – Cursor selalu terlihat saat mengetik di area bawah layar
|
||||||
✅ **Smart Search** - Pencarian realtime dengan filter kategori
|
|
||||||
✅ **Data Safety** - Soft delete dengan trash & restore functionality
|
### **Data Persistence**
|
||||||
✅ **Document Parser** - Upload PDF/TXT/DOCX dengan auto-summary
|
* **Format Tersimpan Permanen** – Rich text tidak hilang setelah save atau reopen
|
||||||
|
* **Auto Save Lifecycle-Aware** – Catatan otomatis tersimpan saat app background / keluar
|
||||||
|
* **Markdown Compatibility** – Support import & export markdown secara aman
|
||||||
|
|
||||||
|
### **Chat History Enhancements**
|
||||||
|
* **Compact Modern Design** - Item lebih kecil dengan horizontal layout dan 30 karakter limit
|
||||||
|
* **Search & Filter System** - Real-time search dengan category dropdown filtering
|
||||||
|
* **Date Grouping** - Auto-group: "Hari Ini", "Kemarin", "Minggu Ini", "Lebih Lama"
|
||||||
|
* **Edit Title with Markdown** - Custom title support: **bold**, *italic*, `code`, ~~strike~~
|
||||||
|
* **Context Menu** - Three-dot menu (⋮) untuk Edit dan Delete actions
|
||||||
|
* **Live Preview** - Real-time markdown preview saat edit title
|
||||||
|
|
||||||
|
### **Technical Updates**
|
||||||
|
* **ChatHistory Model** - Added `customTitle: String?` field
|
||||||
|
* **DataStore Integration** - New `updateChatHistoryTitle()` function
|
||||||
|
* **Smart Truncation** - Auto-truncate preview ke 30 char dengan `toSafeChatPreview()`
|
||||||
|
* **Markdown Parser** - Inline markdown rendering untuk titles dengan proper styling
|
||||||
|
* **Character Counter** - Visual feedback dengan color indicator (Gray → Primary → Red)
|
||||||
|
|
||||||
|
### **User Experience**
|
||||||
|
* **Better Empty States** - Informative UI untuk empty search dan no history
|
||||||
|
* **Smooth Animations** - Slide transitions untuk dialogs
|
||||||
|
* **Input Validation** - Max 30 char dengan real-time blocking
|
||||||
|
* **Focus Management** - Seamless editing experience dengan auto-focus
|
||||||
|
|
||||||
|
> Rich Text Editor butuh dikembangkan lagi lebih advance
|
||||||
|
---
|
||||||
|
|
||||||
|
## **Sprint 5: AI Assistant Enhancements & Smart Organization Features**
|
||||||
|
|
||||||
|
### **Copy Plain Text Feature**
|
||||||
|
* **Dual Copy Options** – Dropdown menu dengan 2 pilihan: "Copy dengan Format" dan "Copy Teks Asli"
|
||||||
|
* **Smart Markdown Stripper** – Utility untuk remove bold, italic, code, headers, lists, links dari text
|
||||||
|
* **Visual Feedback** – Animated checkmark indicator dengan auto-hide setelah 2 detik
|
||||||
|
* **Format Preservation** – Copy dengan format maintain semua markdown syntax
|
||||||
|
* **Clean Output** – Plain text copy menghasilkan text bersih tanpa formatting apapun
|
||||||
|
|
||||||
|
### **Document Upload & AI Summary**
|
||||||
|
* **Multi-Format Support** – Upload PDF, TXT, dan DOCX files dengan file picker
|
||||||
|
* **Smart PDF Parser** – PDFBox Android integration untuk extract text dari PDF documents
|
||||||
|
* **Lightweight DOCX Parser** – Custom XML-based parser tanpa Apache POI dependency
|
||||||
|
* **Auto-Summary Generation** – AI auto-generate ringkasan maksimal 300 kata saat file di-upload
|
||||||
|
* **File Validation** – Maximum 10MB dengan clear error messaging untuk setiap kasus
|
||||||
|
* **Loading Integration** – Loading indicator "Membuat ringkasan..." terintegrasi di chat area
|
||||||
|
* **Chat Format** – Upload result format: "📄 Upload file: filename" dengan summary response
|
||||||
|
|
||||||
|
### **Category Pin System**
|
||||||
|
* **Pin/Unpin Toggle** – Quick access untuk kategori favorit dengan dropdown menu
|
||||||
|
* **Visual Pin Indicator** – 📌 icon dengan scale dan fade animations
|
||||||
|
* **Smart Sorting Logic** – Priority sorting: pinned categories (DESC) → timestamp (DESC)
|
||||||
|
* **Persistent Storage** – Pin status tersimpan di DataStore dengan backward compatibility
|
||||||
|
* **Multiple Pins Support** – User dapat pin multiple categories dengan proper grouping
|
||||||
|
* **Context Menu Integration** – Pin option di dropdown: "Pin Kategori" / "Lepas Pin"
|
||||||
|
|
||||||
|
### **Technical Implementation**
|
||||||
|
* **MarkdownStripper.kt** – Utility class dengan regex-based markdown removal
|
||||||
|
* **FileParser.kt** – Centralized file parsing untuk PDF, TXT, DOCX
|
||||||
|
* **Category Model Update** – Added `isPinned: Boolean` field dengan serialization support
|
||||||
|
* **FileParseResult** – Sealed class untuk type-safe file parsing results
|
||||||
|
* **PDFBoxResourceLoader** – Proper initialization dalam Application.onCreate()
|
||||||
|
* **State Management** – Combined loading states untuk chat dan file upload
|
||||||
|
|
||||||
|
### **User Experience**
|
||||||
|
* **Smooth Transitions** – Loading states dengan color differentiation (Primary vs Secondary)
|
||||||
|
* **Error Handling** – Comprehensive error messages untuk berbagai failure scenarios
|
||||||
|
* **Auto-Scroll** – Scroll to bottom saat upload file untuk show loading indicator
|
||||||
|
* **Disabled States** – Upload button hidden saat processing untuk prevent duplicate actions
|
||||||
|
* **Persistence** – Pin status dan file summary survive app restart
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✨ Fitur Utama
|
## 🎯 Fitur Utama (Core Features)
|
||||||
|
1. **Note Management System** ⭐ (PRIMARY)
|
||||||
|
|
||||||
### 1️⃣ Note Management System
|
* Create, Read, Update, Delete catatan
|
||||||
- ✏️ **CRUD Operations** - Create, Read, Update, Delete catatan
|
* Organize notes dalam categories
|
||||||
- 📁 **Category Organization** - Pengelompokan visual dengan gradien warna
|
* Pin notes untuk quick access
|
||||||
- 📌 **Pin Priority** - Pin notes/kategori untuk akses cepat
|
* Archive & Trash system dengan soft delete
|
||||||
- 🗄️ **Archive & Trash** - Soft delete dengan kemampuan restore
|
* Full-screen rich text editor dengan WYSIWYG
|
||||||
- 🎨 **Rich Text Editor** - Bold, italic, underline, heading, bullet list
|
* Real-time search & filter notes
|
||||||
- 🔍 **Smart Search** - Realtime search dengan case-insensitive
|
|
||||||
|
|
||||||
### 2️⃣ AI Assistant
|
2. **AI Assistant** 🤖 (PRIMARY)
|
||||||
- 🤖 **Contextual AI Chat** - AI memahami konteks dari catatan Anda
|
|
||||||
- 📄 **Document Upload** - Support PDF, TXT, DOCX
|
|
||||||
- 📝 **Auto Summary** - Ringkasan otomatis dari dokumen
|
|
||||||
- 💬 **Chat History** - Penyimpanan percakapan persistent
|
|
||||||
- 🎯 **Category Filter** - Filter konteks berdasarkan kategori
|
|
||||||
- ✍️ **Markdown Support** - Formatted AI responses
|
|
||||||
|
|
||||||
### 3️⃣ Data Management
|
* Chat dengan AI menggunakan Gemini 2.5 Flash
|
||||||
- 💾 **Local Storage** - DataStore Preferences untuk data persistence
|
* Context-aware responses berdasarkan notes user
|
||||||
- 🔄 **Autosave** - Lifecycle-aware autosave dengan debounce 500ms
|
* Chat history management dengan persistent storage
|
||||||
- 🌙 **Theme Preference** - Dark/Light mode support
|
* Document upload & auto-summary (PDF, TXT, DOCX)
|
||||||
- 📊 **Reactive Data** - Flow-based reactive data loading
|
* Markdown support untuk AI responses
|
||||||
- ⚡ **Fast Performance** - Optimized untuk pengalaman smooth
|
* Copy plain text atau formatted text
|
||||||
|
|
||||||
|
3. **Category Organization** 📁 (CORE)
|
||||||
|
|
||||||
|
* Create & manage categories dengan 8 gradient color presets
|
||||||
|
* Pin favorite categories untuk quick access
|
||||||
|
* Smart sorting: pinned categories → timestamp descending
|
||||||
|
* Category-based note filtering dengan statistics
|
||||||
|
* Staggered grid layout responsive
|
||||||
|
|
||||||
|
4. **Rich Text Editor** ✏️ (CORE)
|
||||||
|
|
||||||
|
* WYSIWYG (What You See Is What You Get) editing experience tanpa raw markdown
|
||||||
|
* Bold, italic, underline, headings (H1-H3), bullet lists
|
||||||
|
* Floating draggable toolbar dengan active state indicators
|
||||||
|
* Undo/Redo functionality
|
||||||
|
* Markdown compatibility untuk import/export
|
||||||
|
* Auto-save lifecycle-aware
|
||||||
|
|
||||||
|
5. **Data Persistence** 💾 (ESSENTIAL)
|
||||||
|
|
||||||
|
* Local storage dengan DataStore Preferences
|
||||||
|
* Auto-save dengan debounce (500ms delay)
|
||||||
|
* Theme preference storage (dark/light mode)
|
||||||
|
* Chat history persistence dengan serialization
|
||||||
|
* Flow-based reactive data loading
|
||||||
|
* Error handling untuk semua I/O operations
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📊 Riset dan Analisis
|
## **Features for Sprint 3 v1.1.0**
|
||||||
|
|
||||||
### Analisis Pasar
|
* History Chat AI berdasarkan Catatan yang ada didalam kategori dalam bentuk Drawer Menu di AI Helper (ok)
|
||||||
Berdasarkan riset pasar 2025:
|
* Mengganti Preview Deskripsi NoteCard dan NoteDialog (ok)
|
||||||
- **70% responden** percaya AI meningkatkan produktivitas kerja *(Eurobarometer, Feb 2025)*
|
* Dark/Light theme toggle (ok)
|
||||||
- **Pasar note-taking apps** menunjukkan pertumbuhan dengan tren integrasi AI
|
* Markdown Parser (ok)
|
||||||
- **Gemini 2.5 Flash** dipilih sebagai model "price-performance" terbaik untuk low-latency tasks
|
|
||||||
|
|
||||||
### Diferensiasi NotesAI
|
|
||||||
🎯 **AI Contextual** - AI dapat membaca semua catatan sebagai konteks
|
|
||||||
🎯 **Document to Summary** - Upload file langsung dapat ringkasan
|
|
||||||
🎯 **Local-First** - Tidak butuh login, data tersimpan lokal
|
|
||||||
🎯 **Free & Open** - Tidak ada paywall untuk fitur utama
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎨 Desain UI/UX
|
## **Features for Sprint 4 v1.1.0**
|
||||||
|
* Penyesuaian UI/UX History Chat AI (ok)
|
||||||
### Design System
|
* Rich text editor (ok - Harus Pengembangan Lanjutan)
|
||||||
- **Material Design 3** - Modern, clean, consistent
|
|
||||||
- **Color Scheme** - Dynamic gradients untuk kategori
|
|
||||||
- **Typography** - Clear hierarchy untuk readability
|
|
||||||
- **Spacing** - Consistent 4dp baseline grid
|
|
||||||
|
|
||||||
### User Flow
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────┐
|
|
||||||
│ 🏠 Main Screen (Home) │
|
|
||||||
│ ┌─────────────┐ ┌─────────────┐ │
|
|
||||||
│ │ Category │ │ Category │ │
|
|
||||||
│ │ Card │ │ Card │ │
|
|
||||||
│ └─────────────┘ └─────────────┘ │
|
|
||||||
└───────────┬─────────────────────────────────┘
|
|
||||||
│ Select Category
|
|
||||||
▼
|
|
||||||
┌─────────────────────────────────────────────┐
|
|
||||||
│ 📄 Notes List Screen │
|
|
||||||
│ ┌─────────────┐ ┌─────────────┐ │
|
|
||||||
│ │ Note Card │ │ Note Card │ │
|
|
||||||
│ │ (Pinned) │ │ (Regular) │ │
|
|
||||||
│ └─────────────┘ └─────────────┘ │
|
|
||||||
└───────────┬─────────────────────────────────┘
|
|
||||||
│ Open Note
|
|
||||||
▼
|
|
||||||
┌─────────────────────────────────────────────┐
|
|
||||||
│ ✏️ Full-Screen Editor │
|
|
||||||
│ • Rich Text Toolbar (Draggable) │
|
|
||||||
│ • Bold, Italic, Underline │
|
|
||||||
│ • Heading, Bullet List │
|
|
||||||
│ • Auto-save on background │
|
|
||||||
└─────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Wireframe & Mockup
|
|
||||||
📐 **Wireframe lengkap** tersedia di [Dokumentasi](docs/Laporan%20Dokumentasi%20Aplikasi%20-%20Kelompok%201.pdf) Halaman 15
|
|
||||||
📸 **Screenshot aplikasi** tersedia di Panduan Pengguna (Halaman 21-28)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠️ Teknologi dan Alat
|
## **Features for Sprint 5 v1.1.0**
|
||||||
|
* Fungsi AI (Upload File) (ok)
|
||||||
### Tech Stack
|
* Fitur Sematkan Category, otomatis paling atas (ok)
|
||||||
|
|
||||||
#### Core Technologies
|
|
||||||
```
|
|
||||||
// Build Configuration
|
|
||||||
Kotlin 1.9.0
|
|
||||||
Android Gradle Plugin 8.2.0
|
|
||||||
Compile SDK 34
|
|
||||||
Min SDK 24 (Android 7.0)
|
|
||||||
Target SDK 34
|
|
||||||
```
|
|
||||||
|
|
||||||
#### UI & Architecture
|
|
||||||
- **Jetpack Compose** - Modern declarative UI
|
|
||||||
- **Material 3** - Latest Material Design components
|
|
||||||
- **Navigation Compose** - Type-safe navigation
|
|
||||||
- **Lifecycle** - Lifecycle-aware components
|
|
||||||
|
|
||||||
#### Data & Storage
|
|
||||||
- **DataStore Preferences** - Key-value storage
|
|
||||||
- **Kotlinx Serialization** - JSON serialization
|
|
||||||
- **Kotlin Coroutines** - Asynchronous programming
|
|
||||||
- **Flow** - Reactive data streams
|
|
||||||
|
|
||||||
#### AI & Integration
|
|
||||||
- **Gemini API** - Google Generative AI (Gemini 2.5 Flash)
|
|
||||||
- **PDFBox-Android** - PDF text extraction
|
|
||||||
- **Activity Result API** - File picker for document upload
|
|
||||||
|
|
||||||
#### Development Tools
|
|
||||||
- **Android Studio**
|
|
||||||
- **Git** - Version control (git.lab.ubharajaya.ac.id)
|
|
||||||
- **Gradle** - Build automation
|
|
||||||
- **Claude AI** - AI-assisted development
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
```gradle
|
|
||||||
dependencies {
|
|
||||||
// Compose
|
|
||||||
implementation("androidx.compose.ui:ui:1.6.0")
|
|
||||||
implementation("androidx.compose.material3:material3:1.2.0")
|
|
||||||
|
|
||||||
// DataStore
|
|
||||||
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
|
||||||
|
|
||||||
// Serialization
|
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
|
|
||||||
|
|
||||||
// AI
|
|
||||||
implementation("com.google.ai.client.generativeai:generativeai:0.1.2")
|
|
||||||
|
|
||||||
// PDF Parser
|
|
||||||
implementation("com.tom-roush:pdfbox-android:2.0.27.0")
|
|
||||||
|
|
||||||
// Testing
|
|
||||||
testImplementation("junit:junit:4.13.2")
|
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏗️ Arsitektur Aplikasi
|
|
||||||
|
|
||||||
### Architecture Pattern
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ PRESENTATION LAYER │
|
|
||||||
│ ┌──────────────────────────────────────────┐ │
|
|
||||||
│ │ Composable Screens │ │
|
|
||||||
│ │ • MainScreen │ │
|
|
||||||
│ │ • AIHelperScreen │ │
|
|
||||||
│ │ • ArchiveScreen, TrashScreen │ │
|
|
||||||
│ └──────────────────────────────────────────┘ │
|
|
||||||
└────────────────────┬─────────────────────────────┘
|
|
||||||
│ Uses
|
|
||||||
▼
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ DATA LAYER │
|
|
||||||
│ ┌──────────────────────────────────────────┐ │
|
|
||||||
│ │ DataStoreManager │ │
|
|
||||||
│ │ • saveNotes() / notesFlow │ │
|
|
||||||
│ │ • saveCategories() / categoriesFlow │ │
|
|
||||||
│ │ • saveChatHistory() / chatHistoryFlow │ │
|
|
||||||
│ └──────────────────────────────────────────┘ │
|
|
||||||
└────────────────────┬─────────────────────────────┘
|
|
||||||
│ Stores
|
|
||||||
▼
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ MODEL LAYER │
|
|
||||||
│ • Note (id, title, content, isPinned...) │
|
|
||||||
│ • Category (id, name, gradients, isPinned...) │
|
|
||||||
│ • ChatHistory (messages, timestamp...) │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Package Structure
|
|
||||||
```
|
|
||||||
com.example.notesai/
|
|
||||||
├── 📁 config/
|
|
||||||
│ └── APIKey.kt
|
|
||||||
├── 📁 data/
|
|
||||||
│ ├── 📁 local/
|
|
||||||
│ │ └── DataStoreManager.kt
|
|
||||||
│ └── 📁 model/
|
|
||||||
│ ├── Note.kt
|
|
||||||
│ ├── Category.kt
|
|
||||||
│ ├── ChatHistory.kt
|
|
||||||
│ └── ChatMessage.kt
|
|
||||||
├── 📁 presentation/
|
|
||||||
│ ├── 📁 components/
|
|
||||||
│ │ ├── DrawerMenu.kt
|
|
||||||
│ │ ├── ModernTopBar.kt
|
|
||||||
│ │ └── ModernBottomBar.kt
|
|
||||||
│ └── 📁 screens/
|
|
||||||
│ ├── 📁 main/
|
|
||||||
│ ├── 📁 ai/
|
|
||||||
│ ├── 📁 archive/
|
|
||||||
│ ├── 📁 trash/
|
|
||||||
│ └── 📁 note/
|
|
||||||
└── 📁 util/
|
|
||||||
├── FileParser.kt
|
|
||||||
├── Constants.kt
|
|
||||||
└── AppColors.kt
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Resource yang Digunakan
|
|
||||||
|
|
||||||
### Visual Assets
|
|
||||||
- 🎨 **Icons** - Material Icons & Lucide Icons
|
|
||||||
- 🌈 **Colors** - Material 3 Dynamic Color
|
|
||||||
- 🖼️ **Illustrations** - Custom empty states
|
|
||||||
|
|
||||||
### Content & Data
|
|
||||||
- 📖 **Sample Data** - Test categories & notes untuk demo
|
|
||||||
- 📄 **Documents** - Sample PDF/TXT untuk testing parser
|
|
||||||
|
|
||||||
### External Services
|
|
||||||
- 🤖 **Gemini API** - Google Generative AI
|
|
||||||
- 📚 **Documentation** - Android Developers, Kotlin Docs
|
|
||||||
|
|
||||||
### Learning Resources
|
|
||||||
Referensi utama yang digunakan:
|
|
||||||
- [Android App Architecture Guide](https://developer.android.com/topic/architecture)
|
|
||||||
- [Jetpack Compose Documentation](https://developer.android.com/jetpack/compose)
|
|
||||||
- [Gemini API Documentation](https://ai.google.dev/docs)
|
|
||||||
- [Kotlin Serialization](https://kotlinlang.org/docs/serialization.html)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧪 Pengujian Aplikasi
|
|
||||||
|
|
||||||
### Metodologi Testing
|
|
||||||
|
|
||||||
**Primary Method:** Black-Box Functional Testing
|
|
||||||
**Supporting Method:** Automated Unit Testing
|
|
||||||
|
|
||||||
Pengujian dilakukan menggunakan metode **Black-Box Functional Testing** sebagai pendekatan utama, dimana setiap fitur divalidasi dari perspektif end-user dengan memverifikasi kesesuaian **Expected vs Actual Result**. Didukung oleh **59 automated unit tests** untuk validasi business logic internal.
|
|
||||||
|
|
||||||
### Test Coverage Summary
|
|
||||||
|
|
||||||
| Test Case | Fitur | Tests | Status |
|
|
||||||
|-----------|-------|-------|--------|
|
|
||||||
| **TC-01** | Create Note & Category + Autosave | 8 tests | ✅ PASSED |
|
|
||||||
| **TC-02** | Pin Note (Priority) | included | ✅ PASSED |
|
|
||||||
| **TC-03** | Soft Delete & Restore | 11 tests | ✅ PASSED |
|
|
||||||
| **TC-04** | Search Realtime | 14 tests | ✅ PASSED |
|
|
||||||
| **TC-05** | AI Chat with Context | 14 tests | ✅ PASSED |
|
|
||||||
| **TC-06** | Upload PDF → Summary | 12 tests | ✅ PASSED |
|
|
||||||
| **TOTAL** | **6 Test Cases** | **59 tests** | **✅ 100%** |
|
|
||||||
|
|
||||||
### Test Results
|
|
||||||
|
|
||||||
```
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
📊 TEST SUMMARY REPORT
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
Total Test Cases: 6
|
|
||||||
Passed Test Cases: 6
|
|
||||||
Failed Test Cases: 0
|
|
||||||
Success Rate: 100%
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
Total Unit Tests: 59
|
|
||||||
Passed Tests: 59
|
|
||||||
Failed Tests: 0
|
|
||||||
Execution Time: ~2 minutes
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
Status: ✅ ALL TESTS PASSED
|
|
||||||
Quality: ✅ PRODUCTION READY
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
```
|
|
||||||
|
|
||||||
📄 **Laporan lengkap:** [TEST_SUMMARY_REPORT.md](./TEST_SUMMARY_REPORT.md)
|
|
||||||
|
|
||||||
### Testing Framework
|
|
||||||
- **JUnit 4** - Unit testing framework
|
|
||||||
- **AndroidX Test** - Android testing utilities
|
|
||||||
- **Kotlin Coroutines Test** - Async testing
|
|
||||||
- **Truth** - Assertion library
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Instalasi dan Penggunaan
|
|
||||||
|
|
||||||
### Prasyarat
|
|
||||||
- ✅ Android 7.0 (API 24) atau lebih tinggi
|
|
||||||
- ✅ Koneksi internet (untuk fitur AI)
|
|
||||||
- ✅ Minimal 50MB storage kosong
|
|
||||||
|
|
||||||
### Cara Menjalankan dari Source Code
|
|
||||||
|
|
||||||
#### 1. Clone Repository
|
|
||||||
```bash
|
|
||||||
git clone https://git.lab.ubharajaya.ac.id/kelompok-3/notesai.git
|
|
||||||
cd notesai
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Setup API Key
|
|
||||||
Buat file `local.properties` di root project:
|
|
||||||
```properties
|
|
||||||
GEMINI_API_KEY=your_gemini_api_key_here
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3. Open di Android Studio
|
|
||||||
1. Buka Android Studio
|
|
||||||
2. File → Open → Pilih folder project
|
|
||||||
3. Tunggu Gradle sync selesai
|
|
||||||
|
|
||||||
#### 4. Run Aplikasi
|
|
||||||
1. Pilih device/emulator
|
|
||||||
2. Klik Run (▶️) atau `Shift + F10`
|
|
||||||
3. Aplikasi akan terinstall dan berjalan
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📱 Panduan Penggunaan
|
|
||||||
|
|
||||||
### Quick Start Guide
|
|
||||||
|
|
||||||
#### 1️⃣ Membuat Kategori Pertama
|
|
||||||
```
|
|
||||||
Main Screen → Tap (➕) → Pilih "Kategori Baru"
|
|
||||||
→ Isi nama kategori → Pilih warna → Save
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2️⃣ Membuat Note
|
|
||||||
```
|
|
||||||
Main Screen → Tap kategori → Tap (➕) floating button
|
|
||||||
→ Isi judul & konten → Auto-saved ✓
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3️⃣ Menggunakan Rich Text Editor
|
|
||||||
```
|
|
||||||
Buka note → Tap area teks → Muncul draggable toolbar
|
|
||||||
→ Pilih format (Bold/Italic/Heading/Bullet) → Type away!
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4️⃣ Pin untuk Prioritas
|
|
||||||
```
|
|
||||||
Long-press note → Tap ⭐ Pin icon
|
|
||||||
→ Note akan muncul di urutan teratas
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 5️⃣ Chat dengan AI
|
|
||||||
```
|
|
||||||
Drawer Menu → AI Assistant → Ketik pertanyaan
|
|
||||||
→ AI akan menjawab berdasarkan catatan Anda
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 6️⃣ Upload & Summarize Document
|
|
||||||
```
|
|
||||||
AI Assistant → Tap 📎 Upload → Pilih file (PDF/TXT/DOCX)
|
|
||||||
→ AI otomatis generate summary → Tersimpan di chat history
|
|
||||||
```
|
|
||||||
|
|
||||||
### User Flow Lengkap
|
|
||||||
📖 Panduan detail dengan screenshot tersedia di [Dokumentasi](./docs/Laporan%20Dokumentasi%20Aplikasi%20-%20Kelompok%201.pdf) Bab III (Halaman 21-28)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ Batasan dan Catatan
|
|
||||||
|
|
||||||
### Keterbatasan Saat Ini
|
|
||||||
1. **AI Dependency**
|
|
||||||
- ⚠️ Fitur AI memerlukan koneksi internet
|
|
||||||
- ⚠️ Menggunakan free tier Gemini API (rate limited)
|
|
||||||
- ℹ️ Catatan lokal tetap berfungsi offline
|
|
||||||
|
|
||||||
2. **Document Format**
|
|
||||||
- ✅ Support: PDF, TXT, DOCX
|
|
||||||
- ❌ Tidak support: XLS, PPT, Images
|
|
||||||
|
|
||||||
3. **Data Storage**
|
|
||||||
- 💾 Data tersimpan lokal (DataStore)
|
|
||||||
- ⚠️ Tidak ada cloud backup (planned v2.0)
|
|
||||||
- ℹ️ Risiko data loss jika uninstall app
|
|
||||||
|
|
||||||
4. **Performance**
|
|
||||||
- ⚡ Optimal untuk <1000 notes
|
|
||||||
- ⚠️ Search dapat melambat pada dataset besar
|
|
||||||
- 🔜 Indexing optimization planned
|
|
||||||
|
|
||||||
### Privasi & Keamanan
|
|
||||||
- ✅ Catatan disimpan **100% lokal**
|
|
||||||
- ⚠️ Saat menggunakan AI, konten relevan dikirim ke Gemini API
|
|
||||||
- 🔐 API key tidak hardcoded (menggunakan BuildConfig)
|
|
||||||
- ℹ️ Tidak ada tracking atau analytics
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔮 Roadmap & Future Development
|
|
||||||
|
|
||||||
### Version 1.2.0 (Q2 2025) 🎯
|
|
||||||
- [ ] **Cloud Sync** - Firebase/Supabase integration
|
|
||||||
- [ ] **Backup & Restore** - Export/import data
|
|
||||||
- [ ] **Widget** - Home screen quick note
|
|
||||||
- [ ] **Reminder** - Notification untuk note penting
|
|
||||||
- [ ] **Templates** - Pre-made note templates
|
|
||||||
|
|
||||||
### Version 1.3.0 (Q3 2025) 🚀
|
|
||||||
- [ ] **Collaboration** - Share notes dengan user lain
|
|
||||||
- [ ] **Voice Input** - Speech-to-text untuk note
|
|
||||||
- [ ] **Image Support** - Attach images ke notes
|
|
||||||
- [ ] **Tag System** - Alternative categorization
|
|
||||||
- [ ] **Advanced Search** - Filter by date, tag, etc.
|
|
||||||
|
|
||||||
### Version 1.4.0 (Q4 2025) 💎
|
|
||||||
- [ ] **Multi-device Sync** - Real-time sync
|
|
||||||
- [ ] **Encryption** - End-to-end encryption
|
|
||||||
- [ ] **Premium AI** - Upgrade ke Gemini Pro
|
|
||||||
- [ ] **Offline AI** - On-device AI model
|
|
||||||
- [ ] **iOS Version** - Cross-platform support
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📄 Dokumentasi Tambahan
|
|
||||||
|
|
||||||
### File Dokumentasi
|
|
||||||
- 📖 [Laporan Lengkap](./docs/Laporan%20Dokumentasi%20Aplikasi%20-%20Kelompok%201.pdf) - Dokumentasi lengkap 35 halaman
|
|
||||||
- 🧪 [Test Summary Report](./TEST_SUMMARY_REPORT.md) - Laporan pengujian detail
|
|
||||||
- 📋 [Changelog](./CHANGELOG.md) - Riwayat perubahan versi
|
|
||||||
|
|
||||||
### API Documentation
|
|
||||||
- 🤖 [Gemini API Docs](https://ai.google.dev/docs)
|
|
||||||
- 📚 [Android Developers](https://developer.android.com)
|
|
||||||
- 📝 [Kotlin Documentation](https://kotlinlang.org/docs)
|
|
||||||
|
|
||||||
### Referensi Akademik
|
|
||||||
Semua referensi dan kutipan tercantum di [Daftar Pustaka](./docs/Laporan%20Dokumentasi%20Aplikasi%20-%20Kelompok%201.pdf) halaman 33
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🤝 Kontribusi & Support
|
|
||||||
|
|
||||||
### Cara Berkontribusi
|
|
||||||
1. Fork repository ini
|
|
||||||
2. Buat branch fitur (`git checkout -b feature/AmazingFeature`)
|
|
||||||
3. Commit changes (`git commit -m 'Add some AmazingFeature'`)
|
|
||||||
4. Push ke branch (`git push origin feature/AmazingFeature`)
|
|
||||||
5. Buat Pull Request
|
|
||||||
|
|
||||||
### Coding Standards
|
|
||||||
- ✅ Follow Kotlin coding conventions
|
|
||||||
- ✅ Write descriptive commit messages
|
|
||||||
- ✅ Add unit tests untuk fitur baru
|
|
||||||
- ✅ Update documentation
|
|
||||||
|
|
||||||
### Laporkan Bug
|
|
||||||
Jika menemukan bug, silakan buat issue dengan:
|
|
||||||
- 📝 Deskripsi bug
|
|
||||||
- 📱 Device & Android version
|
|
||||||
- 🔄 Steps to reproduce
|
|
||||||
- 📸 Screenshot (jika ada)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📜 License
|
|
||||||
|
|
||||||
```
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2025 Kelompok 1 - NotesAI
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🙏 Acknowledgments
|
|
||||||
|
|
||||||
### Special Thanks
|
|
||||||
- 🎓 **Bapak Arif Rifai Dwiyanto, ST., MTI** - Dosen pembimbing dan pengampu mata kuliah
|
|
||||||
- 🏫 **Universitas Bhayangkara Jakarta Raya** - Dukungan fasilitas
|
|
||||||
- 🤖 **Claude AI (Anthropic)** - AI assistant untuk pengembangan dan debugging
|
|
||||||
- 🎨 **Material Design Team** - Design system yang digunakan
|
|
||||||
- 📚 **Android Developer Community** - Dokumentasi dan best practices
|
|
||||||
|
|
||||||
### Tools & Services
|
|
||||||
- Android Studio - IDE terbaik untuk Android development
|
|
||||||
- Jetpack Compose - Modern UI toolkit
|
|
||||||
- Gemini API - AI capabilities
|
|
||||||
- PDFBox - PDF parsing library
|
|
||||||
- Git Lab UBHARA - Version control hosting
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📞 Kontak
|
|
||||||
|
|
||||||
**Tim Pengembang Kelompok 3**
|
|
||||||
|
|
||||||
📧 Email: [kelompok3.notesai@ubharajaya.ac.id](mailto:kelompok3.notesai@ubharajaya.ac.id)
|
|
||||||
🌐 Repository: [NotesAI](https://git.lab.ubharajaya.ac.id/202310715297-RAIHAN-ARIQ-MUZAKKI/NotesAI.git)
|
|
||||||
🏫 Institusi: Universitas Bhayangkara Jakarta Raya
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Made with ❤️ by Kelompok 3**
|
|
||||||
|
|
||||||
**Fakultas Ilmu Komputer - Program Studi Informatika**
|
|
||||||
**Universitas Bhayangkara Jakarta Raya**
|
|
||||||
|
|
||||||
**2025**
|
|
||||||
|
|
||||||
[⬆️ Back to Top](#-notesai---ai-powered-note-taking-app)
|
|
||||||
|
|
||||||
|
|||||||
@ -8,11 +8,18 @@
|
|||||||
**Total Unit Tests:** 59
|
**Total Unit Tests:** 59
|
||||||
**Status:** ✅ ALL PASSED
|
**Status:** ✅ ALL PASSED
|
||||||
|
|
||||||
Pengujian fungsional dilakukan secara manual dengan metode black-box berbasis test case,
|
---
|
||||||
didukung oleh Automated Unit Tests, memverifikasi kesesuaian expected vs actual result pada fitur inti
|
|
||||||
(notes, kategori, pin, trash/restore, search, AI context, dan upload-summary).
|
## Test Cases Summary
|
||||||
Unit testing adalah pengujian otomatis terhadap unit terkecil dari kode
|
|
||||||
(functions, methods) untuk memvalidasi logic internal aplikasi.
|
| ID | Fitur | Skenario | Langkah Uji | Expected Result | Actual Result | Status |
|
||||||
|
|----|-------|----------|-------------|-----------------|---------------|--------|
|
||||||
|
| **TC-01** | **Create Note & Category + Autosave** | Membuat note dan category baru dengan autosave debounce 500ms | 1. Buat category baru<br>2. Buat note baru<br>3. Edit note<br>4. Tunggu 500ms<br>5. Verify autosave | - Category tersimpan dengan benar<br>- Note tersimpan dengan benar<br>- Autosave berjalan setelah 500ms debounce<br>- Data ter-update | - ✅ Category tersimpan: `testCreateCategory_shouldSaveSuccessfully`<br>- ✅ Note tersimpan: `testCreateNote_shouldSaveSuccessfully`<br>- ✅ Multiple categories: `testCreateMultipleCategories_shouldSaveInCorrectOrder`<br>- ✅ Autosave works: `testAutoSave_shouldUpdateExistingNote` | ✅ PASSED<br>(8 tests) |
|
||||||
|
| **TC-02** | **Pin Note** | Pin note muncul di urutan teratas | 1. Buat 3 notes dengan timestamp berbeda<br>2. Pin note terlama<br>3. Verify urutan | - Pinned note muncul di posisi teratas<br>- Unpinned notes diurutkan berdasarkan timestamp<br>- Multiple pinned notes diurutkan by timestamp | - ✅ Pinned note first: `testPinNote_shouldAppearFirst`<br>- ✅ Multiple pins sorted: `testMultiplePinnedNotes_shouldSortByTimestamp`<br>- ✅ Unpin works: `testUnpinNote_shouldMoveToNormalPosition`<br>- ✅ Category pin: `testPinCategory_shouldPersist` | ✅ PASSED<br>(included in TC-01) |
|
||||||
|
| **TC-03** | **Soft Delete & Restore** | Soft delete note/category dan restore dari trash | 1. Delete note/category (soft delete)<br>2. Verify item masuk trash<br>3. Restore item dari trash<br>4. Verify item kembali aktif<br>5. Test permanent delete | - Item ditandai `isDeleted=true`<br>- Item muncul di trash screen<br>- Restore mengembalikan `isDeleted=false`<br>- Data tetap preserved<br>- Permanent delete menghapus sepenuhnya | - ✅ Soft delete note: `testSoftDeleteNote_shouldMarkAsDeleted`<br>- ✅ Restore note: `testRestoreNoteFromTrash_shouldUnmarkDeleted`<br>- ✅ Soft delete category: `testSoftDeleteCategory_shouldMarkAsDeleted`<br>- ✅ Restore category: `testRestoreCategoryFromTrash_shouldUnmarkDeleted`<br>- ✅ Filter deleted: `testFilterDeletedNotes_shouldOnlyShowDeleted`<br>- ✅ Permanent delete: `testPermanentDeleteNote_shouldRemoveCompletely`<br>- ✅ Data preserved: `testDeletedNotePreservesAllData_shouldKeepContent` | ✅ PASSED<br>(11 tests) |
|
||||||
|
| **TC-04** | **Search Realtime** | Search realtime menemukan keyword di notes dan categories | 1. Buat multiple notes dengan content berbeda<br>2. Input search query<br>3. Verify hasil realtime<br>4. Test case-insensitive<br>5. Test partial match<br>6. Test filter by category | - Search menemukan notes by title<br>- Search menemukan notes by content<br>- Case-insensitive search works<br>- Partial match ditemukan<br>- Empty query return all<br>- Exclude deleted & archived notes | - ✅ Search by title: `testSearchNoteByTitle_shouldFindMatches`<br>- ✅ Search by content: `testSearchNoteByContent_shouldFindMatches`<br>- ✅ Case insensitive: `testSearchCaseInsensitive_shouldFindMatches`<br>- ✅ Partial match: `testSearchPartialMatch_shouldFindResults`<br>- ✅ Empty query: `testSearchEmptyQuery_shouldReturnAllNotes`<br>- ✅ Exclude deleted: `testSearchExcludesDeletedNotes_shouldNotFindDeleted`<br>- ✅ Search category: `testSearchCategory_shouldFindByName`<br>- ✅ Realtime update: `testSearchRealtime_shouldUpdateImmediately` | ✅ PASSED<br>(14 tests) |
|
||||||
|
| **TC-05** | **AI Chat with Context** | AI chat menjawab dengan konteks note (gunakan 1-2 contoh note) | 1. Buat 1-2 sample notes<br>2. Open AI chat<br>3. Send query tentang notes<br>4. Verify AI dapat akses context<br>5. Save chat history<br>6. Load chat history | - Context mencakup semua notes<br>- Context filtered by category<br>- Exclude archived notes<br>- Chat history tersimpan<br>- Chat history bisa di-load<br>- Custom title bisa di-set | - ✅ Build context: `testBuildNotesContext_shouldIncludeAllNotes`<br>- ✅ Filter by category: `testBuildNotesContext_shouldFilterByCategory`<br>- ✅ Exclude archived: `testBuildNotesContext_shouldExcludeArchivedNotes`<br>- ✅ Save history: `testSaveChatHistory_shouldPersist`<br>- ✅ Load history: `testLoadChatHistory_shouldRestoreMessages`<br>- ✅ Sort histories: `testMultipleChatHistories_shouldSortByTimestamp`<br>- ✅ Update history: `testUpdateChatHistory_shouldUpdateExisting`<br>- ✅ Delete history: `testDeleteChatHistory_shouldMarkAsDeleted`<br>- ✅ Custom title: `testCustomChatTitle_shouldPersist` | ✅ PASSED<br>(14 tests) |
|
||||||
|
| **TC-06** | **Upload PDF → Summary** | Upload PDF dan summary tersimpan/terbaca | 1. Upload file (PDF/TXT/DOCX)<br>2. Verify file parsed<br>3. Generate AI summary<br>4. Save summary to chat history<br>5. Verify summary readable<br>6. Test error handling | - File di-parse dengan benar<br>- Word count calculated<br>- File type identified<br>- Summary generated & saved<br>- Summary tersimpan di chat history<br>- Metadata preserved<br>- Error handling gracefully | - ✅ Word count: `testFileParseResult_shouldCalculateWordCount`<br>- ✅ File type: `testFileParseResult_shouldIdentifyFileType`<br>- ✅ File size format: `testFormatFileSize_shouldFormatCorrectly`<br>- ✅ Save summary: `testSaveSummaryToChatHistory_shouldPersist`<br>- ✅ Multiple uploads: `testMultipleFileUploads_shouldTrackAll`<br>- ✅ Summary readable: `testSummaryContent_shouldBeReadable`<br>- ✅ Error handling: `testFileUploadError_shouldHandleGracefully`<br>- ✅ Structured format: `testPDFSummaryFormat_shouldBeStructured`<br>- ✅ Metadata preserved: `testFileMetadata_shouldBePreserved` | ✅ PASSED<br>(12 tests) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -247,24 +247,21 @@ fun NotesApp() {
|
|||||||
if (!showFullScreenNote && currentScreen != "ai") {
|
if (!showFullScreenNote && currentScreen != "ai") {
|
||||||
ModernTopBar(
|
ModernTopBar(
|
||||||
title = when(currentScreen) {
|
title = when(currentScreen) {
|
||||||
"main" -> if (selectedCategory != null) selectedCategory!!.name else "NotesAI"
|
"main" -> if (selectedCategory != null) selectedCategory!!.name else "AI Notes"
|
||||||
"starred" -> "Berbintang"
|
"starred" -> "Berbintang"
|
||||||
"archive" -> "Arsip"
|
"archive" -> "Arsip"
|
||||||
"trash" -> "Sampah"
|
"trash" -> "Sampah"
|
||||||
else -> "NotesAI"
|
else -> "AI Notes"
|
||||||
},
|
},
|
||||||
showBackButton = (selectedCategory != null && currentScreen == "main"),
|
showBackButton = (selectedCategory != null && currentScreen == "main"),
|
||||||
onBackClick = {
|
onBackClick = {
|
||||||
selectedCategory = null
|
selectedCategory = null
|
||||||
},
|
},
|
||||||
onMenuClick = { drawerState = !drawerState },
|
onMenuClick = { drawerState = !drawerState },
|
||||||
onSearchClick = {
|
onSearchClick = { showSearch = !showSearch },
|
||||||
showSearch = !showSearch
|
|
||||||
if (!showSearch) searchQuery = "" // Reset search saat close
|
|
||||||
},
|
|
||||||
searchQuery = searchQuery,
|
searchQuery = searchQuery,
|
||||||
onSearchQueryChange = { searchQuery = it },
|
onSearchQueryChange = { searchQuery = it },
|
||||||
showSearch = showSearch // AKTIFKAN UNTUK SEMUA SCREEN
|
showSearch = showSearch && currentScreen == "main"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -429,7 +426,6 @@ fun NotesApp() {
|
|||||||
"trash" -> TrashScreen(
|
"trash" -> TrashScreen(
|
||||||
notes = notes.filter { it.isDeleted },
|
notes = notes.filter { it.isDeleted },
|
||||||
categories = categories,
|
categories = categories,
|
||||||
searchQuery = searchQuery, // TAMBAHKAN INI
|
|
||||||
onRestoreNote = { note ->
|
onRestoreNote = { note ->
|
||||||
notes = notes.map {
|
notes = notes.map {
|
||||||
if (it.id == note.id) it.copy(isDeleted = false, isArchived = false)
|
if (it.id == note.id) it.copy(isDeleted = false, isArchived = false)
|
||||||
@ -458,7 +454,6 @@ fun NotesApp() {
|
|||||||
"starred" -> StarredNotesScreen(
|
"starred" -> StarredNotesScreen(
|
||||||
notes = notes,
|
notes = notes,
|
||||||
categories = categories.filter { !it.isDeleted },
|
categories = categories.filter { !it.isDeleted },
|
||||||
searchQuery = searchQuery, // TAMBAHKAN INI
|
|
||||||
onNoteClick = { note ->
|
onNoteClick = { note ->
|
||||||
fullScreenNote = note
|
fullScreenNote = note
|
||||||
showFullScreenNote = true
|
showFullScreenNote = true
|
||||||
@ -474,7 +469,6 @@ fun NotesApp() {
|
|||||||
"archive" -> ArchiveScreen(
|
"archive" -> ArchiveScreen(
|
||||||
notes = notes.filter { it.isArchived && !it.isDeleted },
|
notes = notes.filter { it.isArchived && !it.isDeleted },
|
||||||
categories = categories.filter { !it.isDeleted },
|
categories = categories.filter { !it.isDeleted },
|
||||||
searchQuery = searchQuery,
|
|
||||||
onRestore = { note ->
|
onRestore = { note ->
|
||||||
notes = notes.map {
|
notes = notes.map {
|
||||||
if (it.id == note.id) it.copy(isArchived = false)
|
if (it.id == note.id) it.copy(isArchived = false)
|
||||||
@ -572,8 +566,8 @@ fun NotesApp() {
|
|||||||
currentScreen = screen
|
currentScreen = screen
|
||||||
selectedCategory = null
|
selectedCategory = null
|
||||||
drawerState = false
|
drawerState = false
|
||||||
showSearch = false // TUTUP SEARCH
|
showSearch = false
|
||||||
searchQuery = "" // RESET SEARCH QUERY
|
searchQuery = ""
|
||||||
},
|
},
|
||||||
onThemeToggle = {
|
onThemeToggle = {
|
||||||
isDarkTheme = !isDarkTheme
|
isDarkTheme = !isDarkTheme
|
||||||
|
|||||||
@ -4,13 +4,27 @@ import androidx.compose.foundation.layout.Arrangement
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
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.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Archive
|
import androidx.compose.material.icons.filled.Archive
|
||||||
|
import androidx.compose.material.icons.filled.Clear
|
||||||
import androidx.compose.material.icons.filled.Search
|
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.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.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.notesai.data.model.Note
|
import com.example.notesai.data.model.Note
|
||||||
import com.example.notesai.data.model.Category
|
import com.example.notesai.data.model.Category
|
||||||
@ -21,11 +35,12 @@ import com.example.notesai.presentation.screens.archive.components.ArchiveNoteCa
|
|||||||
fun ArchiveScreen(
|
fun ArchiveScreen(
|
||||||
notes: List<Note>,
|
notes: List<Note>,
|
||||||
categories: List<Category>,
|
categories: List<Category>,
|
||||||
searchQuery: String = "", // Tambahkan parameter ini
|
|
||||||
onRestore: (Note) -> Unit,
|
onRestore: (Note) -> Unit,
|
||||||
onDelete: (Note) -> Unit
|
onDelete: (Note) -> Unit
|
||||||
) {
|
) {
|
||||||
// Filter berdasarkan search query dari ModernTopBar
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
// Filter berdasarkan search query
|
||||||
val filteredNotes = if (searchQuery.isBlank()) {
|
val filteredNotes = if (searchQuery.isBlank()) {
|
||||||
notes
|
notes
|
||||||
} else {
|
} else {
|
||||||
@ -38,6 +53,50 @@ fun ArchiveScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
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
|
// Content
|
||||||
if (filteredNotes.isEmpty()) {
|
if (filteredNotes.isEmpty()) {
|
||||||
if (searchQuery.isNotEmpty()) {
|
if (searchQuery.isNotEmpty()) {
|
||||||
@ -58,7 +117,6 @@ fun ArchiveScreen(
|
|||||||
contentPadding = PaddingValues(
|
contentPadding = PaddingValues(
|
||||||
start = 16.dp,
|
start = 16.dp,
|
||||||
end = 16.dp,
|
end = 16.dp,
|
||||||
top = 8.dp,
|
|
||||||
bottom = 100.dp
|
bottom = 100.dp
|
||||||
),
|
),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
|||||||
@ -43,25 +43,11 @@ fun MainScreen(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Filter kategori berdasarkan searchQuery
|
// Filter kategori berdasarkan searchQuery
|
||||||
val filteredCategories = if (searchQuery.isBlank()) {
|
val filteredCategories = if (searchQuery.isEmpty()) {
|
||||||
categories
|
categories
|
||||||
} else {
|
} else {
|
||||||
categories.filter { category ->
|
categories.filter {
|
||||||
// 1. Cek nama kategori cocok
|
it.name.contains(searchQuery, ignoreCase = true)
|
||||||
val categoryNameMatches = category.name.contains(searchQuery, ignoreCase = true)
|
|
||||||
|
|
||||||
// 2. Cek ada catatan yang cocok di kategori ini
|
|
||||||
val hasMatchingNotes = notes.any { note ->
|
|
||||||
note.categoryId == category.id &&
|
|
||||||
!note.isDeleted &&
|
|
||||||
!note.isArchived &&
|
|
||||||
(note.title.contains(searchQuery, ignoreCase = true) ||
|
|
||||||
note.description.contains(searchQuery, ignoreCase = true) ||
|
|
||||||
note.content.contains(searchQuery, ignoreCase = true))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kategori muncul jika salah satu kondisi terpenuhi
|
|
||||||
categoryNameMatches || hasMatchingNotes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,15 +3,32 @@ package com.example.notesai.presentation.screens.starred
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
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.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
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.Search
|
||||||
import androidx.compose.material.icons.filled.Star
|
import androidx.compose.material.icons.filled.Star
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
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.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.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.notesai.presentation.components.EmptyState
|
import com.example.notesai.presentation.components.EmptyState
|
||||||
import com.example.notesai.presentation.screens.starred.components.StarredNoteCard
|
import com.example.notesai.presentation.screens.starred.components.StarredNoteCard
|
||||||
@ -23,15 +40,16 @@ import com.example.notesai.data.model.Category
|
|||||||
fun StarredNotesScreen(
|
fun StarredNotesScreen(
|
||||||
notes: List<Note>,
|
notes: List<Note>,
|
||||||
categories: List<Category>,
|
categories: List<Category>,
|
||||||
searchQuery: String = "", // Tambahkan parameter ini
|
|
||||||
onNoteClick: (Note) -> Unit,
|
onNoteClick: (Note) -> Unit,
|
||||||
onUnpin: (Note) -> Unit
|
onUnpin: (Note) -> Unit
|
||||||
) {
|
) {
|
||||||
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
|
|
||||||
val starredNotes = notes
|
val starredNotes = notes
|
||||||
.filter { it.isPinned && !it.isArchived && !it.isDeleted }
|
.filter { it.isPinned && !it.isArchived && !it.isDeleted }
|
||||||
.sortedByDescending { it.timestamp }
|
.sortedByDescending { it.timestamp }
|
||||||
|
|
||||||
// Filter berdasarkan search query dari ModernTopBar
|
// Filter berdasarkan search query
|
||||||
val filteredNotes = if (searchQuery.isBlank()) {
|
val filteredNotes = if (searchQuery.isBlank()) {
|
||||||
starredNotes
|
starredNotes
|
||||||
} else {
|
} else {
|
||||||
@ -43,6 +61,50 @@ fun StarredNotesScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
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 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
|
// Content
|
||||||
if (filteredNotes.isEmpty()) {
|
if (filteredNotes.isEmpty()) {
|
||||||
if (searchQuery.isNotEmpty()) {
|
if (searchQuery.isNotEmpty()) {
|
||||||
@ -63,7 +125,6 @@ fun StarredNotesScreen(
|
|||||||
contentPadding = PaddingValues(
|
contentPadding = PaddingValues(
|
||||||
start = 16.dp,
|
start = 16.dp,
|
||||||
end = 16.dp,
|
end = 16.dp,
|
||||||
top = 8.dp,
|
|
||||||
bottom = 100.dp
|
bottom = 100.dp
|
||||||
),
|
),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
|||||||
@ -4,15 +4,26 @@ import androidx.compose.foundation.layout.Arrangement
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
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.Delete
|
||||||
import androidx.compose.material.icons.filled.Search
|
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.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
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.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@ -27,17 +38,18 @@ import com.example.notesai.data.model.Category
|
|||||||
fun TrashScreen(
|
fun TrashScreen(
|
||||||
notes: List<Note>,
|
notes: List<Note>,
|
||||||
categories: List<Category>,
|
categories: List<Category>,
|
||||||
searchQuery: String = "", // Tambahkan parameter ini
|
|
||||||
onRestoreNote: (Note) -> Unit,
|
onRestoreNote: (Note) -> Unit,
|
||||||
onDeleteNotePermanent: (Note) -> Unit,
|
onDeleteNotePermanent: (Note) -> Unit,
|
||||||
onRestoreCategory: (Category) -> Unit,
|
onRestoreCategory: (Category) -> Unit,
|
||||||
onDeleteCategoryPermanent: (Category) -> Unit
|
onDeleteCategoryPermanent: (Category) -> Unit
|
||||||
) {
|
) {
|
||||||
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
|
|
||||||
// Filter kategori dan note yang dihapus
|
// Filter kategori dan note yang dihapus
|
||||||
val deletedCategories = categories.filter { it.isDeleted }
|
val deletedCategories = categories.filter { it.isDeleted }
|
||||||
val deletedNotes = notes.filter { it.isDeleted }
|
val deletedNotes = notes.filter { it.isDeleted }
|
||||||
|
|
||||||
// Filter berdasarkan search query dari ModernTopBar
|
// Filter berdasarkan search query
|
||||||
val filteredCategories = if (searchQuery.isBlank()) {
|
val filteredCategories = if (searchQuery.isBlank()) {
|
||||||
deletedCategories
|
deletedCategories
|
||||||
} else {
|
} else {
|
||||||
@ -58,6 +70,50 @@ fun TrashScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
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
|
// Content
|
||||||
if (filteredCategories.isEmpty() && filteredNotes.isEmpty()) {
|
if (filteredCategories.isEmpty() && filteredNotes.isEmpty()) {
|
||||||
if (searchQuery.isNotEmpty()) {
|
if (searchQuery.isNotEmpty()) {
|
||||||
@ -78,7 +134,6 @@ fun TrashScreen(
|
|||||||
contentPadding = PaddingValues(
|
contentPadding = PaddingValues(
|
||||||
start = 16.dp,
|
start = 16.dp,
|
||||||
end = 16.dp,
|
end = 16.dp,
|
||||||
top = 8.dp,
|
|
||||||
bottom = 100.dp
|
bottom = 100.dp
|
||||||
),
|
),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">NotesAI</string>
|
<string name="app_name">AI Notes</string>
|
||||||
</resources>
|
</resources>
|
||||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user