Penyesuaian Migrasi (import Library), Fix Bug Aplikasi Crash, Menambahkan Fitur edit dan hapus pada kategori
This commit is contained in:
parent
63b10a3e1c
commit
3f84068d72
4
.idea/deploymentTargetSelector.xml
generated
4
.idea/deploymentTargetSelector.xml
generated
@ -4,10 +4,10 @@
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2025-12-12T17:42:15.072692700Z">
|
||||
<DropdownSelection timestamp="2025-12-13T07:41:36.634314200Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\dendi\.android\avd\Medium_Phone.avd" />
|
||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=RR8T103A6JZ" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.example.notesai
|
||||
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
@ -11,12 +12,10 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import java.util.UUID
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@ -31,37 +30,13 @@ import com.example.notesai.presentation.screens.ai.AIHelperScreen
|
||||
import com.example.notesai.presentation.screens.archive.ArchiveScreen
|
||||
import com.example.notesai.presentation.screens.main.MainScreen
|
||||
import com.example.notesai.presentation.screens.note.EditableFullScreenNoteView
|
||||
import com.example.notesai.presentation.screens.starred.components.StarredNotesScreen
|
||||
import com.example.notesai.presentation.screens.trash.components.TrashScreen
|
||||
import com.example.notesai.presentation.screens.starred.StarredNotesScreen
|
||||
import com.example.notesai.presentation.screens.trash.TrashScreen
|
||||
import com.example.notesai.data.model.Note
|
||||
import com.example.notesai.data.model.Category
|
||||
import com.example.notesai.util.updateWhere
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
// Data Classes
|
||||
data class Category(
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val name: String,
|
||||
val gradientStart: Long,
|
||||
val gradientEnd: Long,
|
||||
val timestamp: Long = System.currentTimeMillis()
|
||||
)
|
||||
|
||||
data class Note(
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val categoryId: String,
|
||||
val title: String,
|
||||
val content: String,
|
||||
val timestamp: Long = System.currentTimeMillis(),
|
||||
val isArchived: Boolean = false,
|
||||
val isDeleted: Boolean = false,
|
||||
val isPinned: Boolean = false
|
||||
)
|
||||
|
||||
data class ChatMessage(
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val message: String,
|
||||
val isUser: Boolean,
|
||||
val timestamp: Long = System.currentTimeMillis()
|
||||
)
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -300,6 +275,19 @@ fun NotesApp() {
|
||||
categories = categories.filter { it.id != category.id }
|
||||
notes = notes.filter { it.categoryId != category.id }
|
||||
selectedCategory = null
|
||||
},
|
||||
onCategoryEdit = { category, newName, newGradientStart, newGradientEnd ->
|
||||
categories = categories.updateWhere(
|
||||
predicate = { it.id == category.id },
|
||||
transform = {
|
||||
it.copy(
|
||||
name = newName,
|
||||
gradientStart = newGradientStart,
|
||||
gradientEnd = newGradientEnd,
|
||||
timestamp = System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
"starred" -> StarredNotesScreen(
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
package com.example.notesai.config
|
||||
|
||||
object APIKey {
|
||||
const val GEMINI_API_KEY = "MY_GEMINI_KEY"
|
||||
const val GEMINI_API_KEY = "AIzaSyBzC64RXsNtSERlts_FSd8HXKEpkLdT7-8"
|
||||
}
|
||||
@ -9,8 +9,8 @@ import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.emptyPreferences
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.example.notesai.Category
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.data.model.Note
|
||||
import com.example.notesai.data.model.Category
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
// File: data/local/PreferencesKeys.kt
|
||||
package com.example.notesai.data.local
|
||||
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
|
||||
object PreferencesKeys {
|
||||
val CATEGORIES_KEY = stringPreferencesKey("categories")
|
||||
val NOTES_KEY = stringPreferencesKey("notes")
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
// File: data/model/SerializableModels.kt
|
||||
package com.example.notesai.data.model
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
@Serializable
|
||||
data class SerializableCategory(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val gradientStart: Long,
|
||||
val gradientEnd: Long,
|
||||
val timestamp: Long
|
||||
)
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
@Serializable
|
||||
data class SerializableNote(
|
||||
val id: String,
|
||||
val categoryId: String,
|
||||
val title: String,
|
||||
val content: String,
|
||||
val timestamp: Long,
|
||||
val isArchived: Boolean,
|
||||
val isDeleted: Boolean,
|
||||
val isPinned: Boolean
|
||||
)
|
||||
|
||||
// Extension functions untuk konversi
|
||||
fun Category.toSerializable() = SerializableCategory(
|
||||
id = id,
|
||||
name = name,
|
||||
gradientStart = gradientStart,
|
||||
gradientEnd = gradientEnd,
|
||||
timestamp = timestamp
|
||||
)
|
||||
|
||||
fun SerializableCategory.toCategory() = Category(
|
||||
id = id,
|
||||
name = name,
|
||||
gradientStart = gradientStart,
|
||||
gradientEnd = gradientEnd,
|
||||
timestamp = timestamp
|
||||
)
|
||||
|
||||
fun Note.toSerializable() = SerializableNote(
|
||||
id = id,
|
||||
categoryId = categoryId,
|
||||
title = title,
|
||||
content = content,
|
||||
timestamp = timestamp,
|
||||
isArchived = isArchived,
|
||||
isDeleted = isDeleted,
|
||||
isPinned = isPinned
|
||||
)
|
||||
|
||||
fun SerializableNote.toNote() = Note(
|
||||
id = id,
|
||||
categoryId = categoryId,
|
||||
title = title,
|
||||
content = content,
|
||||
timestamp = timestamp,
|
||||
isArchived = isArchived,
|
||||
isDeleted = isDeleted,
|
||||
isPinned = isPinned
|
||||
)
|
||||
@ -25,7 +25,7 @@ import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.data.model.Note
|
||||
|
||||
@Composable
|
||||
fun NoteDialog(
|
||||
|
||||
@ -53,9 +53,9 @@ import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.Category
|
||||
import com.example.notesai.ChatMessage
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.data.model.Note
|
||||
import com.example.notesai.data.model.ChatMessage
|
||||
import com.example.notesai.data.model.Category
|
||||
import com.example.notesai.config.APIKey
|
||||
import com.example.notesai.presentation.screens.ai.components.ChatBubble
|
||||
import com.example.notesai.presentation.screens.ai.components.CompactStatItem
|
||||
|
||||
@ -23,7 +23,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.notesai.ChatMessage
|
||||
import com.example.notesai.data.model.ChatMessage
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
@ -8,8 +8,8 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Archive
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.Category
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.data.model.Note
|
||||
import com.example.notesai.data.model.Category
|
||||
import com.example.notesai.presentation.components.EmptyState
|
||||
import com.example.notesai.presentation.screens.archive.components.ArchiveNoteCard
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ 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 com.example.notesai.Note
|
||||
import com.example.notesai.data.model.Note
|
||||
|
||||
@Composable
|
||||
fun ArchiveNoteCard(
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
// File: presentation/screens/main/MainScreen.kt
|
||||
package com.example.notesai.presentation.screens.main
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
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.*
|
||||
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
|
||||
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
|
||||
import androidx.compose.foundation.lazy.staggeredgrid.items
|
||||
@ -15,12 +12,12 @@ import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.Category
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.data.model.Category
|
||||
import com.example.notesai.data.model.Note
|
||||
import com.example.notesai.presentation.components.EmptyState
|
||||
import com.example.notesai.presentation.screens.main.components.CategoryCard
|
||||
import com.example.notesai.presentation.screens.main.components.NoteCard
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun MainScreen(
|
||||
categories: List<Category>,
|
||||
@ -30,7 +27,8 @@ fun MainScreen(
|
||||
onCategoryClick: (Category) -> Unit,
|
||||
onNoteClick: (Note) -> Unit,
|
||||
onPinToggle: (Note) -> Unit,
|
||||
onCategoryDelete: (Category) -> Unit
|
||||
onCategoryDelete: (Category) -> Unit,
|
||||
onCategoryEdit: (Category, String, Long, Long) -> Unit // Parameter baru
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
if (selectedCategory == null) {
|
||||
@ -68,10 +66,15 @@ fun MainScreen(
|
||||
items(filteredCategories) { category ->
|
||||
CategoryCard(
|
||||
category = category,
|
||||
noteCount = notes.count { it.categoryId == category.id && !it.isDeleted && !it.isArchived },
|
||||
noteCount = notes.count {
|
||||
it.categoryId == category.id &&
|
||||
!it.isDeleted &&
|
||||
!it.isArchived
|
||||
},
|
||||
onClick = { onCategoryClick(category) },
|
||||
onDelete = {
|
||||
onCategoryDelete(category)
|
||||
onDelete = { onCategoryDelete(category) },
|
||||
onEdit = { name, gradientStart, gradientEnd ->
|
||||
onCategoryEdit(category, name, gradientStart, gradientEnd)
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -108,7 +111,7 @@ fun MainScreen(
|
||||
NoteCard(
|
||||
note = note,
|
||||
onClick = { onNoteClick(note) },
|
||||
onPinClick = { onPinToggle(note) },
|
||||
onPinClick = { onPinToggle(note) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -116,8 +119,3 @@ fun MainScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NoteCard(note: Note, onClick: () -> Unit, onPinClick: () -> Unit) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
@ -1,58 +1,44 @@
|
||||
package com.example.notesai.presentation.screens.main.components
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Folder
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
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.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.Category
|
||||
import com.example.notesai.data.model.Category
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun CategoryCard(
|
||||
category: Category,
|
||||
noteCount: Int,
|
||||
onClick: () -> Unit,
|
||||
onDelete: () -> Unit = {}
|
||||
onDelete: () -> Unit = {},
|
||||
onEdit: (String, Long, Long) -> Unit = { _, _, _ -> }
|
||||
) {
|
||||
var showDeleteConfirm by remember { mutableStateOf(false) }
|
||||
var showEditDialog by remember { mutableStateOf(false) }
|
||||
var showMenu by remember { mutableStateOf(false) }
|
||||
|
||||
// Delete confirmation dialog
|
||||
// Delete Confirmation Dialog
|
||||
if (showDeleteConfirm) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showDeleteConfirm = false },
|
||||
title = { Text("Hapus Kategori?", color = Color.White) },
|
||||
title = { Text("Pindahkan ke Sampah?", color = Color.White) },
|
||||
text = {
|
||||
Text("Kategori '${category.name}' dan semua catatan di dalamnya akan dihapus. Tindakan ini tidak dapat dibatalkan.", color = Color.White)
|
||||
Text(
|
||||
"Kategori '${category.name}' dan semua catatan di dalamnya akan dipindahkan ke sampah.",
|
||||
color = Color.White
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
Button(
|
||||
@ -81,6 +67,18 @@ fun CategoryCard(
|
||||
)
|
||||
}
|
||||
|
||||
// Edit Dialog
|
||||
if (showEditDialog) {
|
||||
EditCategoryDialog(
|
||||
category = category,
|
||||
onDismiss = { showEditDialog = false },
|
||||
onSave = { name, gradientStart, gradientEnd ->
|
||||
onEdit(name, gradientStart, gradientEnd)
|
||||
showEditDialog = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -124,22 +122,199 @@ fun CategoryCard(
|
||||
)
|
||||
}
|
||||
|
||||
// Delete button di top-right corner
|
||||
IconButton(
|
||||
onClick = {
|
||||
showDeleteConfirm = true
|
||||
},
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.size(40.dp)
|
||||
// Menu Button (Titik Tiga)
|
||||
Box(
|
||||
modifier = Modifier.align(Alignment.TopEnd)
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Close,
|
||||
contentDescription = "Hapus kategori",
|
||||
tint = Color.White.copy(0.7f),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
IconButton(
|
||||
onClick = { showMenu = true }
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.MoreVert,
|
||||
contentDescription = "Menu",
|
||||
tint = Color.White.copy(0.9f)
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = showMenu,
|
||||
onDismissRequest = { showMenu = false },
|
||||
modifier = Modifier.background(Color(0xFF1E293B))
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Edit,
|
||||
contentDescription = null,
|
||||
tint = Color(0xFF6366F1),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Text("Edit Kategori", color = Color.White)
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
showMenu = false
|
||||
showEditDialog = true
|
||||
}
|
||||
)
|
||||
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
contentDescription = null,
|
||||
tint = Color(0xFFEF4444),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Text("Pindah ke Sampah", color = Color.White)
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
showMenu = false
|
||||
showDeleteConfirm = true
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EditCategoryDialog(
|
||||
category: Category,
|
||||
onDismiss: () -> Unit,
|
||||
onSave: (String, Long, Long) -> Unit
|
||||
) {
|
||||
val gradients = listOf(
|
||||
Pair(0xFF6366F1L, 0xFFA855F7L),
|
||||
Pair(0xFFEC4899L, 0xFFF59E0BL),
|
||||
Pair(0xFF8B5CF6L, 0xFFEC4899L),
|
||||
Pair(0xFF06B6D4L, 0xFF3B82F6L),
|
||||
Pair(0xFF10B981L, 0xFF059669L),
|
||||
Pair(0xFFF59E0BL, 0xFFEF4444L),
|
||||
Pair(0xFF6366F1L, 0xFF8B5CF6L),
|
||||
Pair(0xFFEF4444L, 0xFFDC2626L)
|
||||
)
|
||||
var name by remember { mutableStateOf(category.name) }
|
||||
var selectedGradient by remember {
|
||||
mutableStateOf(
|
||||
gradients.indexOfFirst {
|
||||
it.first == category.gradientStart && it.second == category.gradientEnd
|
||||
}.takeIf { it >= 0 } ?: 0
|
||||
)
|
||||
}
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
containerColor = Color(0xFF1E293B),
|
||||
title = {
|
||||
Text(
|
||||
"Edit Kategori",
|
||||
color = Color.White,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
value = name,
|
||||
onValueChange = { name = it },
|
||||
label = { Text("Nama Kategori", color = Color(0xFF94A3B8)) },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedTextColor = Color.White,
|
||||
unfocusedTextColor = Color.White,
|
||||
focusedContainerColor = Color(0xFF334155),
|
||||
unfocusedContainerColor = Color(0xFF334155),
|
||||
cursorColor = Color(0xFFA855F7),
|
||||
focusedIndicatorColor = Color(0xFFA855F7),
|
||||
unfocusedIndicatorColor = Color(0xFF64748B)
|
||||
),
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Text(
|
||||
"Pilih Gradient:",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = Color.White,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
gradients.chunked(4).forEach { row ->
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
row.forEachIndexed { _, gradient ->
|
||||
val globalIndex = gradients.indexOf(gradient)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.aspectRatio(1f)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(
|
||||
brush = Brush.linearGradient(
|
||||
colors = listOf(
|
||||
Color(gradient.first),
|
||||
Color(gradient.second)
|
||||
)
|
||||
)
|
||||
)
|
||||
.clickable { selectedGradient = globalIndex },
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (selectedGradient == globalIndex) {
|
||||
Icon(
|
||||
Icons.Default.Check,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Button(
|
||||
onClick = {
|
||||
if (name.isNotBlank()) {
|
||||
val gradient = gradients[selectedGradient]
|
||||
onSave(name, gradient.first, gradient.second)
|
||||
}
|
||||
},
|
||||
enabled = name.isNotBlank(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.Transparent
|
||||
),
|
||||
modifier = Modifier.background(
|
||||
brush = Brush.linearGradient(
|
||||
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
|
||||
),
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
)
|
||||
) {
|
||||
Text("Simpan", color = Color.White, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text("Batal", color = Color(0xFF94A3B8))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -16,7 +16,6 @@ import androidx.compose.material.icons.filled.Star
|
||||
import androidx.compose.material.icons.outlined.StarBorder
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@ -30,8 +29,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.util.Constants.AppColors.Divider
|
||||
import com.example.notesai.data.model.Note
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
@ -112,7 +110,7 @@ fun NoteCard(
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Divider(
|
||||
HorizontalDivider(
|
||||
color = Color(0xFF334155),
|
||||
thickness = 1.dp
|
||||
)
|
||||
|
||||
@ -39,8 +39,7 @@ 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.Note
|
||||
import com.example.notesai.util.Constants.AppColors.Divider
|
||||
import com.example.notesai.data.model.Note
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.example.notesai.presentation.screens.starred.components
|
||||
package com.example.notesai.presentation.screens.starred
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
@ -9,10 +9,10 @@ import androidx.compose.material.icons.filled.Star
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.Category
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.presentation.components.EmptyState
|
||||
import com.example.notesai.presentation.screens.starred.StarredNoteCard
|
||||
import com.example.notesai.presentation.screens.starred.components.StarredNoteCard
|
||||
import com.example.notesai.data.model.Note
|
||||
import com.example.notesai.data.model.Category
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -1,4 +1,4 @@
|
||||
package com.example.notesai.presentation.screens.starred
|
||||
package com.example.notesai.presentation.screens.starred.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@ -28,7 +28,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.data.model.Note
|
||||
|
||||
@Composable
|
||||
fun StarredNoteCard(
|
||||
@ -1,4 +1,4 @@
|
||||
package com.example.notesai.presentation.screens.trash.components
|
||||
package com.example.notesai.presentation.screens.trash
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
@ -8,9 +8,10 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.notesai.Category
|
||||
import com.example.notesai.Note
|
||||
import com.example.notesai.presentation.components.EmptyState
|
||||
import com.example.notesai.presentation.screens.trash.components.TrashNoteCard
|
||||
import com.example.notesai.data.model.Note
|
||||
import com.example.notesai.data.model.Category
|
||||
|
||||
@Composable
|
||||
fun TrashScreen(
|
||||
@ -24,7 +24,7 @@ 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 com.example.notesai.Note
|
||||
import com.example.notesai.data.model.Note
|
||||
|
||||
@Composable
|
||||
fun TrashNoteCard(
|
||||
|
||||
@ -25,3 +25,7 @@ fun <T> List<T>.replaceWhere(predicate: (T) -> Boolean, transform: (T) -> T): Li
|
||||
fun <T> List<T>.removeWhere(predicate: (T) -> Boolean): List<T> {
|
||||
return this.filter { !predicate(it) }
|
||||
}
|
||||
|
||||
fun <T> List<T>.updateWhere(predicate: (T) -> Boolean, transform: (T) -> T): List<T> {
|
||||
return this.map { if (predicate(it)) transform(it) else it }
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user