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,153 +92,467 @@ 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
fun NewNotebookCard(onClick: () -> Unit) {
Card(
modifier = Modifier
.fillMaxWidth()
.height(120.dp)
.clickable(onClick = onClick),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFFF0F4F7))
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.background(Color(0xFFE1E3E6)),
contentAlignment = Alignment.Center
) {
Icon(Icons.Default.Add, contentDescription = "Buat notebook baru", tint = Color.Black)
}
Spacer(modifier = Modifier.height(8.dp))
Text("Buat notebook baru", color = Color.Black)
} }
} }
} }
@Composable @Composable
fun NotebookCard( fun NotebookHeader(
notebook: com.example.notebook.data.NotebookEntity, isDarkMode: Boolean,
onClick: () -> Unit, onThemeChange: (Boolean) -> Unit,
onDelete: () -> Unit onAccountClick: () -> Unit
) {
val dateFormat = SimpleDateFormat("dd MMM yyyy, HH:mm", Locale.getDefault())
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFFF8F9FA)),
onClick = {
println("🔵 Card onClick: ID=${notebook.id}, Title=${notebook.title}")
onClick()
}
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
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(),
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
) {
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), .padding(16.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
// Icon notebook 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(48.dp) .fillMaxSize()
.clip(RoundedCornerShape(8.dp)) .background(
.background(Color(0xFFE8EAF6)), Brush.horizontalGradient(
listOf(Color(0xFF7C3AED), Color(0xFF9333EA))
)
),
contentAlignment = Alignment.Center
) {
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
)
}
}
}
}
}
@Composable
fun NotebookCardItem(
notebook: com.example.notebook.data.NotebookEntity,
onClick: () -> Unit,
onDelete: () -> Unit
) {
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(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onClick),
shape = RoundedCornerShape(12.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLowest // [DIUBAH]
),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(44.dp)
.clip(RoundedCornerShape(10.dp))
.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
fun CreateNotebookDialog( fun CreateNotebookDialog(
@ -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) }
)
}
}