Compare commits
6 Commits
9715d958ae
...
cd035198f5
| Author | SHA1 | Date | |
|---|---|---|---|
| cd035198f5 | |||
| ca6ff4410a | |||
| 3b9b2e030f | |||
| 08dc54116e | |||
| 171d808dad | |||
| 4caea5c83e |
361
CHANGELOG.md
Normal file
361
CHANGELOG.md
Normal file
@ -0,0 +1,361 @@
|
||||
# **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,306 +1,599 @@
|
||||
# **AI Notes – Changelog**
|
||||
# 📝 NotesAI - AI-Powered Note Taking App 1.1.0
|
||||
|
||||
## **Tim Pengembang**
|
||||
|
||||
* Dendi Yogia Pratama
|
||||
* Raihan Ariq Muzakki
|
||||
* Fazri Abdurrahman
|
||||
|
||||
# **Version 1.0.0 – Initial Release**
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## **Sprint 1: Struktur Dasar Aplikasi**
|
||||
**Aplikasi pencatatan cerdas berbasis AI untuk Android dengan fitur organisasi terstruktur dan AI Assistant**
|
||||
|
||||
### **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
|
||||
[📖 Dokumentasi Lengkap](./docs/Laporan%20Dokumentasi%20Aplikasi%20-%20Kelompok%201.pdf) | [🧪 Test Report](./TEST_SUMMARY_REPORT.md) | [📋 Changelog](./CHANGELOG.md)
|
||||
|
||||
### **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**
|
||||
## 👥 Tim Pengembang
|
||||
|
||||
### **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
|
||||
**Kelompok 1 - Kelas F5A5**
|
||||
|
||||
### **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
|
||||
| Nama | NPM |
|
||||
|------|-----|
|
||||
| Dendi Yogia Pratama | 202310715051 |
|
||||
| Raihan Ariq Muzakki | 202310715297 |
|
||||
| Fazri Abdurahman | 202310715082 |
|
||||
|
||||
### **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
|
||||
**Dosen Pengampu:** Arif Rifai Dwiyanto, ST., MTI
|
||||
**Mata Kuliah:** Pemrograman Perangkat Bergerak
|
||||
**Institusi:** Universitas Bhayangkara Jakarta Raya
|
||||
|
||||
---
|
||||
|
||||
# **Version 1.1.0 – AI Helper Screen Enhancement & UI Refinement**
|
||||
## 📌 Informasi Proyek
|
||||
|
||||
## **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
|
||||
- **Nama Aplikasi:** NotesAI
|
||||
- **Repository:** [NotesAI](https://git.lab.ubharajaya.ac.id/202310715297-RAIHAN-ARIQ-MUZAKKI/NotesAI.git)
|
||||
- **Platform:** Android (Minimum API 24 / Android 7.0)
|
||||
- **Bahasa:** Kotlin 100%
|
||||
- **UI Framework:** Jetpack Compose + Material 3
|
||||
|
||||
---
|
||||
|
||||
## **Sprint 4: Rich Text Editor Core Features & AI Chat History UI/UX Improvements**
|
||||
## 🎯 Tujuan dan Sasaran Aplikasi
|
||||
|
||||
### **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
|
||||
### Masalah yang Dipecahkan
|
||||
1. **Catatan tidak terorganisir** - Catatan bercampur tanpa struktur yang jelas
|
||||
2. **Sulit mencari informasi** - Kehilangan waktu mencari catatan penting
|
||||
3. **Kurang interaktif** - Tidak ada bantuan untuk merangkum atau menganalisis catatan
|
||||
4. **Risiko kehilangan data** - Catatan terhapus permanen tanpa backup
|
||||
|
||||
### **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
|
||||
### Target Pengguna
|
||||
- 🎓 **Mahasiswa** (18-25 tahun) - Catatan kuliah, tugas, ringkasan dokumen
|
||||
- 💼 **Profesional** (22-40 tahun) - Meeting notes, to-do lists, catatan kerja
|
||||
- 👤 **Pengguna Umum** (18-40 tahun) - Catatan pribadi, jurnal, daftar belanja
|
||||
|
||||
### **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
|
||||
### Keunggulan NotesAI
|
||||
✅ **Organisasi Terstruktur** - Sistem kategori dengan visual gradien warna
|
||||
✅ **AI Assistant** - Powered by Gemini 2.5 Flash untuk respons kontekstual
|
||||
✅ **Rich Text Editor** - WYSIWYG editor dengan drag-and-drop toolbar
|
||||
✅ **Smart Search** - Pencarian realtime dengan filter kategori
|
||||
✅ **Data Safety** - Soft delete dengan trash & restore functionality
|
||||
✅ **Document Parser** - Upload PDF/TXT/DOCX dengan auto-summary
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Fitur Utama (Core Features)
|
||||
1. **Note Management System** ⭐ (PRIMARY)
|
||||
## ✨ Fitur Utama
|
||||
|
||||
* 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
|
||||
### 1️⃣ Note Management System
|
||||
- ✏️ **CRUD Operations** - Create, Read, Update, Delete catatan
|
||||
- 📁 **Category Organization** - Pengelompokan visual dengan gradien warna
|
||||
- 📌 **Pin Priority** - Pin notes/kategori untuk akses cepat
|
||||
- 🗄️ **Archive & Trash** - Soft delete dengan kemampuan restore
|
||||
- 🎨 **Rich Text Editor** - Bold, italic, underline, heading, bullet list
|
||||
- 🔍 **Smart Search** - Realtime search dengan case-insensitive
|
||||
|
||||
2. **AI Assistant** 🤖 (PRIMARY)
|
||||
### 2️⃣ AI Assistant
|
||||
- 🤖 **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
|
||||
|
||||
* 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
|
||||
### 3️⃣ Data Management
|
||||
- 💾 **Local Storage** - DataStore Preferences untuk data persistence
|
||||
- 🔄 **Autosave** - Lifecycle-aware autosave dengan debounce 500ms
|
||||
- 🌙 **Theme Preference** - Dark/Light mode support
|
||||
- 📊 **Reactive Data** - Flow-based reactive data loading
|
||||
- ⚡ **Fast Performance** - Optimized untuk pengalaman smooth
|
||||
|
||||
---
|
||||
|
||||
## **Features for Sprint 3 v1.1.0**
|
||||
## 📊 Riset dan Analisis
|
||||
|
||||
* History Chat AI berdasarkan Catatan yang ada didalam kategori dalam bentuk Drawer Menu di AI Helper (ok)
|
||||
* Mengganti Preview Deskripsi NoteCard dan NoteDialog (ok)
|
||||
* Dark/Light theme toggle (ok)
|
||||
* Markdown Parser (ok)
|
||||
### Analisis Pasar
|
||||
Berdasarkan riset pasar 2025:
|
||||
- **70% responden** percaya AI meningkatkan produktivitas kerja *(Eurobarometer, Feb 2025)*
|
||||
- **Pasar note-taking apps** menunjukkan pertumbuhan dengan tren integrasi AI
|
||||
- **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
|
||||
|
||||
---
|
||||
|
||||
## **Features for Sprint 4 v1.1.0**
|
||||
* Penyesuaian UI/UX History Chat AI (ok)
|
||||
* Rich text editor (ok - Harus Pengembangan Lanjutan)
|
||||
## 🎨 Desain UI/UX
|
||||
|
||||
### Design System
|
||||
- **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)
|
||||
|
||||
---
|
||||
|
||||
## **Features for Sprint 5 v1.1.0**
|
||||
* Fungsi AI (Upload File) (ok)
|
||||
* Fitur Sematkan Category, otomatis paling atas (ok)
|
||||
## 🛠️ Teknologi dan Alat
|
||||
|
||||
### Tech Stack
|
||||
|
||||
#### 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,18 +8,11 @@
|
||||
**Total Unit Tests:** 59
|
||||
**Status:** ✅ ALL PASSED
|
||||
|
||||
---
|
||||
|
||||
## Test Cases Summary
|
||||
|
||||
| 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) |
|
||||
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).
|
||||
Unit testing adalah pengujian otomatis terhadap unit terkecil dari kode
|
||||
(functions, methods) untuk memvalidasi logic internal aplikasi.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -247,21 +247,24 @@ fun NotesApp() {
|
||||
if (!showFullScreenNote && currentScreen != "ai") {
|
||||
ModernTopBar(
|
||||
title = when(currentScreen) {
|
||||
"main" -> if (selectedCategory != null) selectedCategory!!.name else "AI Notes"
|
||||
"main" -> if (selectedCategory != null) selectedCategory!!.name else "NotesAI"
|
||||
"starred" -> "Berbintang"
|
||||
"archive" -> "Arsip"
|
||||
"trash" -> "Sampah"
|
||||
else -> "AI Notes"
|
||||
else -> "NotesAI"
|
||||
},
|
||||
showBackButton = (selectedCategory != null && currentScreen == "main"),
|
||||
onBackClick = {
|
||||
selectedCategory = null
|
||||
},
|
||||
onMenuClick = { drawerState = !drawerState },
|
||||
onSearchClick = { showSearch = !showSearch },
|
||||
onSearchClick = {
|
||||
showSearch = !showSearch
|
||||
if (!showSearch) searchQuery = "" // Reset search saat close
|
||||
},
|
||||
searchQuery = searchQuery,
|
||||
onSearchQueryChange = { searchQuery = it },
|
||||
showSearch = showSearch && currentScreen == "main"
|
||||
showSearch = showSearch // AKTIFKAN UNTUK SEMUA SCREEN
|
||||
)
|
||||
}
|
||||
},
|
||||
@ -426,6 +429,7 @@ fun NotesApp() {
|
||||
"trash" -> TrashScreen(
|
||||
notes = notes.filter { it.isDeleted },
|
||||
categories = categories,
|
||||
searchQuery = searchQuery, // TAMBAHKAN INI
|
||||
onRestoreNote = { note ->
|
||||
notes = notes.map {
|
||||
if (it.id == note.id) it.copy(isDeleted = false, isArchived = false)
|
||||
@ -454,6 +458,7 @@ fun NotesApp() {
|
||||
"starred" -> StarredNotesScreen(
|
||||
notes = notes,
|
||||
categories = categories.filter { !it.isDeleted },
|
||||
searchQuery = searchQuery, // TAMBAHKAN INI
|
||||
onNoteClick = { note ->
|
||||
fullScreenNote = note
|
||||
showFullScreenNote = true
|
||||
@ -469,6 +474,7 @@ fun NotesApp() {
|
||||
"archive" -> ArchiveScreen(
|
||||
notes = notes.filter { it.isArchived && !it.isDeleted },
|
||||
categories = categories.filter { !it.isDeleted },
|
||||
searchQuery = searchQuery,
|
||||
onRestore = { note ->
|
||||
notes = notes.map {
|
||||
if (it.id == note.id) it.copy(isArchived = false)
|
||||
@ -566,8 +572,8 @@ fun NotesApp() {
|
||||
currentScreen = screen
|
||||
selectedCategory = null
|
||||
drawerState = false
|
||||
showSearch = false
|
||||
searchQuery = ""
|
||||
showSearch = false // TUTUP SEARCH
|
||||
searchQuery = "" // RESET SEARCH QUERY
|
||||
},
|
||||
onThemeToggle = {
|
||||
isDarkTheme = !isDarkTheme
|
||||
|
||||
@ -4,27 +4,13 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Archive
|
||||
import androidx.compose.material.icons.filled.Clear
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.data.model.Note
|
||||
import com.example.notesai.data.model.Category
|
||||
@ -35,12 +21,11 @@ import com.example.notesai.presentation.screens.archive.components.ArchiveNoteCa
|
||||
fun ArchiveScreen(
|
||||
notes: List<Note>,
|
||||
categories: List<Category>,
|
||||
searchQuery: String = "", // Tambahkan parameter ini
|
||||
onRestore: (Note) -> Unit,
|
||||
onDelete: (Note) -> Unit
|
||||
) {
|
||||
var searchQuery by remember { mutableStateOf("") }
|
||||
|
||||
// Filter berdasarkan search query
|
||||
// Filter berdasarkan search query dari ModernTopBar
|
||||
val filteredNotes = if (searchQuery.isBlank()) {
|
||||
notes
|
||||
} else {
|
||||
@ -53,50 +38,6 @@ fun ArchiveScreen(
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
// Search Bar
|
||||
OutlinedTextField(
|
||||
value = searchQuery,
|
||||
onValueChange = { searchQuery = it },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
placeholder = {
|
||||
Text(
|
||||
"Cari catatan arsip...",
|
||||
color = Color(0xFF64748B)
|
||||
)
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Search,
|
||||
contentDescription = null,
|
||||
tint = Color(0xFF64748B)
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (searchQuery.isNotEmpty()) {
|
||||
IconButton(onClick = { searchQuery = "" }) {
|
||||
Icon(
|
||||
Icons.Default.Clear,
|
||||
contentDescription = "Clear",
|
||||
tint = Color(0xFF64748B)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedContainerColor = Color(0xFF1E293B),
|
||||
unfocusedContainerColor = Color(0xFF1E293B),
|
||||
focusedBorderColor = Color(0xFF6366F1),
|
||||
unfocusedBorderColor = Color(0xFF334155),
|
||||
focusedTextColor = Color.White,
|
||||
unfocusedTextColor = Color.White,
|
||||
cursorColor = Color(0xFF6366F1)
|
||||
),
|
||||
singleLine = true
|
||||
)
|
||||
|
||||
// Content
|
||||
if (filteredNotes.isEmpty()) {
|
||||
if (searchQuery.isNotEmpty()) {
|
||||
@ -117,6 +58,7 @@ fun ArchiveScreen(
|
||||
contentPadding = PaddingValues(
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
top = 8.dp,
|
||||
bottom = 100.dp
|
||||
),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
|
||||
@ -43,11 +43,25 @@ fun MainScreen(
|
||||
)
|
||||
} else {
|
||||
// Filter kategori berdasarkan searchQuery
|
||||
val filteredCategories = if (searchQuery.isEmpty()) {
|
||||
val filteredCategories = if (searchQuery.isBlank()) {
|
||||
categories
|
||||
} else {
|
||||
categories.filter {
|
||||
it.name.contains(searchQuery, ignoreCase = true)
|
||||
categories.filter { category ->
|
||||
// 1. Cek nama kategori cocok
|
||||
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,32 +3,15 @@ package com.example.notesai.presentation.screens.starred
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Clear
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.Star
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.presentation.components.EmptyState
|
||||
import com.example.notesai.presentation.screens.starred.components.StarredNoteCard
|
||||
@ -40,16 +23,15 @@ import com.example.notesai.data.model.Category
|
||||
fun StarredNotesScreen(
|
||||
notes: List<Note>,
|
||||
categories: List<Category>,
|
||||
searchQuery: String = "", // Tambahkan parameter ini
|
||||
onNoteClick: (Note) -> Unit,
|
||||
onUnpin: (Note) -> Unit
|
||||
) {
|
||||
var searchQuery by remember { mutableStateOf("") }
|
||||
|
||||
val starredNotes = notes
|
||||
.filter { it.isPinned && !it.isArchived && !it.isDeleted }
|
||||
.sortedByDescending { it.timestamp }
|
||||
|
||||
// Filter berdasarkan search query
|
||||
// Filter berdasarkan search query dari ModernTopBar
|
||||
val filteredNotes = if (searchQuery.isBlank()) {
|
||||
starredNotes
|
||||
} else {
|
||||
@ -61,50 +43,6 @@ fun StarredNotesScreen(
|
||||
}
|
||||
|
||||
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
|
||||
if (filteredNotes.isEmpty()) {
|
||||
if (searchQuery.isNotEmpty()) {
|
||||
@ -125,6 +63,7 @@ fun StarredNotesScreen(
|
||||
contentPadding = PaddingValues(
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
top = 8.dp,
|
||||
bottom = 100.dp
|
||||
),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
|
||||
@ -4,26 +4,15 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Clear
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
@ -38,18 +27,17 @@ import com.example.notesai.data.model.Category
|
||||
fun TrashScreen(
|
||||
notes: List<Note>,
|
||||
categories: List<Category>,
|
||||
searchQuery: String = "", // Tambahkan parameter ini
|
||||
onRestoreNote: (Note) -> Unit,
|
||||
onDeleteNotePermanent: (Note) -> Unit,
|
||||
onRestoreCategory: (Category) -> Unit,
|
||||
onDeleteCategoryPermanent: (Category) -> Unit
|
||||
) {
|
||||
var searchQuery by remember { mutableStateOf("") }
|
||||
|
||||
// Filter kategori dan note yang dihapus
|
||||
val deletedCategories = categories.filter { it.isDeleted }
|
||||
val deletedNotes = notes.filter { it.isDeleted }
|
||||
|
||||
// Filter berdasarkan search query
|
||||
// Filter berdasarkan search query dari ModernTopBar
|
||||
val filteredCategories = if (searchQuery.isBlank()) {
|
||||
deletedCategories
|
||||
} else {
|
||||
@ -70,50 +58,6 @@ fun TrashScreen(
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
// Search Bar
|
||||
OutlinedTextField(
|
||||
value = searchQuery,
|
||||
onValueChange = { searchQuery = it },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
placeholder = {
|
||||
Text(
|
||||
"Cari di sampah...",
|
||||
color = Color(0xFF64748B)
|
||||
)
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Search,
|
||||
contentDescription = null,
|
||||
tint = Color(0xFF64748B)
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (searchQuery.isNotEmpty()) {
|
||||
IconButton(onClick = { searchQuery = "" }) {
|
||||
Icon(
|
||||
Icons.Default.Clear,
|
||||
contentDescription = "Clear",
|
||||
tint = Color(0xFF64748B)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedContainerColor = Color(0xFF1E293B),
|
||||
unfocusedContainerColor = Color(0xFF1E293B),
|
||||
focusedBorderColor = Color(0xFF6366F1),
|
||||
unfocusedBorderColor = Color(0xFF334155),
|
||||
focusedTextColor = Color.White,
|
||||
unfocusedTextColor = Color.White,
|
||||
cursorColor = Color(0xFF6366F1)
|
||||
),
|
||||
singleLine = true
|
||||
)
|
||||
|
||||
// Content
|
||||
if (filteredCategories.isEmpty() && filteredNotes.isEmpty()) {
|
||||
if (searchQuery.isNotEmpty()) {
|
||||
@ -134,6 +78,7 @@ fun TrashScreen(
|
||||
contentPadding = PaddingValues(
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
top = 8.dp,
|
||||
bottom = 100.dp
|
||||
),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">AI Notes</string>
|
||||
<string name="app_name">NotesAI</string>
|
||||
</resources>
|
||||
BIN
docs/Laporan Dokumentasi Aplikasi - Kelompok 1.pdf
Normal file
BIN
docs/Laporan Dokumentasi Aplikasi - Kelompok 1.pdf
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user