Apis benerin dong

This commit is contained in:
202310715082 FAZRI ABDURRAHMAN 2025-11-17 14:48:17 +07:00
parent f64bff7933
commit 912c489123
3 changed files with 467 additions and 326 deletions

View File

@ -4,6 +4,14 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-11-14T10:53:18.219362400Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=10DEC90GZE0004R" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState> </SelectionState>
</selectionStates> </selectionStates>
</component> </component>

View File

@ -5,7 +5,7 @@
<list> <list>
<ColumnSorterState> <ColumnSorterState>
<option name="column" value="Name" /> <option name="column" value="Name" />
<option name="order" value="ASCENDING" /> <option name="order" value="DESCENDING" />
</ColumnSorterState> </ColumnSorterState>
</list> </list>
</option> </option>

View File

@ -6,8 +6,9 @@ import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@ -15,16 +16,16 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.filled.* import androidx.compose.material.icons.filled.*
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@ -40,8 +41,6 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// Initialize PDFBox
com.example.notebook.utils.PdfHelper.initialize(this) com.example.notebook.utils.PdfHelper.initialize(this)
setContent { setContent {
@ -50,9 +49,9 @@ class MainActivity : ComponentActivity() {
NotebookTheme(darkTheme = isDarkMode) { NotebookTheme(darkTheme = isDarkMode) {
Surface( Surface(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background color = MaterialTheme.colorScheme.background // [DIUBAH] Menggunakan warna tema
) { ) {
NotebookApp( NotebookBottomSheetApp(
viewModel = viewModel, viewModel = viewModel,
isDarkMode = isDarkMode, isDarkMode = isDarkMode,
onThemeChange = { isDarkMode = it } onThemeChange = { isDarkMode = it }
@ -63,130 +62,26 @@ class MainActivity : ComponentActivity() {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun NotebookApp(viewModel: NotebookViewModel, isDarkMode: Boolean, onThemeChange: (Boolean) -> Unit) { fun NotebookBottomSheetApp(
var selectedTabIndex by remember { mutableIntStateOf(0) } viewModel: NotebookViewModel,
val tabs = listOf("Studio", "Chat", "Sources") isDarkMode: Boolean,
var showGoogleAppsMenu by remember { mutableStateOf(false) } onThemeChange: (Boolean) -> Unit
var showSettingsMenu by remember { mutableStateOf(false) } ) {
var showAccountScreen by remember { mutableStateOf(false) } val notebooks by viewModel.notebooks.collectAsState()
var chatInput by remember { mutableStateOf("") }
var selectedNotebookId by remember { mutableIntStateOf(-1) } var selectedNotebookId by remember { mutableIntStateOf(-1) }
var showCreateDialog by remember { mutableStateOf(false) }
var showAccountScreen by remember { mutableStateOf(false) }
// Log setiap kali selectedNotebookId berubah
LaunchedEffect(selectedNotebookId) {
println("🎯 selectedNotebookId berubah menjadi: $selectedNotebookId")
}
// Kalau ada notebook yang dipilih, tampilkan detail screen
if (selectedNotebookId != -1) { if (selectedNotebookId != -1) {
println("✨ Menampilkan NotebookDetailScreen untuk ID: $selectedNotebookId")
com.example.notebook.ui.screens.NotebookDetailScreen( com.example.notebook.ui.screens.NotebookDetailScreen(
viewModel = viewModel, viewModel = viewModel,
notebookId = selectedNotebookId, notebookId = selectedNotebookId,
onBack = { onBack = { selectedNotebookId = -1 }
println("⬅️ Kembali dari detail screen")
selectedNotebookId = -1
}
) )
return return
} }
if (showAccountScreen) {
AccountScreen(onDismiss = { showAccountScreen = false })
}
Scaffold(
topBar = {
TopAppBar(
title = { Text("NoteBook") },
actions = {
Box {
IconButton(onClick = { showSettingsMenu = true }) {
Icon(Icons.Filled.Settings, contentDescription = "Settings")
}
SettingsMenu(
expanded = showSettingsMenu,
onDismiss = { showSettingsMenu = false },
isDarkMode = isDarkMode,
onThemeChange = onThemeChange
)
}
Box(
modifier = Modifier
.size(32.dp)
.clip(CircleShape)
.background(Color.Magenta)
.clickable { showAccountScreen = true },
contentAlignment = Alignment.Center
) {
Text("M", color = Color.White, fontWeight = FontWeight.Bold)
}
Spacer(modifier = Modifier.width(8.dp))
}
)
},
bottomBar = {
if (selectedTabIndex == 1) {
BottomAppBar {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(horizontal = 8.dp)
) {
OutlinedTextField(
value = chatInput,
onValueChange = { chatInput = it },
placeholder = { Text("Message...") },
modifier = Modifier.weight(1f)
)
IconButton(
onClick = {
if (chatInput.isNotBlank()) {
// TODO: Kirim ke notebook yang aktif
// viewModel.sendUserMessage(notebookId, chatInput)
chatInput = ""
}
}
) {
Icon(Icons.AutoMirrored.Filled.Send, contentDescription = "Send")
}
}
}
}
}
) { innerPadding ->
Column(modifier = Modifier.padding(innerPadding)) {
TabRow(selectedTabIndex = selectedTabIndex) {
tabs.forEachIndexed { index, title ->
Tab(
selected = selectedTabIndex == index,
onClick = { selectedTabIndex = index },
text = { Text(title) }
)
}
}
when (selectedTabIndex) {
0 -> StudioScreen(
viewModel = viewModel,
onNotebookClick = { notebookId ->
println("📱 Navigasi ke notebook ID: $notebookId")
selectedNotebookId = notebookId
}
)
1 -> ChatScreen(viewModel)
2 -> SourcesScreen(viewModel)
}
}
}
}
// === STUDIO SCREEN (UPDATED) ===
@Composable
fun StudioScreen(viewModel: NotebookViewModel, onNotebookClick: (Int) -> Unit) {
val notebooks by viewModel.notebooks.collectAsState()
var showCreateDialog by remember { mutableStateOf(false) }
if (showCreateDialog) { if (showCreateDialog) {
CreateNotebookDialog( CreateNotebookDialog(
onDismiss = { showCreateDialog = false }, onDismiss = { showCreateDialog = false },
@ -197,152 +92,466 @@ fun StudioScreen(viewModel: NotebookViewModel, onNotebookClick: (Int) -> Unit) {
) )
} }
if (showAccountScreen) {
AccountScreen(onDismiss = { showAccountScreen = false })
}
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background) // [DIUBAH] Menggunakan warna tema
) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(Color.White) .shadow(
.padding(16.dp) elevation = 8.dp,
shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp)
)
.clip(RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp))
.background(MaterialTheme.colorScheme.surface) // [DIUBAH] Menggunakan warna tema
) {
NotebookHeader(
isDarkMode = isDarkMode,
onThemeChange = onThemeChange,
onAccountClick = { showAccountScreen = true }
)
Divider(color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f), thickness = 1.dp)
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 16.dp)
.padding(top = 16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) { ) {
Text( Text(
"Notebook terbaru", "Notebook Saya",
style = MaterialTheme.typography.titleLarge, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = Color.Black color = MaterialTheme.colorScheme.onSurface // [DIUBAH]
) )
Text(
"${notebooks.size} notebook tersimpan",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant // [DIUBAH]
)
}
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
LazyColumn( CreateNotebookButton(onClick = { showCreateDialog = true })
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
// Card untuk buat notebook baru
item {
NewNotebookCard(onClick = { showCreateDialog = true })
}
// List notebooks yang sudah ada Spacer(modifier = Modifier.height(20.dp))
items(notebooks) { notebook ->
NotebookCard( if (notebooks.isEmpty()) {
EmptyNotebookMessage()
} else {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(12.dp),
contentPadding = PaddingValues(bottom = 16.dp)
) {
items(notebooks, key = { it.id }) { notebook ->
NotebookCardItem(
notebook = notebook, notebook = notebook,
onClick = { onClick = { selectedNotebookId = notebook.id },
println("🟢 onClick triggered untuk notebook ID: ${notebook.id}") onDelete = { viewModel.deleteNotebook(notebook) }
onNotebookClick(notebook.id)
},
onDelete = {
println("🔴 Delete triggered untuk notebook ID: ${notebook.id}")
viewModel.deleteNotebook(notebook)
}
) )
} }
} }
} }
}
}
}
} }
@Composable @Composable
fun NewNotebookCard(onClick: () -> Unit) { fun NotebookHeader(
Card( isDarkMode: Boolean,
onThemeChange: (Boolean) -> Unit,
onAccountClick: () -> Unit
) {
Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(120.dp) .padding(horizontal = 16.dp, vertical = 12.dp),
.clickable(onClick = onClick), horizontalArrangement = Arrangement.SpaceBetween,
shape = RoundedCornerShape(16.dp), verticalAlignment = Alignment.CenterVertically
colors = CardDefaults.cardColors(containerColor = Color(0xFFF0F4F7))
) { ) {
Column( Row(verticalAlignment = Alignment.CenterVertically) {
Box(
modifier = Modifier
.size(32.dp)
.clip(RoundedCornerShape(8.dp))
.background(
Brush.linearGradient(
listOf(Color(0xFF7C3AED), Color(0xFF9333EA))
)
),
contentAlignment = Alignment.Center
) {
Icon(
Icons.Default.Book,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(20.dp)
)
}
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(
"NoteBook",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onSurface // [DIUBAH]
)
Text(
"Selamat datang kembali!",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant, // [DIUBAH]
fontSize = 11.sp
)
}
}
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
IconButton(onClick = { onThemeChange(!isDarkMode) }) {
Icon(
imageVector = if (isDarkMode) Icons.Default.LightMode else Icons.Default.DarkMode,
contentDescription = "Toggle Theme",
tint = MaterialTheme.colorScheme.onSurfaceVariant // [DIUBAH]
)
}
IconButton(onClick = onAccountClick) {
Icon(
Icons.Default.AccountCircle,
contentDescription = "Account",
tint = Color(0xFF7C3AED),
modifier = Modifier.size(28.dp)
)
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AccountScreen(onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false)) {
Scaffold(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center, topBar = {
TopAppBar(
title = { Text("Akun") },
navigationIcon = {
IconButton(onClick = onDismiss) {
Icon(Icons.Default.Close, contentDescription = "Tutup")
}
}
)
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(32.dp))
Box(
modifier = Modifier
.size(80.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.primary), // [DIUBAH]
contentAlignment = Alignment.Center
) {
Text("A", fontSize = 40.sp, color = MaterialTheme.colorScheme.onPrimary, fontWeight = FontWeight.Bold) // [DIUBAH]
}
Spacer(modifier = Modifier.height(16.dp))
Text("user@google.com", fontWeight = FontWeight.Bold, fontSize = 20.sp, color = MaterialTheme.colorScheme.onSurface)
Spacer(modifier = Modifier.height(8.dp))
Text("Fazri Abdurrahman", fontSize = 16.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(modifier = Modifier.height(24.dp))
// [DIUBAH] Tombol Kelola Akun menjadi OutlinedButton
OutlinedButton(onClick = { /* TODO: Logika Google Sign-In */ }, modifier = Modifier.fillMaxWidth()) {
Text("Kelola Akun Google Anda")
}
Spacer(modifier = Modifier.height(24.dp))
// [BARU] Kartu untuk menambah dan mengelola akun
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainer)
) {
Column {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { /* TODO */ }
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Default.PersonAdd, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(modifier = Modifier.width(16.dp))
Text("Tambah akun lain", color = MaterialTheme.colorScheme.onSurface)
}
Divider(modifier = Modifier.padding(horizontal = 16.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { /* TODO */ }
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Default.ManageAccounts, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(modifier = Modifier.width(16.dp))
Text("Kelola akun di perangkat ini", color = MaterialTheme.colorScheme.onSurface)
}
}
}
Spacer(modifier = Modifier.weight(1f))
Row(
modifier = Modifier.padding(bottom = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
Text("Kebijakan Privasi", fontSize = 12.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
Text("", fontSize = 12.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
Text("Persyaratan Layanan", fontSize = 12.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
}
}
}
}
@Composable
fun CreateNotebookButton(onClick: () -> Unit) {
Button(
onClick = onClick,
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent
),
contentPadding = PaddingValues(0.dp)
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier
.size(40.dp) .fillMaxSize()
.clip(CircleShape) .background(
.background(Color(0xFFE1E3E6)), Brush.horizontalGradient(
listOf(Color(0xFF7C3AED), Color(0xFF9333EA))
)
),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Icon(Icons.Default.Add, contentDescription = "Buat notebook baru", tint = Color.Black) Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Icon(
Icons.Default.Add,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Column(horizontalAlignment = Alignment.Start) {
Text(
"Buat notebook baru",
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 15.sp
)
}
} }
Spacer(modifier = Modifier.height(8.dp))
Text("Buat notebook baru", color = Color.Black)
} }
} }
} }
@Composable @Composable
fun NotebookCard( fun NotebookCardItem(
notebook: com.example.notebook.data.NotebookEntity, notebook: com.example.notebook.data.NotebookEntity,
onClick: () -> Unit, onClick: () -> Unit,
onDelete: () -> Unit onDelete: () -> Unit
) { ) {
val dateFormat = SimpleDateFormat("dd MMM yyyy, HH:mm", Locale.getDefault()) val dateFormat = SimpleDateFormat("dd MMM yyyy, HH:mm", Locale("id", "ID"))
var showMenu by remember { mutableStateOf(false) }
var showDeleteDialog by remember { mutableStateOf(false) }
val iconColors = listOf(
Color(0xFFEC4899), // Pink
Color(0xFF8B5CF6), // Purple
Color(0xFF3B82F6), // Blue
Color(0xFF10B981), // Green
Color(0xFFF59E0B), // Orange
)
val iconColor = remember { iconColors.random() }
if (showDeleteDialog) {
AlertDialog(
onDismissRequest = { showDeleteDialog = false },
icon = { Icon(Icons.Default.Delete, contentDescription = null) },
title = { Text("Hapus Notebook?") },
text = { Text("Notebook \"${notebook.title}\" dan semua isinya akan dihapus permanen.") },
confirmButton = {
Button(
onClick = {
onDelete()
showDeleteDialog = false
},
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFEF4444)
)
) {
Text("Hapus")
}
},
dismissButton = {
TextButton(onClick = { showDeleteDialog = false }) {
Text("Batal")
}
}
)
}
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onClick),
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFFF8F9FA)), colors = CardDefaults.cardColors(
onClick = { containerColor = MaterialTheme.colorScheme.surfaceContainerLowest // [DIUBAH]
println("🔵 Card onClick: ID=${notebook.id}, Title=${notebook.title}") ),
onClick() elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
}
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp), .padding(12.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
// Icon notebook
Box( Box(
modifier = Modifier modifier = Modifier
.size(48.dp) .size(44.dp)
.clip(RoundedCornerShape(8.dp)) .clip(RoundedCornerShape(10.dp))
.background(Color(0xFFE8EAF6)), .background(iconColor),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Icon( Icon(
Icons.Default.Description, Icons.Default.Description,
contentDescription = null, contentDescription = null,
tint = Color(0xFF5C6BC0) tint = Color.White,
modifier = Modifier.size(24.dp)
) )
} }
Spacer(modifier = Modifier.width(12.dp)) Spacer(modifier = Modifier.width(12.dp))
// Info notebook
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
Text( Text(
text = notebook.title, text = notebook.title,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis,
) color = MaterialTheme.colorScheme.onSurface // [DIUBAH]
Spacer(modifier = Modifier.height(4.dp))
Text(
text = if (notebook.description.isNotBlank()) notebook.description
else "Belum ada deskripsi",
style = MaterialTheme.typography.bodySmall,
color = Color.Gray,
maxLines = 1,
overflow = TextOverflow.Ellipsis
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Text( Text(
text = dateFormat.format(Date(notebook.updatedAt)), text = dateFormat.format(Date(notebook.updatedAt)),
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = Color.Gray color = MaterialTheme.colorScheme.onSurfaceVariant, // [DIUBAH]
fontSize = 12.sp
)
if (notebook.description.isNotBlank()) {
Spacer(modifier = Modifier.height(4.dp))
Text(
text = notebook.description,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.outline, // [DIUBAH]
maxLines = 1,
overflow = TextOverflow.Ellipsis,
fontSize = 12.sp
)
}
}
Box {
IconButton(
onClick = { showMenu = true },
modifier = Modifier.size(32.dp)
) {
Icon(
Icons.Default.MoreVert,
contentDescription = "Menu",
tint = MaterialTheme.colorScheme.onSurfaceVariant // [DIUBAH]
) )
} }
// Delete button DropdownMenu(
IconButton(onClick = onDelete) { expanded = showMenu,
onDismissRequest = { showMenu = false }
) {
DropdownMenuItem(
text = { Text("Hapus") },
onClick = {
showMenu = false
showDeleteDialog = true
},
leadingIcon = {
Icon( Icon(
Icons.Default.Delete, Icons.Default.Delete,
contentDescription = "Hapus", contentDescription = null,
tint = Color.Gray tint = Color(0xFFEF4444)
)
}
) )
} }
} }
} }
}
}
@Composable
fun EmptyNotebookMessage() {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 32.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Icon(
Icons.Default.Description,
contentDescription = null,
modifier = Modifier.size(64.dp),
tint = MaterialTheme.colorScheme.surfaceVariant // [DIUBAH]
)
Spacer(modifier = Modifier.height(16.dp))
Text(
"Belum ada notebook",
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant // [DIUBAH]
)
Text(
"Klik tombol di atas untuk membuat notebook baru",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.outline // [DIUBAH]
)
}
} }
@Composable @Composable
@ -355,23 +564,58 @@ fun CreateNotebookDialog(
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text("Buat Notebook Baru") }, icon = {
Box(
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
.background(
Brush.linearGradient(
listOf(Color(0xFF7C3AED), Color(0xFF9333EA))
)
),
contentAlignment = Alignment.Center
) {
Icon(
Icons.Default.Add,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(28.dp)
)
}
},
title = {
Text(
"Buat Notebook Baru",
fontWeight = FontWeight.Bold
)
},
text = { text = {
Column { Column {
OutlinedTextField( OutlinedTextField(
value = title, value = title,
onValueChange = { title = it }, onValueChange = { title = it },
label = { Text("Judul Notebook") }, label = { Text("Judul Notebook") },
placeholder = { Text("Contoh: Catatan Kuliah") },
singleLine = true, singleLine = true,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth(),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Color(0xFF7C3AED),
focusedLabelColor = Color(0xFF7C3AED)
) )
Spacer(modifier = Modifier.height(8.dp)) )
Spacer(modifier = Modifier.height(12.dp))
OutlinedTextField( OutlinedTextField(
value = description, value = description,
onValueChange = { description = it }, onValueChange = { description = it },
label = { Text("Deskripsi (opsional)") }, label = { Text("Deskripsi (opsional)") },
placeholder = { Text("Tambahkan deskripsi singkat...") },
maxLines = 3, maxLines = 3,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth(),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Color(0xFF7C3AED),
focusedLabelColor = Color(0xFF7C3AED)
)
) )
} }
}, },
@ -382,129 +626,18 @@ fun CreateNotebookDialog(
onConfirm(title, description) onConfirm(title, description)
} }
}, },
enabled = title.isNotBlank() enabled = title.isNotBlank(),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF7C3AED)
)
) { ) {
Text("Buat") Text("Buat")
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismiss) { TextButton(onClick = onDismiss) {
Text("Batal") Text("Batal", color = MaterialTheme.colorScheme.onSurfaceVariant) // [DIUBAH]
} }
} }
) )
} }
// === CHAT & SOURCES SCREEN (Placeholder - akan diupdate nanti) ===
@Composable
fun ChatScreen(viewModel: NotebookViewModel) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Chat Screen - Coming Soon")
}
}
@Composable
fun SourcesScreen(viewModel: NotebookViewModel) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Sources Screen - Coming Soon")
}
}
// === MENU COMPONENTS (Tetap sama) ===
@Composable
fun AccountScreen(onDismiss: () -> Unit) {
Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(usePlatformDefaultWidth = false)
) {
Scaffold(
topBar = {
TopAppBar(
title = {
Column {
Text("202310715190@mhs.ubharajaya.ac.id", fontSize = 14.sp)
Text("Managed by mhs.ubharajay.ac.id", fontSize = 12.sp, color = Color.Gray)
}
},
actions = {
IconButton(onClick = onDismiss) {
Icon(Icons.Default.Close, contentDescription = "Close")
}
}
)
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(48.dp))
Box {
Box(
modifier = Modifier
.size(80.dp)
.clip(CircleShape)
.background(Color.Magenta),
contentAlignment = Alignment.Center
) {
Text("M", color = Color.White, fontWeight = FontWeight.Bold, fontSize = 40.sp)
}
}
Spacer(modifier = Modifier.height(16.dp))
Text("Hi, 202310715190!", fontSize = 20.sp)
}
}
}
}
@Composable
fun SettingsMenu(
expanded: Boolean,
onDismiss: () -> Unit,
isDarkMode: Boolean,
onThemeChange: (Boolean) -> Unit
) {
DropdownMenu(expanded = expanded, onDismissRequest = onDismiss) {
// Dark Mode Toggle
DropdownMenuItem(
text = {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
if (isDarkMode) Icons.Default.DarkMode else Icons.Default.LightMode,
contentDescription = null
)
Spacer(modifier = Modifier.width(12.dp))
Text(if (isDarkMode) "Mode Gelap" else "Mode Terang")
}
Switch(
checked = isDarkMode,
onCheckedChange = onThemeChange
)
}
},
onClick = { onThemeChange(!isDarkMode) }
)
Divider()
DropdownMenuItem(
text = { Text("NotebookLM Help") },
onClick = { },
leadingIcon = { Icon(Icons.Default.HelpOutline, contentDescription = null) }
)
}
}