Memperbaiki Bug tidak tersimpan
This commit is contained in:
parent
79f7e33a5a
commit
b264f87b14
@ -149,7 +149,8 @@
|
||||
* Dark/Light theme toggle (ok)
|
||||
* AI Agent Catatan
|
||||
* Fungsi AI (Upload File)
|
||||
* Markdown Parser
|
||||
* Markdown Parser (ok)
|
||||
* Sematkan Category
|
||||
---
|
||||
|
||||
|
||||
|
||||
@ -6,21 +6,16 @@ import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
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.unit.dp
|
||||
import java.util.UUID
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.zIndex
|
||||
import com.example.notesai.data.local.DataStoreManager
|
||||
@ -37,55 +32,36 @@ 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
|
||||
import com.example.notesai.util.AppColors
|
||||
|
||||
// File: MainActivity.kt (Bagian Theme Setup)
|
||||
// Ganti MaterialTheme di setContent dengan ini:
|
||||
|
||||
import com.example.notesai.util.Constants
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
MaterialTheme(
|
||||
colorScheme = darkColorScheme(
|
||||
// Primary colors
|
||||
primary = AppColors.Primary,
|
||||
onPrimary = Color.White,
|
||||
primaryContainer = AppColors.PrimaryContainer,
|
||||
onPrimaryContainer = Color.White,
|
||||
|
||||
// Secondary colors
|
||||
secondary = AppColors.Secondary,
|
||||
onSecondary = Color.White,
|
||||
secondaryContainer = AppColors.SecondaryVariant,
|
||||
onSecondaryContainer = Color.White,
|
||||
|
||||
// Background colors
|
||||
background = AppColors.Background,
|
||||
onBackground = AppColors.OnBackground,
|
||||
|
||||
// Surface colors
|
||||
surface = AppColors.Surface,
|
||||
onSurface = AppColors.OnSurface,
|
||||
surfaceVariant = AppColors.SurfaceVariant,
|
||||
onSurfaceVariant = AppColors.OnSurfaceVariant,
|
||||
|
||||
// Error colors
|
||||
error = AppColors.Error,
|
||||
onError = Color.White,
|
||||
|
||||
// Other
|
||||
outline = AppColors.Border,
|
||||
outlineVariant = AppColors.Divider
|
||||
),
|
||||
typography = Typography(
|
||||
// Improve typography for better readability
|
||||
displayLarge = MaterialTheme.typography.displayLarge.copy(
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
@ -120,6 +96,7 @@ fun NotesApp() {
|
||||
val context = LocalContext.current
|
||||
val dataStoreManager = remember { DataStoreManager(context) }
|
||||
val scope = rememberCoroutineScope()
|
||||
val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current
|
||||
|
||||
var categories by remember { mutableStateOf(listOf<Category>()) }
|
||||
var notes by remember { mutableStateOf(listOf<Note>()) }
|
||||
@ -133,66 +110,85 @@ fun NotesApp() {
|
||||
var showSearch by remember { mutableStateOf(false) }
|
||||
var showFullScreenNote by remember { mutableStateOf(false) }
|
||||
var fullScreenNote by remember { mutableStateOf<Note?>(null) }
|
||||
|
||||
// Theme state
|
||||
var isDarkTheme by remember { mutableStateOf(true) }
|
||||
|
||||
// Load theme preference - SET THEME HERE
|
||||
// Guard flags to prevent race conditions
|
||||
var isDataLoaded by remember { mutableStateOf(false) }
|
||||
|
||||
// Load theme preference
|
||||
LaunchedEffect(Unit) {
|
||||
dataStoreManager.themeFlow.collect { theme ->
|
||||
isDarkTheme = theme == "dark"
|
||||
AppColors.setTheme(isDarkTheme) // SET GLOBAL THEME
|
||||
AppColors.setTheme(isDarkTheme)
|
||||
}
|
||||
}
|
||||
|
||||
// Load data dari DataStore
|
||||
// Load categories ONCE
|
||||
LaunchedEffect(Unit) {
|
||||
try {
|
||||
dataStoreManager.categoriesFlow.collect { loadedCategories ->
|
||||
dataStoreManager.categoriesFlow.collect { loadedCategories ->
|
||||
if (!isDataLoaded) {
|
||||
android.util.Log.d("NotesApp", "Loading ${loadedCategories.size} categories")
|
||||
categories = loadedCategories
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
// Load notes ONCE
|
||||
LaunchedEffect(Unit) {
|
||||
try {
|
||||
dataStoreManager.notesFlow.collect { loadedNotes ->
|
||||
dataStoreManager.notesFlow.collect { loadedNotes ->
|
||||
if (!isDataLoaded) {
|
||||
android.util.Log.d("NotesApp", "Loading ${loadedNotes.size} notes")
|
||||
notes = loadedNotes
|
||||
isDataLoaded = true // Mark as loaded
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
// Simpan categories dengan debounce
|
||||
LaunchedEffect(categories.size) {
|
||||
if (categories.isNotEmpty()) {
|
||||
delay(500)
|
||||
try {
|
||||
// Save categories when changed
|
||||
LaunchedEffect(categories) {
|
||||
if (isDataLoaded && categories.isNotEmpty()) {
|
||||
android.util.Log.d("NotesApp", "Saving ${categories.size} categories")
|
||||
scope.launch {
|
||||
dataStoreManager.saveCategories(categories)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simpan notes dengan debounce
|
||||
LaunchedEffect(notes.size) {
|
||||
if (notes.isNotEmpty()) {
|
||||
delay(500)
|
||||
try {
|
||||
// Save notes when changed
|
||||
LaunchedEffect(notes) {
|
||||
if (isDataLoaded && notes.isNotEmpty()) {
|
||||
android.util.Log.d("NotesApp", "Saving ${notes.size} notes")
|
||||
scope.launch {
|
||||
dataStoreManager.saveNotes(notes)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Provide theme colors
|
||||
// Save on lifecycle events
|
||||
DisposableEffect(lifecycleOwner) {
|
||||
val observer = androidx.lifecycle.LifecycleEventObserver { _, event ->
|
||||
if (event == androidx.lifecycle.Lifecycle.Event.ON_PAUSE ||
|
||||
event == androidx.lifecycle.Lifecycle.Event.ON_STOP) {
|
||||
android.util.Log.d("NotesApp", "Lifecycle ${event.name}: Saving data")
|
||||
scope.launch {
|
||||
if (categories.isNotEmpty()) {
|
||||
dataStoreManager.saveCategories(categories)
|
||||
}
|
||||
if (notes.isNotEmpty()) {
|
||||
dataStoreManager.saveNotes(notes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose {
|
||||
lifecycleOwner.lifecycle.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Scaffold(
|
||||
containerColor = AppColors.Background,
|
||||
topBar = {
|
||||
if (!showFullScreenNote && currentScreen != "ai") {
|
||||
ModernTopBar(
|
||||
@ -222,7 +218,12 @@ fun NotesApp() {
|
||||
floatingActionButton = {
|
||||
AnimatedVisibility(
|
||||
visible = currentScreen == "main" && !showFullScreenNote,
|
||||
enter = scaleIn() + fadeIn(),
|
||||
enter = scaleIn(
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioMediumBouncy,
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
) + fadeIn(),
|
||||
exit = scaleOut() + fadeOut()
|
||||
) {
|
||||
FloatingActionButton(
|
||||
@ -235,9 +236,18 @@ fun NotesApp() {
|
||||
}
|
||||
},
|
||||
containerColor = AppColors.Primary,
|
||||
contentColor = Color.White
|
||||
contentColor = Color.White,
|
||||
elevation = FloatingActionButtonDefaults.elevation(
|
||||
defaultElevation = 8.dp,
|
||||
pressedElevation = 12.dp
|
||||
),
|
||||
modifier = Modifier.size(64.dp)
|
||||
) {
|
||||
Icon(Icons.Default.Add, contentDescription = "Add")
|
||||
Icon(
|
||||
Icons.Default.Add,
|
||||
contentDescription = if (selectedCategory != null) "Tambah Catatan" else "Tambah Kategori",
|
||||
modifier = Modifier.size(28.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -252,8 +262,7 @@ fun NotesApp() {
|
||||
onAIClick = { currentScreen = "ai" }
|
||||
)
|
||||
}
|
||||
},
|
||||
containerColor = AppColors.Background // SET BACKGROUND HERE
|
||||
}
|
||||
) { padding ->
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
if (showFullScreenNote && fullScreenNote != null) {
|
||||
@ -306,7 +315,7 @@ fun NotesApp() {
|
||||
) {
|
||||
when (currentScreen) {
|
||||
"main" -> MainScreen(
|
||||
categories = categories.filter { !it.isDeleted }, // TAMBAHKAN FILTER INI
|
||||
categories = categories.filter { !it.isDeleted },
|
||||
notes = notes,
|
||||
selectedCategory = selectedCategory,
|
||||
searchQuery = searchQuery,
|
||||
@ -322,12 +331,10 @@ fun NotesApp() {
|
||||
}
|
||||
},
|
||||
onCategoryDelete = { category ->
|
||||
// UBAH: Jangan filter, tapi set isDeleted = true
|
||||
categories = categories.map {
|
||||
if (it.id == category.id) it.copy(isDeleted = true)
|
||||
else it
|
||||
}
|
||||
// Note di dalam kategori juga di-delete
|
||||
notes = notes.map {
|
||||
if (it.categoryId == category.id) it.copy(isDeleted = true)
|
||||
else it
|
||||
@ -352,7 +359,7 @@ fun NotesApp() {
|
||||
|
||||
"trash" -> TrashScreen(
|
||||
notes = notes.filter { it.isDeleted },
|
||||
categories = categories, // Pass semua categories (sudah ada yang isDeleted)
|
||||
categories = categories,
|
||||
onRestoreNote = { note ->
|
||||
notes = notes.map {
|
||||
if (it.id == note.id) it.copy(isDeleted = false, isArchived = false)
|
||||
@ -363,28 +370,24 @@ fun NotesApp() {
|
||||
notes = notes.filter { it.id != note.id }
|
||||
},
|
||||
onRestoreCategory = { category ->
|
||||
// Restore kategori
|
||||
categories = categories.map {
|
||||
if (it.id == category.id) it.copy(isDeleted = false)
|
||||
else it
|
||||
}
|
||||
// Restore semua note di dalam kategori
|
||||
notes = notes.map {
|
||||
if (it.categoryId == category.id) it.copy(isDeleted = false, isArchived = false)
|
||||
else it
|
||||
}
|
||||
},
|
||||
onDeleteCategoryPermanent = { category ->
|
||||
// Hapus kategori permanen
|
||||
categories = categories.filter { it.id != category.id }
|
||||
// Hapus semua note di dalam kategori permanen
|
||||
notes = notes.filter { it.categoryId != category.id }
|
||||
}
|
||||
)
|
||||
|
||||
"starred" -> StarredNotesScreen(
|
||||
notes = notes,
|
||||
categories = categories.filter { !it.isDeleted }, // FILTER
|
||||
categories = categories.filter { !it.isDeleted },
|
||||
onNoteClick = { note ->
|
||||
fullScreenNote = note
|
||||
showFullScreenNote = true
|
||||
@ -401,7 +404,7 @@ fun NotesApp() {
|
||||
|
||||
"archive" -> ArchiveScreen(
|
||||
notes = notes.filter { it.isArchived && !it.isDeleted },
|
||||
categories = categories.filter { !it.isDeleted }, // FILTER
|
||||
categories = categories.filter { !it.isDeleted },
|
||||
onRestore = { note ->
|
||||
notes = notes.map {
|
||||
if (it.id == note.id) it.copy(isArchived = false)
|
||||
@ -417,7 +420,7 @@ fun NotesApp() {
|
||||
)
|
||||
|
||||
"ai" -> AIHelperScreen(
|
||||
categories = categories.filter { !it.isDeleted }, // FILTER
|
||||
categories = categories.filter { !it.isDeleted },
|
||||
notes = notes.filter { !it.isDeleted }
|
||||
)
|
||||
}
|
||||
@ -462,13 +465,11 @@ fun NotesApp() {
|
||||
categoryId = selectedCategory!!.id,
|
||||
title = title,
|
||||
description = description,
|
||||
content = "" // Content kosong, akan diisi di EditableFullScreenNoteView
|
||||
content = ""
|
||||
)
|
||||
}
|
||||
showNoteDialog = false
|
||||
editingNote = null
|
||||
showNoteDialog = false
|
||||
editingNote = null
|
||||
},
|
||||
onDelete = if (editingNote != null) {
|
||||
{
|
||||
@ -485,11 +486,16 @@ fun NotesApp() {
|
||||
}
|
||||
}
|
||||
|
||||
// Drawer with theme toggle
|
||||
// Drawer with Animation
|
||||
AnimatedVisibility(
|
||||
visible = drawerState,
|
||||
enter = fadeIn() + slideInHorizontally { -it },
|
||||
exit = fadeOut() + slideOutHorizontally { -it }
|
||||
enter = fadeIn() + slideInHorizontally(
|
||||
initialOffsetX = { -it }
|
||||
),
|
||||
exit = fadeOut() + slideOutHorizontally(
|
||||
targetOffsetX = { -it }
|
||||
),
|
||||
modifier = Modifier.zIndex(100f)
|
||||
) {
|
||||
DrawerMenu(
|
||||
currentScreen = currentScreen,
|
||||
@ -504,7 +510,7 @@ fun NotesApp() {
|
||||
},
|
||||
onThemeToggle = {
|
||||
isDarkTheme = !isDarkTheme
|
||||
AppColors.setTheme(isDarkTheme) // UPDATE THEME
|
||||
AppColors.setTheme(isDarkTheme)
|
||||
scope.launch {
|
||||
dataStoreManager.saveTheme(if (isDarkTheme) "dark" else "light")
|
||||
}
|
||||
@ -512,5 +518,4 @@ fun NotesApp() {
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user