From aeeb830143a10e36a70d170cd03b2b4af87e051f Mon Sep 17 00:00:00 2001 From: Raihan Ariq <202310715297@mhs.ubharajaya.ac.id> Date: Wed, 24 Dec 2025 12:29:46 +0700 Subject: [PATCH] Penyesuaian UI/UX pada Halaman Utama dan AI Helper Screen belum selesai --- .../presentation/components/DrawerMenu.kt | 4 +- .../presentation/screens/ai/AIHelperScreen.kt | 136 +++++++++++++----- 2 files changed, 101 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/example/notesai/presentation/components/DrawerMenu.kt b/app/src/main/java/com/example/notesai/presentation/components/DrawerMenu.kt index ae9ba01..58a7acd 100644 --- a/app/src/main/java/com/example/notesai/presentation/components/DrawerMenu.kt +++ b/app/src/main/java/com/example/notesai/presentation/components/DrawerMenu.kt @@ -179,7 +179,7 @@ fun DrawerMenu( verticalAlignment = Alignment.CenterVertically ) { Text( - "Version 1.0.0", + "Version 1.1.0", style = MaterialTheme.typography.bodySmall, color = AppColors.OnSurfaceTertiary, fontSize = 12.sp @@ -202,7 +202,7 @@ fun DrawerMenu( modifier = Modifier.size(12.dp) ) Text( - "AI", + "Gemini AI", color = AppColors.Primary, fontSize = 11.sp, fontWeight = FontWeight.Bold 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 7ed119a..04a0589 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 @@ -3,6 +3,8 @@ package com.example.notesai.presentation.screens.ai import androidx.compose.animation.* import androidx.compose.animation.core.* import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape @@ -22,6 +24,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.zIndex import com.example.notesai.config.APIKey import com.example.notesai.data.local.DataStoreManager import com.example.notesai.data.model.* @@ -139,7 +142,10 @@ fun AIHelperScreen( isGeneratingSummary = false } - Box(modifier = Modifier.fillMaxSize()) { + Box( + modifier = Modifier.fillMaxSize() + ) { + // MAIN CONTENT - Layer 1 (paling bawah) Column( modifier = Modifier .fillMaxSize() @@ -349,7 +355,8 @@ fun AIHelperScreen( scrollState.animateScrollTo(scrollState.maxValue) // Generate summary dengan Gemini - val response = generativeModel.generateContent(summaryPrompt) + val response = + generativeModel.generateContent(summaryPrompt) val summary = response.text ?: "Gagal membuat ringkasan" // Add AI response @@ -462,7 +469,7 @@ fun AIHelperScreen( } } - // Input Area + // Input Area - Layer 2 (di atas chat, tapi di bawah drawer) Surface( color = AppColors.Surface, shadowElevation = 8.dp, @@ -509,7 +516,8 @@ fun AIHelperScreen( delay(100) scrollState.animateScrollTo(scrollState.maxValue) - val response = generativeModel.generateContent(summaryPrompt) + val response = + generativeModel.generateContent(summaryPrompt) val summary = response.text ?: "Gagal membuat ringkasan" chatMessages = chatMessages + ChatMessage( @@ -599,9 +607,11 @@ fun AIHelperScreen( } } - val fullPrompt = "$notesContext\n\nPertanyaan: $userPrompt\n\nBerikan jawaban dalam bahasa Indonesia yang natural dan membantu." + val fullPrompt = + "$notesContext\n\nPertanyaan: $userPrompt\n\nBerikan jawaban dalam bahasa Indonesia yang natural dan membantu." val result = generativeModel.generateContent(fullPrompt) - val response = result.text ?: "Tidak ada respons dari AI" + val response = + result.text ?: "Tidak ada respons dari AI" chatMessages = chatMessages + ChatMessage( message = response, @@ -611,18 +621,44 @@ fun AIHelperScreen( saveChatHistory() } catch (e: Exception) { errorMessage = when { - e.message?.contains("quota", ignoreCase = true) == true -> + e.message?.contains( + "quota", + ignoreCase = true + ) == true -> "⚠️ Kuota API habis. Silakan coba lagi nanti atau hubungi developer." - e.message?.contains("404", ignoreCase = true) == true || - e.message?.contains("not found", ignoreCase = true) == true -> + + e.message?.contains( + "404", + ignoreCase = true + ) == true || + e.message?.contains( + "not found", + ignoreCase = true + ) == true -> "⚠️ Model AI tidak ditemukan. Silakan hubungi developer." - e.message?.contains("401", ignoreCase = true) == true || - e.message?.contains("API key", ignoreCase = true) == true -> + + e.message?.contains( + "401", + ignoreCase = true + ) == true || + e.message?.contains( + "API key", + ignoreCase = true + ) == true -> "⚠️ API key tidak valid. Silakan hubungi developer." - e.message?.contains("timeout", ignoreCase = true) == true -> + + e.message?.contains( + "timeout", + ignoreCase = true + ) == true -> "⚠️ Koneksi timeout. Periksa koneksi internet Anda." - e.message?.contains("network", ignoreCase = true) == true -> + + e.message?.contains( + "network", + ignoreCase = true + ) == true -> "⚠️ Tidak ada koneksi internet. Silakan periksa koneksi Anda." + else -> "⚠️ Terjadi kesalahan: ${e.message?.take(100) ?: "Unknown error"}" } @@ -647,34 +683,60 @@ fun AIHelperScreen( } } - // Chat History Drawer + // DRAWER - Layer 3 (paling atas, di luar Column) AnimatedVisibility( visible = showHistoryDrawer, - enter = fadeIn() + slideInHorizontally(), - exit = fadeOut() + slideOutHorizontally() + enter = fadeIn() + slideInHorizontally(initialOffsetX = { -it }), + exit = fadeOut() + slideOutHorizontally(targetOffsetX = { -it }), + modifier = Modifier + .fillMaxSize() + .zIndex(10f) // Z-index lebih tinggi dari bottom bar ) { - ChatHistoryDrawer( - chatHistories = chatHistories, - categories = categories, - notes = notes, - selectedCategory = selectedCategory, - onDismiss = { showHistoryDrawer = false }, - onHistoryClick = { loadChatHistory(it) }, - onDeleteHistory = { historyId -> - scope.launch { - dataStoreManager.deleteChatHistory(historyId) - } - }, - onCategorySelected = { category -> - selectedCategory = category - }, - onNewChat = { startNewChat() }, - onEditHistoryTitle = { historyId, newTitle -> - scope.launch { - dataStoreManager.updateChatHistoryTitle(historyId, newTitle) - } + // Backdrop + Drawer + Box( + modifier = Modifier + .fillMaxSize() + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null + ) { showHistoryDrawer = false } + .background(Color.Black.copy(alpha = 0.5f)) + ) { + // Drawer Content + Box( + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth(0.85f) // 85% dari lebar layar + .align(Alignment.CenterStart) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null + ) { /* Prevent backdrop click */ } + ) { + ChatHistoryDrawer( + chatHistories = chatHistories, + categories = categories, + notes = notes, + selectedCategory = selectedCategory, + onDismiss = { showHistoryDrawer = false }, + onHistoryClick = { loadChatHistory(it) }, + onDeleteHistory = { historyId -> + scope.launch { + dataStoreManager.deleteChatHistory(historyId) + } + }, + onCategorySelected = { category -> + selectedCategory = category + }, + onNewChat = { startNewChat() }, + onEditHistoryTitle = { historyId, newTitle -> + scope.launch { + dataStoreManager.updateChatHistoryTitle(historyId, newTitle) + } + } + ) } - ) + } } } } \ No newline at end of file