diff --git a/app/src/main/java/com/example/notesai/presentation/dialogs/CategoryDialog.kt b/app/src/main/java/com/example/notesai/presentation/dialogs/CategoryDialog.kt index 4b213a0..019b335 100644 --- a/app/src/main/java/com/example/notesai/presentation/dialogs/CategoryDialog.kt +++ b/app/src/main/java/com/example/notesai/presentation/dialogs/CategoryDialog.kt @@ -89,11 +89,11 @@ fun CategoryDialog( Spacer(modifier = Modifier.height(8.dp)) - // Color Grid + // Color Grid - 2 rows of 4 colors Constants.CategoryColors.chunked(4).forEach { row -> Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp) + horizontalArrangement = Arrangement.spacedBy(12.dp) ) { row.forEachIndexed { _, gradient -> val globalIndex = Constants.CategoryColors.indexOf(gradient) @@ -135,13 +135,13 @@ fun CategoryDialog( Icons.Default.Check, contentDescription = "Selected", tint = Color.White, - modifier = Modifier.size(24.dp) + modifier = Modifier.size(28.dp) ) } } } } - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.height(12.dp)) } } }, diff --git a/app/src/main/java/com/example/notesai/presentation/screens/ai/AIHelperScreen.kt b/app/src/main/java/com/example/notesai/presentation/screens/ai/AIHelperScreen.kt index 3ea5221..7ed119a 100644 --- a/app/src/main/java/com/example/notesai/presentation/screens/ai/AIHelperScreen.kt +++ b/app/src/main/java/com/example/notesai/presentation/screens/ai/AIHelperScreen.kt @@ -64,7 +64,7 @@ fun AIHelperScreen( var showHistoryDrawer by remember { mutableStateOf(false) } var currentChatId by remember { mutableStateOf(null) } - // NEW: File Upload States + // File Upload States var uploadedFile by remember { mutableStateOf(null) } var isGeneratingSummary by remember { mutableStateOf(false) } @@ -145,19 +145,21 @@ fun AIHelperScreen( .fillMaxSize() .background(AppColors.Background) ) { - // Top Bar with History Button & Stats - Surface( - color = AppColors.Surface, - shadowElevation = 2.dp + // UPDATED: Floating Top Bar + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) + Surface( + color = AppColors.SurfaceElevated, + shape = RoundedCornerShape(Constants.Radius.ExtraLarge.dp), + shadowElevation = Constants.Elevation.Large.dp ) { - // Top Row - Menu & New Chat Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 8.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { @@ -234,41 +236,9 @@ fun AIHelperScreen( } } } - - Spacer(modifier = Modifier.height(12.dp)) - - // Stats - Compact - val filteredNotes = if (selectedCategory != null) { - notes.filter { it.categoryId == selectedCategory!!.id && !it.isArchived } - } else { - notes.filter { !it.isArchived } - } - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly - ) { - CompactStatItem( - icon = Icons.Default.Description, - value = filteredNotes.size.toString(), - label = "Catatan" - ) - CompactStatItem( - icon = Icons.Default.Star, - value = filteredNotes.count { it.isPinned }.toString(), - label = "Dipasang" - ) - CompactStatItem( - icon = Icons.Default.Folder, - value = categories.size.toString(), - label = "Kategori" - ) - } } } - HorizontalDivider(color = AppColors.Divider) - // Chat Area Box( modifier = Modifier @@ -276,18 +246,20 @@ fun AIHelperScreen( .fillMaxWidth() ) { if (chatMessages.isEmpty()) { - // Welcome State + // Welcome State - Optimized Layout Column( modifier = Modifier .fillMaxSize() - .padding(32.dp) + .padding(horizontal = 24.dp, vertical = 16.dp) .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center + verticalArrangement = Arrangement.spacedBy(16.dp) ) { + Spacer(modifier = Modifier.weight(0.5f)) + Box( modifier = Modifier - .size(80.dp) + .size(64.dp) .background( color = AppColors.Primary.copy(alpha = 0.1f), shape = CircleShape @@ -297,50 +269,49 @@ fun AIHelperScreen( Icon( Icons.Default.AutoAwesome, contentDescription = null, - modifier = Modifier.size(40.dp), + modifier = Modifier.size(32.dp), tint = AppColors.Primary ) } - Spacer(modifier = Modifier.height(24.dp)) - Text( "AI Assistant", style = MaterialTheme.typography.headlineMedium, color = AppColors.OnBackground, - fontWeight = FontWeight.Bold + fontWeight = FontWeight.Bold, + fontSize = 24.sp + ) + + Text( + "Tanyakan apa saja tentang catatan Anda", + style = MaterialTheme.typography.bodyMedium, + color = AppColors.OnSurfaceVariant, + textAlign = TextAlign.Center, + fontSize = 14.sp ) Spacer(modifier = Modifier.height(8.dp)) - Text( - "Tanyakan apa saja tentang catatan Anda", - style = MaterialTheme.typography.bodyLarge, - color = AppColors.OnSurfaceVariant, - textAlign = TextAlign.Center - ) - - Spacer(modifier = Modifier.height(32.dp)) - - // Suggestion Chips + // Suggestion Chips - Lebih besar Column( - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier.fillMaxWidth(0.85f) + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(10.dp), + modifier = Modifier.fillMaxWidth() ) { Text( "Contoh pertanyaan:", style = MaterialTheme.typography.labelMedium, - color = AppColors.OnSurfaceTertiary + color = AppColors.OnSurfaceTertiary, + fontSize = 13.sp ) SuggestionChip("Analisis catatan saya") { prompt = it } SuggestionChip("Buat ringkasan") { prompt = it } SuggestionChip("Berikan saran organisasi") { prompt = it } } - Spacer(modifier = Modifier.height(24.dp)) + Spacer(modifier = Modifier.height(8.dp)) - // NEW: File Upload Button + // File Upload Button - PENTING: Jangan dihapus! FileUploadButton( onFileSelected = { fileResult -> uploadedFile = fileResult @@ -401,14 +372,16 @@ fun AIHelperScreen( }, modifier = Modifier.fillMaxWidth() ) + + Spacer(modifier = Modifier.weight(0.5f)) } } else { - // Chat Messages + // Chat Messages - UPDATED: Bottom padding dari 100dp ke 120dp Column( modifier = Modifier .fillMaxSize() .verticalScroll(scrollState) - .padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 100.dp) + .padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 120.dp) ) { chatMessages.forEach { message -> ChatBubble( @@ -427,7 +400,7 @@ fun AIHelperScreen( Spacer(modifier = Modifier.height(12.dp)) } - // Loading Indicator (untuk chat biasa DAN file summary) + // Loading Indicator if (isLoading || isGeneratingSummary) { Row( modifier = Modifier @@ -489,7 +462,7 @@ fun AIHelperScreen( } } - // Input Area - Minimalist + // Input Area Surface( color = AppColors.Surface, shadowElevation = 8.dp, @@ -501,7 +474,7 @@ fun AIHelperScreen( .padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - // NEW: Upload File Button (di atas input text) + // Upload File Button (di atas input text) if (chatMessages.isNotEmpty() && !isGeneratingSummary && !isLoading) { FileUploadButton( onFileSelected = { fileResult -> @@ -533,7 +506,6 @@ fun AIHelperScreen( isUser = true ) - // Scroll to show loading delay(100) scrollState.animateScrollTo(scrollState.maxValue) diff --git a/app/src/main/java/com/example/notesai/presentation/screens/ai/components/CompactStatItem.kt b/app/src/main/java/com/example/notesai/presentation/screens/ai/components/CompactStatItem.kt deleted file mode 100644 index 9d4b67d..0000000 --- a/app/src/main/java/com/example/notesai/presentation/screens/ai/components/CompactStatItem.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.example.notesai.presentation.screens.ai.components - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.example.notesai.util.AppColors -import com.example.notesai.util.Constants - -@Composable -fun CompactStatItem( - icon: androidx.compose.ui.graphics.vector.ImageVector, - value: String, - label: String -) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(6.dp), - modifier = Modifier - .background( - color = AppColors.SurfaceVariant, - shape = RoundedCornerShape(8.dp) - ) - .padding(horizontal = 12.dp, vertical = 8.dp) - ) { - Icon( - icon, - contentDescription = null, - tint = AppColors.Primary, - modifier = Modifier.size(16.dp) - ) - Column { - Text( - value, - style = MaterialTheme.typography.titleMedium, - color = AppColors.OnBackground, - fontWeight = FontWeight.Bold, - fontSize = 16.sp - ) - Text( - label, - style = MaterialTheme.typography.bodySmall, - color = AppColors.OnSurfaceTertiary, - fontSize = 11.sp - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notesai/presentation/screens/ai/components/StatItem.kt b/app/src/main/java/com/example/notesai/presentation/screens/ai/components/StatItem.kt deleted file mode 100644 index 9966133..0000000 --- a/app/src/main/java/com/example/notesai/presentation/screens/ai/components/StatItem.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.example.notesai.presentation.screens.ai.components - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp - -@Composable -fun StatItem(label: String, value: String, color: Color) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.padding(8.dp) - ) { - Text( - value, - style = MaterialTheme.typography.headlineMedium, - color = color, - fontWeight = FontWeight.Bold - ) - Spacer(modifier = Modifier.height(4.dp)) - Text( - label, - style = MaterialTheme.typography.bodySmall, - color = Color(0xFF94A3B8) - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notesai/presentation/screens/main/components/CategoryCard.kt b/app/src/main/java/com/example/notesai/presentation/screens/main/components/CategoryCard.kt index cd4983c..3747d9d 100644 --- a/app/src/main/java/com/example/notesai/presentation/screens/main/components/CategoryCard.kt +++ b/app/src/main/java/com/example/notesai/presentation/screens/main/components/CategoryCard.kt @@ -32,7 +32,7 @@ fun CategoryCard( onClick: () -> Unit, onDelete: () -> Unit = {}, onEdit: (String, Long, Long) -> Unit = { _, _, _ -> }, - onPin: () -> Unit = {} // NEW: Pin callback + onPin: () -> Unit = {} ) { var showDeleteConfirm by remember { mutableStateOf(false) } var showEditDialog by remember { mutableStateOf(false) } @@ -160,7 +160,7 @@ fun CategoryCard( ) } - // NEW: Pin Indicator & Menu Button + // Pin Indicator & Menu Button Row( horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically @@ -198,7 +198,7 @@ fun CategoryCard( onDismissRequest = { showMenu = false }, modifier = Modifier.background(AppColors.SurfaceElevated) ) { - // NEW: Pin/Unpin Menu Item + // Pin/Unpin Menu Item DropdownMenuItem( text = { Row( @@ -382,10 +382,11 @@ fun EditCategoryDialog( Spacer(modifier = Modifier.height(12.dp)) + // 8 colors in 2 rows Constants.CategoryColors.chunked(4).forEach { row -> Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp) + horizontalArrangement = Arrangement.spacedBy(12.dp) ) { row.forEachIndexed { _, gradient -> val globalIndex = Constants.CategoryColors.indexOf(gradient) @@ -416,13 +417,13 @@ fun EditCategoryDialog( Icons.Default.Check, contentDescription = null, tint = Color.White, - modifier = Modifier.size(24.dp) + modifier = Modifier.size(28.dp) ) } } } } - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.height(12.dp)) } } }, diff --git a/app/src/main/java/com/example/notesai/presentation/screens/note/EditableFullScreenNoteView.kt b/app/src/main/java/com/example/notesai/presentation/screens/note/EditableFullScreenNoteView.kt index 298dacc..8eb2a6d 100644 --- a/app/src/main/java/com/example/notesai/presentation/screens/note/EditableFullScreenNoteView.kt +++ b/app/src/main/java/com/example/notesai/presentation/screens/note/EditableFullScreenNoteView.kt @@ -20,7 +20,7 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.SolidColor // ✅ ADD +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.* import androidx.compose.ui.text.AnnotatedString @@ -57,7 +57,6 @@ fun EditableFullScreenNoteView( ) } - val focusRequester = remember { FocusRequester() } val bringIntoViewRequester = remember { BringIntoViewRequester() } val scrollState = rememberScrollState() @@ -78,7 +77,7 @@ fun EditableFullScreenNoteView( } } - // 🔥 AUTO SAVE SAAT APP BACKGROUND / KELUAR + // AUTO SAVE SAAT APP BACKGROUND / KELUAR val lifecycleOwner = LocalLifecycleOwner.current DisposableEffect(lifecycleOwner) { @@ -95,7 +94,6 @@ fun EditableFullScreenNoteView( } } - val dateFormat = remember { SimpleDateFormat("dd MMMM yyyy, HH:mm", Locale("id", "ID")) } @@ -177,21 +175,32 @@ fun EditableFullScreenNoteView( ) ) { - TextField( + // FIXED: BasicTextField untuk judul agar sejajar dengan konten + BasicTextField( value = title, onValueChange = { title = it }, textStyle = MaterialTheme.typography.headlineLarge.copy( fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onBackground ), - placeholder = { Text("Judul") }, - modifier = Modifier.fillMaxWidth(), - colors = TextFieldDefaults.colors( - focusedContainerColor = Color.Transparent, - unfocusedContainerColor = Color.Transparent, - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent - ) + cursorBrush = SolidColor(MaterialTheme.colorScheme.primary), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + decorationBox = { innerTextField -> + Box { + if (title.isEmpty()) { + Text( + "Judul", + style = MaterialTheme.typography.headlineLarge.copy( + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.4f) + ) + ) + } + innerTextField() + } + } ) Spacer(Modifier.height(12.dp)) @@ -204,7 +213,7 @@ fun EditableFullScreenNoteView( HorizontalDivider(Modifier.padding(vertical = 20.dp)) - // ✅ FIX UTAMA: set cursorBrush agar insertion cursor muncul + // Konten editor BasicTextField( value = editorState.value, onValueChange = { @@ -213,7 +222,7 @@ fun EditableFullScreenNoteView( bringIntoViewRequester.bringIntoView() } }, - cursorBrush = SolidColor(Color(0xFFA855F7)), // ✅ ADD THIS + cursorBrush = SolidColor(Color(0xFFA855F7)), textStyle = MaterialTheme.typography.bodyLarge.copy( color = MaterialTheme.colorScheme.onBackground, lineHeight = 28.sp @@ -285,9 +294,9 @@ fun EditableFullScreenNoteView( editorState.toggleItalic() }, onUnderline = { ensureFocus(); editorState.toggleUnderline() }, - onHeading = { ensureFocus(); editorState.setHeading(1) }, // sementara H1 + onHeading = { ensureFocus(); editorState.setHeading(1) }, onBullet = { ensureFocus(); editorState.toggleBulletList() } ) } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notesai/util/Constants.kt b/app/src/main/java/com/example/notesai/util/Constants.kt index 8a4991f..94d67c2 100644 --- a/app/src/main/java/com/example/notesai/util/Constants.kt +++ b/app/src/main/java/com/example/notesai/util/Constants.kt @@ -112,54 +112,30 @@ object Constants { // Reference to AppColors for compatibility val AppColors = com.example.notesai.util.AppColors - // Category gradient colors + // Category gradient colors - 8 pilihan warna val CategoryColors = listOf( - // Purple gradients + // Purple gradient 0xFF6750A4L to 0xFF7E57C2L, + + // Pink gradient 0xFF9C27B0L to 0xFFE91E63L, - // Blue gradients + // Blue gradient 0xFF2196F3L to 0xFF03A9F4L, - 0xFF1976D2L to 0xFF4FC3F7L, - // Green gradients + // Green gradient 0xFF4CAF50L to 0xFF8BC34AL, - 0xFF009688L to 0xFF00BCD4L, - // Orange gradients + // Orange gradient 0xFFFF9800L to 0xFFFFB74DL, - 0xFFFF5722L to 0xFFFF7043L, - // Red gradients + // Red gradient 0xFFF44336L to 0xFFE91E63L, - 0xFFD32F2FL to 0xFFFF5252L, - // Teal gradients + // Teal gradient 0xFF009688L to 0xFF26A69AL, - 0xFF00897BL to 0xFF4DB6ACL, - // Indigo gradients - 0xFF3F51B5L to 0xFF5C6BC0L, - 0xFF303F9FL to 0xFF7986CBL, - - // Amber gradients - 0xFFFFC107L to 0xFFFFD54FL, - 0xFFFFB300L to 0xFFFFCA28L, - - // Pink gradients - 0xFFE91E63L to 0xFFF06292L, - 0xFFC2185BL to 0xFFEC407AL, - - // Cyan gradients - 0xFF00BCD4L to 0xFF26C6DAL, - 0xFF0097A7L to 0xFF00ACC1L, - - // Deep Purple gradients - 0xFF673AB7L to 0xFF9575CDL, - 0xFF512DA8L to 0xFF7E57C2L, - - // Lime gradients - 0xFFCDDC39L to 0xFFD4E157L, - 0xFFAFB42BL to 0xFFC0CA33L + // Indigo gradient + 0xFF3F51B5L to 0xFF5C6BC0L ) } \ No newline at end of file