Compare commits
No commits in common. "nextNoteVault" and "compose-integration" have entirely different histories.
nextNoteVa
...
compose-in
1
.idea/.gitignore
vendored
1
.idea/.gitignore
vendored
@ -6,4 +6,3 @@
|
|||||||
# Datasource local storage ignored files
|
# Datasource local storage ignored files
|
||||||
/dataSources/
|
/dataSources/
|
||||||
/dataSources.local.xml
|
/dataSources.local.xml
|
||||||
/AndroidProjectSystem.xml
|
|
||||||
|
@ -1,7 +1,49 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
<data-source source="LOCAL" name="note_database" uuid="669634a7-d50e-4c04-b2fe-786d18bbd166">
|
<data-source source="LOCAL" name="music_database" uuid="95a3c2ec-2c29-4336-900a-3993de90ae66">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$USER_HOME$/.cache/JetBrains/IntelliJIdea2025.1/device-explorer/samsung SM-P610/_/data/data/com.stormtales.notevault/databases/music_database</jdbc-url>
|
||||||
|
<jdbc-additional-properties>
|
||||||
|
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
||||||
|
</jdbc-additional-properties>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
<libraries>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
|
||||||
|
</library>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
||||||
|
</library>
|
||||||
|
</libraries>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="note_database" uuid="b3770d7c-0a73-40c6-aab8-010effaa19b6">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$USER_HOME$/.cache/JetBrains/IntelliJIdea2025.1/device-explorer/samsung SM-P610/_/data/data/come.stormborntales.notevault/databases/note_database</jdbc-url>
|
||||||
|
<jdbc-additional-properties>
|
||||||
|
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
||||||
|
</jdbc-additional-properties>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
<libraries>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
|
||||||
|
</library>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
||||||
|
</library>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
|
||||||
|
</library>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
||||||
|
</library>
|
||||||
|
</libraries>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="note_database [2]" uuid="ad94cfd9-e485-4151-8bf4-a080c51fa27c">
|
||||||
<driver-ref>sqlite.xerial</driver-ref>
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
<synchronize>true</synchronize>
|
<synchronize>true</synchronize>
|
||||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
@ -23,12 +65,6 @@
|
|||||||
<library>
|
<library>
|
||||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
||||||
</library>
|
</library>
|
||||||
<library>
|
|
||||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
|
|
||||||
</library>
|
|
||||||
<library>
|
|
||||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
|
||||||
</library>
|
|
||||||
</libraries>
|
</libraries>
|
||||||
</data-source>
|
</data-source>
|
||||||
</component>
|
</component>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
<DropdownSelection timestamp="2025-05-10T10:58:30.749991183Z">
|
<DropdownSelection timestamp="2025-04-29T17:33:41.575251940Z">
|
||||||
<Target type="DEFAULT_BOOT">
|
<Target type="DEFAULT_BOOT">
|
||||||
<handle>
|
<handle>
|
||||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=R52N50NLGRT" />
|
<DeviceId pluginId="PhysicalDevice" identifier="serial=R52N50NLGRT" />
|
||||||
|
@ -40,9 +40,6 @@
|
|||||||
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
<option name="composableFile" value="true" />
|
<option name="composableFile" value="true" />
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
<inspection_tool class="PreviewParameterProviderOnFirstParameter" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
<option name="composableFile" value="true" />
|
<option name="composableFile" value="true" />
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
|
@ -63,5 +63,4 @@ dependencies {
|
|||||||
implementation(libs.compose.runtime.livedata)
|
implementation(libs.compose.runtime.livedata)
|
||||||
implementation(libs.coil.compose)
|
implementation(libs.coil.compose)
|
||||||
ksp(libs.androidx.room.compiler)
|
ksp(libs.androidx.room.compiler)
|
||||||
implementation(libs.androidx.material.icons.extended)
|
|
||||||
}
|
}
|
@ -2,82 +2,49 @@ package come.stormborntales.notevault
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.webkit.MimeTypeMap
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.result.PickVisualMediaRequest
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.AccountCircle
|
|
||||||
import androidx.compose.material.icons.filled.Menu
|
|
||||||
import androidx.compose.material3.DrawerValue
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.ModalDrawerSheet
|
|
||||||
import androidx.compose.material3.ModalNavigationDrawer
|
|
||||||
import androidx.compose.material3.NavigationDrawerItem
|
|
||||||
import androidx.compose.material3.NavigationDrawerItemDefaults
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextField
|
|
||||||
import androidx.compose.material3.TextFieldDefaults
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.rememberDrawerState
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.compose.NavHost
|
|
||||||
import androidx.navigation.compose.composable
|
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
|
||||||
import androidx.navigation.compose.rememberNavController
|
|
||||||
import come.stormborntales.notevault.data.local.AppDatabase
|
import come.stormborntales.notevault.data.local.AppDatabase
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
import come.stormborntales.notevault.data.model.NoteEntry
|
||||||
import come.stormborntales.notevault.data.repository.CollectionRepository
|
|
||||||
import come.stormborntales.notevault.data.repository.NoteRepository
|
import come.stormborntales.notevault.data.repository.NoteRepository
|
||||||
import come.stormborntales.notevault.ui.screens.AddNoteDialog
|
import come.stormborntales.notevault.ui.screens.AddNoteDialog
|
||||||
import come.stormborntales.notevault.ui.screens.MainScreen
|
import come.stormborntales.notevault.ui.screens.MainScreen
|
||||||
import come.stormborntales.notevault.ui.screens.notebrowser.NotesScreen
|
|
||||||
import come.stormborntales.notevault.ui.screens.SettingsScreen
|
|
||||||
import come.stormborntales.notevault.ui.theme.NoteVaultTheme
|
import come.stormborntales.notevault.ui.theme.NoteVaultTheme
|
||||||
import come.stormborntales.notevault.ui.viewmodel.NoteBrowserViewModel
|
|
||||||
import come.stormborntales.notevault.ui.viewmodel.NoteBrowserViewModelFactory
|
|
||||||
import come.stormborntales.notevault.ui.viewmodel.NoteViewModel
|
import come.stormborntales.notevault.ui.viewmodel.NoteViewModel
|
||||||
import come.stormborntales.notevault.ui.viewmodel.NoteViewModelFactory
|
import come.stormborntales.notevault.ui.viewmodel.NoteViewModelFactory
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.File
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val applicationContext = applicationContext
|
val applicationContext = applicationContext
|
||||||
val database = AppDatabase.getDatabase(applicationContext)
|
val database = AppDatabase.getDatabase(applicationContext)
|
||||||
val noteRepository = NoteRepository(database.noteDao())
|
val repository = NoteRepository(database.noteDao())
|
||||||
val collectionRepository = CollectionRepository(database.collectionDao())
|
val viewModelFactory = NoteViewModelFactory(repository)
|
||||||
val viewModelFactory = NoteViewModelFactory(noteRepository)
|
|
||||||
val noteBrowserViewModelFactory = NoteBrowserViewModelFactory(noteRepository, collectionRepository)
|
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
NoteVaultTheme {
|
NoteVaultTheme {
|
||||||
val navController = rememberNavController()
|
|
||||||
val viewModel: NoteViewModel = viewModel(factory = viewModelFactory)
|
val viewModel: NoteViewModel = viewModel(factory = viewModelFactory)
|
||||||
val noteBrowserViewModel: NoteBrowserViewModel = viewModel(factory = noteBrowserViewModelFactory)
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
// Globale Notenliste
|
||||||
|
val notes = remember { mutableStateListOf<NoteEntry>() }
|
||||||
|
|
||||||
|
// Bildauswahl + Dialog-States
|
||||||
var selectedUris by remember { mutableStateOf<List<Uri>>(emptyList()) }
|
var selectedUris by remember { mutableStateOf<List<Uri>>(emptyList()) }
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
var noteToEdit by remember { mutableStateOf<NoteEntity?>(null) }
|
|
||||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
|
// Launcher innerhalb von Compose
|
||||||
val imagePickerLauncher = rememberLauncherForActivityResult(
|
val imagePickerLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.OpenMultipleDocuments(),
|
contract = ActivityResultContracts.OpenMultipleDocuments(),
|
||||||
onResult = { uris ->
|
onResult = { uris ->
|
||||||
@ -88,145 +55,23 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val openDialog: (NoteEntity?) -> Unit = { note ->
|
// UI anzeigen
|
||||||
Log.d("EditNote", "NoteEntity: ${note?.title}")
|
|
||||||
noteToEdit = note
|
|
||||||
showDialog = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val navItems = listOf(
|
|
||||||
"Home" to "main",
|
|
||||||
"Notes" to "notes",
|
|
||||||
"Einstellungen" to "settings"
|
|
||||||
)
|
|
||||||
|
|
||||||
ModalNavigationDrawer(
|
|
||||||
drawerState = drawerState,
|
|
||||||
drawerContent = {
|
|
||||||
ModalDrawerSheet {
|
|
||||||
Text("Navigation", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
|
|
||||||
navItems.forEach { (label, route) ->
|
|
||||||
NavigationDrawerItem(
|
|
||||||
label = { Text(label) },
|
|
||||||
selected = false,
|
|
||||||
onClick = {
|
|
||||||
navController.navigate(route) {
|
|
||||||
popUpTo(navController.graph.startDestinationId) { saveState = true }
|
|
||||||
launchSingleTop = true
|
|
||||||
restoreState = true
|
|
||||||
}
|
|
||||||
scope.launch { drawerState.close() }
|
|
||||||
},
|
|
||||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
topBar = {
|
|
||||||
var searchQuery by remember { mutableStateOf("") }
|
|
||||||
var isMenuExpanded by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
|
||||||
val currentRoute = navBackStackEntry?.destination?.route
|
|
||||||
|
|
||||||
TopAppBar(
|
|
||||||
title = {
|
|
||||||
if(currentRoute == "main") {
|
|
||||||
TextField(
|
|
||||||
value = searchQuery,
|
|
||||||
onValueChange = {
|
|
||||||
searchQuery = it
|
|
||||||
viewModel.searchQuery.value = it
|
|
||||||
},
|
|
||||||
placeholder = { Text("Suche...") },
|
|
||||||
singleLine = true,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(end = 48.dp), // Platz für Avatar
|
|
||||||
textStyle = MaterialTheme.typography.bodyLarge,
|
|
||||||
colors = TextFieldDefaults.textFieldColors(
|
|
||||||
containerColor = Color.Transparent,
|
|
||||||
unfocusedIndicatorColor = Color.Transparent,
|
|
||||||
focusedIndicatorColor = Color.Transparent
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Text("NoteVault")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
navigationIcon = {
|
|
||||||
IconButton(onClick = { scope.launch { drawerState.open() } }) {
|
|
||||||
Icon(Icons.Default.Menu, contentDescription = "Menü öffnen")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions = {
|
|
||||||
Box {
|
|
||||||
IconButton(onClick = { isMenuExpanded = true }) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.AccountCircle, // Avatar-Icon
|
|
||||||
contentDescription = "Benutzerprofil"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = isMenuExpanded,
|
|
||||||
onDismissRequest = { isMenuExpanded = false }
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text("Profil") },
|
|
||||||
onClick = {
|
|
||||||
isMenuExpanded = false
|
|
||||||
// TODO: Navigiere ggf. zu Profilscreen
|
|
||||||
}
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text("Abmelden") },
|
|
||||||
onClick = {
|
|
||||||
isMenuExpanded = false
|
|
||||||
// TODO: Logout-Logik
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { innerPadding ->
|
|
||||||
NavHost(
|
|
||||||
navController = navController,
|
|
||||||
startDestination = "main",
|
|
||||||
modifier = Modifier.padding(innerPadding)
|
|
||||||
) {
|
|
||||||
composable("main") {
|
|
||||||
MainScreen(
|
MainScreen(
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
onAddNoteClicked = {
|
onAddNoteClicked = {
|
||||||
imagePickerLauncher.launch(arrayOf("image/*"))
|
imagePickerLauncher.launch(
|
||||||
},
|
arrayOf("image/*")
|
||||||
onEditNote = openDialog
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable("settings") {
|
)
|
||||||
SettingsScreen()
|
|
||||||
}
|
|
||||||
composable("notes") {
|
|
||||||
NotesScreen(collectionRepository, noteRepository, onImportNotes = {
|
|
||||||
imagePickerLauncher.launch(arrayOf("image/*"))
|
|
||||||
}, noteBrowserViewModel,
|
|
||||||
onEditNote = {
|
|
||||||
noteToEdit = it
|
|
||||||
showDialog = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Dialog bei Bedarf
|
||||||
if (showDialog) {
|
if (showDialog) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current;
|
||||||
|
val scope = rememberCoroutineScope();
|
||||||
AddNoteDialog(
|
AddNoteDialog(
|
||||||
onDismiss = { showDialog = false },
|
onDismiss = { showDialog = false },
|
||||||
onSave = { title, composer, year, genre, description ->
|
onSave = { title, composer, year, genre, description ->
|
||||||
if (noteToEdit == null) {
|
|
||||||
viewModel.addNote(
|
viewModel.addNote(
|
||||||
context = context,
|
context = context,
|
||||||
title = title,
|
title = title,
|
||||||
@ -235,31 +80,12 @@ class MainActivity : ComponentActivity() {
|
|||||||
genre = genre,
|
genre = genre,
|
||||||
description = description,
|
description = description,
|
||||||
selectedUris = selectedUris,
|
selectedUris = selectedUris,
|
||||||
collectionID = noteBrowserViewModel.currentParentId.value,
|
|
||||||
onDone = { showDialog = false }
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
viewModel.updateNote(
|
|
||||||
editedNote = noteToEdit!!,
|
|
||||||
updatedTitle = title,
|
|
||||||
updatedComposer = composer,
|
|
||||||
updatedYear = year,
|
|
||||||
updatedGenre = genre,
|
|
||||||
updatedDescription = description,
|
|
||||||
onDone = { showDialog = false }
|
onDone = { showDialog = false }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
initialTitle = noteToEdit?.title ?: "",
|
|
||||||
initialComposer = noteToEdit?.composer,
|
|
||||||
initialYear = noteToEdit?.year,
|
|
||||||
initialGenre = noteToEdit?.genre,
|
|
||||||
initialDescription = noteToEdit?.description
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,13 @@ import androidx.room.Database
|
|||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.TypeConverters
|
import androidx.room.TypeConverters
|
||||||
import come.stormborntales.notevault.data.local.dao.CollectionDao
|
|
||||||
import come.stormborntales.notevault.data.local.dao.NoteDao
|
import come.stormborntales.notevault.data.local.dao.NoteDao
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteCollection
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
||||||
|
|
||||||
@Database(entities = [NoteEntity::class, NoteCollection::class], version = 1)
|
@Database(entities = [NoteEntity::class], version = 1)
|
||||||
@TypeConverters(UriListConverter::class)
|
@TypeConverters(UriListConverter::class)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
abstract fun noteDao(): NoteDao
|
abstract fun noteDao(): NoteDao
|
||||||
abstract fun collectionDao(): CollectionDao
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Volatile
|
@Volatile
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package come.stormborntales.notevault.data.local.dao
|
|
||||||
|
|
||||||
import androidx.room.Dao
|
|
||||||
import androidx.room.Delete
|
|
||||||
import androidx.room.Insert
|
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
|
||||||
import androidx.room.Update
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteCollection
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
interface CollectionDao {
|
|
||||||
|
|
||||||
@Query(value = "SELECT * FROM note_collections WHERE parentId IS :parentId")
|
|
||||||
fun getCollectionsByParent(parentId: Int?): Flow<List<NoteCollection>>
|
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
|
||||||
suspend fun insertCollection(collection: NoteCollection)
|
|
||||||
|
|
||||||
@Update
|
|
||||||
suspend fun updateCollection(collection: NoteCollection)
|
|
||||||
|
|
||||||
@Delete
|
|
||||||
suspend fun deleteCollection(collection: NoteCollection)
|
|
||||||
|
|
||||||
@Query("SELECT * FROM note_collections WHERE id = :id LIMIT 1")
|
|
||||||
suspend fun getById(id: Int): NoteCollection?
|
|
||||||
|
|
||||||
@Query("SELECT * FROM note_collections")
|
|
||||||
fun getAll(): Flow<List<NoteCollection>>
|
|
||||||
}
|
|
@ -5,7 +5,6 @@ import androidx.room.Delete
|
|||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import androidx.room.Update
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@ -19,9 +18,4 @@ interface NoteDao {
|
|||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
suspend fun delete(note: NoteEntity)
|
suspend fun delete(note: NoteEntity)
|
||||||
|
|
||||||
@Update
|
|
||||||
suspend fun update(note: NoteEntity)
|
|
||||||
@Query("SELECT * FROM notes WHERE collectionId IS :collectionId")
|
|
||||||
fun getNotesForCollection(collectionId: Int?): Flow<List<NoteEntity>>
|
|
||||||
}
|
}
|
@ -1,11 +0,0 @@
|
|||||||
package come.stormborntales.notevault.data.local.entity
|
|
||||||
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
|
|
||||||
@Entity("note_collections")
|
|
||||||
data class NoteCollection(
|
|
||||||
@PrimaryKey(autoGenerate = true) var id: Int = 0,
|
|
||||||
var name: String,
|
|
||||||
var parentId: Int? = null
|
|
||||||
)
|
|
@ -1,24 +1,16 @@
|
|||||||
package come.stormborntales.notevault.data.local.entity
|
package come.stormborntales.notevault.data.local.entity
|
||||||
|
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.ForeignKey
|
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
@Entity(tableName = "notes",
|
@Entity(tableName = "notes")
|
||||||
foreignKeys = [ForeignKey(
|
|
||||||
entity = NoteCollection::class,
|
|
||||||
parentColumns = ["id"],
|
|
||||||
childColumns = ["collectionId"],
|
|
||||||
onDelete = ForeignKey.CASCADE
|
|
||||||
)])
|
|
||||||
data class NoteEntity(
|
data class NoteEntity(
|
||||||
@PrimaryKey(autoGenerate = true) val id: Int = 0,
|
@PrimaryKey(autoGenerate = true) val id: Int = 0,
|
||||||
var title: String,
|
val title: String,
|
||||||
val images: List<String>, // oder String + TypeConverter
|
val images: List<String>, // oder String + TypeConverter
|
||||||
var composer: String?,
|
val composer: String?,
|
||||||
var year: Int?,
|
val year: Int?,
|
||||||
var genre: String?,
|
val genre: String?,
|
||||||
var description: String?,
|
val description: String?,
|
||||||
val imagePreview: String,
|
val imagePreview: String
|
||||||
val collectionId: Int?
|
|
||||||
)
|
)
|
@ -1,34 +0,0 @@
|
|||||||
package come.stormborntales.notevault.data.repository
|
|
||||||
|
|
||||||
import come.stormborntales.notevault.data.local.dao.CollectionDao
|
|
||||||
import come.stormborntales.notevault.data.local.dao.NoteDao
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteCollection
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionRepository(private val dao: CollectionDao) {
|
|
||||||
fun getCollectionsByParent(parentId: Int?): Flow<List<NoteCollection>> {
|
|
||||||
return dao.getCollectionsByParent(parentId)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun insertCollection(collection: NoteCollection) {
|
|
||||||
dao.insertCollection(collection)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun updateCollection(collection: NoteCollection) {
|
|
||||||
dao.updateCollection(collection)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun deleteCollection(collection: NoteCollection) {
|
|
||||||
dao.deleteCollection(collection)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getCollectionById(id: Int): NoteCollection? {
|
|
||||||
return dao.getById(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAllCollections(): Flow<List<NoteCollection>> {
|
|
||||||
return dao.getAll()
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,7 +9,4 @@ class NoteRepository(private val dao: NoteDao) {
|
|||||||
|
|
||||||
suspend fun insert(note: NoteEntity) = dao.insert(note)
|
suspend fun insert(note: NoteEntity) = dao.insert(note)
|
||||||
suspend fun delete(note: NoteEntity) = dao.delete(note)
|
suspend fun delete(note: NoteEntity) = dao.delete(note)
|
||||||
|
|
||||||
suspend fun update(note: NoteEntity) = dao.update(note);
|
|
||||||
fun getNotesForCollection(parentId: Int?) = dao.getNotesForCollection(parentId);
|
|
||||||
}
|
}
|
||||||
|
@ -14,22 +14,15 @@ import androidx.compose.ui.unit.dp
|
|||||||
@Composable
|
@Composable
|
||||||
fun AddNoteDialog(
|
fun AddNoteDialog(
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onSave: (title: String, composer: String?, year: Int?, genre: String?, description: String?) -> Unit,
|
onSave: (title: String, composer: String?, year: Int?, genre: String?, description: String?) -> Unit
|
||||||
initialTitle: String = "",
|
|
||||||
initialComposer: String? = null,
|
|
||||||
initialYear: Int? = null,
|
|
||||||
initialGenre: String? = null,
|
|
||||||
initialDescription: String? = null,
|
|
||||||
collectionId: Int? = null
|
|
||||||
) {
|
) {
|
||||||
var title by remember { mutableStateOf(initialTitle) }
|
var title by remember { mutableStateOf("") }
|
||||||
var composer by remember { mutableStateOf(initialComposer ?: "") }
|
var composer by remember { mutableStateOf("") }
|
||||||
var yearText by remember { mutableStateOf(initialYear?.toString() ?: "") }
|
var yearText by remember { mutableStateOf("") }
|
||||||
var genre by remember { mutableStateOf(initialGenre ?: "") }
|
var genre by remember { mutableStateOf("") }
|
||||||
var description by remember { mutableStateOf(initialDescription ?: "") }
|
var description by remember { mutableStateOf("") }
|
||||||
var showTitleError by remember { mutableStateOf(false) }
|
var showTitleError by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
|
@ -6,13 +6,10 @@ import android.graphics.BitmapFactory
|
|||||||
import android.graphics.ImageDecoder
|
import android.graphics.ImageDecoder
|
||||||
import android.media.Image
|
import android.media.Image
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.horizontalScroll
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
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.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
@ -24,7 +21,6 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import come.stormborntales.notevault.FullscreenImageViewerActivity
|
import come.stormborntales.notevault.FullscreenImageViewerActivity
|
||||||
@ -33,7 +29,6 @@ import come.stormborntales.notevault.data.model.NoteEntry
|
|||||||
import come.stormborntales.notevault.ui.viewmodel.NoteViewModel
|
import come.stormborntales.notevault.ui.viewmodel.NoteViewModel
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
|
|
||||||
fun loadImageBitmap(context: Context, uriString: String): ImageBitmap? {
|
fun loadImageBitmap(context: Context, uriString: String): ImageBitmap? {
|
||||||
@ -46,14 +41,12 @@ fun loadImageBitmap(context: Context, uriString: String): ImageBitmap? {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}@Composable
|
}
|
||||||
fun NoteCard(note: NoteEntity, onDeleteNote: (NoteEntity) -> Unit, onEditNote: (NoteEntity) -> Unit) {
|
|
||||||
|
@Composable
|
||||||
|
fun NoteCard(note: NoteEntity) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val screenWidth = LocalConfiguration.current.screenWidthDp // Bildschirmbreite in dp
|
|
||||||
|
|
||||||
// Dynamische Bildgröße basierend auf der Bildschirmbreite
|
|
||||||
val imageSize = if (screenWidth < 400) 80.dp else 120.dp
|
|
||||||
|
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -62,105 +55,22 @@ fun NoteCard(note: NoteEntity, onDeleteNote: (NoteEntity) -> Unit, onEditNote: (
|
|||||||
shape = RoundedCornerShape(16.dp),
|
shape = RoundedCornerShape(16.dp),
|
||||||
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
|
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
|
||||||
) {
|
) {
|
||||||
// Responsive Layout: Überprüfen, ob der Bildschirm schmaler als 360 dp ist
|
|
||||||
if (screenWidth < 400) {
|
|
||||||
// Wenn der Bildschirm schmal ist, arrangiere die Elemente vertikal
|
|
||||||
Row(modifier = Modifier.padding(16.dp)) {
|
|
||||||
AsyncImage(
|
|
||||||
model = note.imagePreview,
|
|
||||||
contentDescription = "Vorschaubild",
|
|
||||||
modifier = Modifier
|
|
||||||
.size(imageSize)
|
|
||||||
.clip(RoundedCornerShape(12.dp))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(16.dp)) {
|
|
||||||
Text(
|
|
||||||
text = note.title,
|
|
||||||
style = MaterialTheme.typography.titleMedium
|
|
||||||
)
|
|
||||||
|
|
||||||
note.composer?.let {
|
|
||||||
Text("von $it", style = MaterialTheme.typography.labelMedium)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
|
|
||||||
note.year?.let {
|
|
||||||
Text("Jahr: $it", style = MaterialTheme.typography.bodySmall)
|
|
||||||
}
|
|
||||||
|
|
||||||
note.genre?.let {
|
|
||||||
Text("Genre: $it", style = MaterialTheme.typography.bodySmall)
|
|
||||||
}
|
|
||||||
|
|
||||||
note.description?.let {
|
|
||||||
Text("Beschreibung: $it", style = MaterialTheme.typography.bodySmall, maxLines = 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp)) // Abstand zwischen Text und Buttons
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Buttons unter dem Text
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
|
||||||
) {
|
|
||||||
OutlinedButton(
|
|
||||||
onClick = {
|
|
||||||
val uris = ArrayList<Uri>()
|
|
||||||
note.images.forEach { uris.add(it.toUri()) }
|
|
||||||
|
|
||||||
val intent = Intent(context, FullscreenImageViewerActivity::class.java).apply {
|
|
||||||
putParcelableArrayListExtra("imageUris", ArrayList(uris))
|
|
||||||
}
|
|
||||||
context.startActivity(intent)
|
|
||||||
},
|
|
||||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
|
|
||||||
) {
|
|
||||||
Text("Anzeigen", style = MaterialTheme.typography.labelLarge)
|
|
||||||
}
|
|
||||||
|
|
||||||
OutlinedButton(
|
|
||||||
onClick = {
|
|
||||||
onEditNote(note)
|
|
||||||
},
|
|
||||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
|
|
||||||
) {
|
|
||||||
Text("Bearbeiten", style = MaterialTheme.typography.labelLarge)
|
|
||||||
}
|
|
||||||
|
|
||||||
OutlinedButton(
|
|
||||||
onClick = {
|
|
||||||
onDeleteNote(note)
|
|
||||||
},
|
|
||||||
colors = ButtonDefaults.outlinedButtonColors(
|
|
||||||
contentColor = MaterialTheme.colorScheme.error
|
|
||||||
),
|
|
||||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
|
|
||||||
) {
|
|
||||||
Text("Löschen", style = MaterialTheme.typography.labelLarge)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Wenn der Bildschirm breiter als 360 dp ist, arrangiere die Elemente nebeneinander
|
|
||||||
Row(modifier = Modifier.padding(16.dp)) {
|
Row(modifier = Modifier.padding(16.dp)) {
|
||||||
// Linkes Vorschaubild
|
// Linkes Vorschaubild
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = note.imagePreview,
|
model = note.imagePreview,
|
||||||
contentDescription = "Vorschaubild",
|
contentDescription = "Vorschaubild",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(imageSize)
|
.size(120.dp)
|
||||||
.clip(RoundedCornerShape(12.dp))
|
.clip(RoundedCornerShape(12.dp))
|
||||||
)
|
)
|
||||||
|
|
||||||
// Rechte Info-Spalte
|
// Rechte Info-Spalte
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f) // Damit die Spalte den verfügbaren Platz nutzt
|
.weight(1f)
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
.padding(start = 16.dp)
|
.padding(start=16.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = note.title,
|
text = note.title,
|
||||||
@ -187,14 +97,12 @@ fun NoteCard(note: NoteEntity, onDeleteNote: (NoteEntity) -> Unit, onEditNote: (
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
// Buttons in einer Row anordnen
|
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
modifier = Modifier.fillMaxWidth() // Stellt sicher, dass die Row den gesamten verfügbaren Platz einnimmt
|
|
||||||
) {
|
) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
val uris = ArrayList<Uri>()
|
val uris = ArrayList<Uri>();
|
||||||
note.images.forEach { uris.add(it.toUri()) }
|
note.images.forEach { uris.add(it.toUri()) }
|
||||||
|
|
||||||
val intent = Intent(context, FullscreenImageViewerActivity::class.java).apply {
|
val intent = Intent(context, FullscreenImageViewerActivity::class.java).apply {
|
||||||
@ -206,20 +114,14 @@ fun NoteCard(note: NoteEntity, onDeleteNote: (NoteEntity) -> Unit, onEditNote: (
|
|||||||
) {
|
) {
|
||||||
Text("Anzeigen", style = MaterialTheme.typography.labelLarge)
|
Text("Anzeigen", style = MaterialTheme.typography.labelLarge)
|
||||||
}
|
}
|
||||||
|
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onClick = {
|
onClick = { /* TODO */ },
|
||||||
onEditNote(note)
|
|
||||||
},
|
|
||||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
|
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
|
||||||
) {
|
) {
|
||||||
Text("Bearbeiten", style = MaterialTheme.typography.labelLarge)
|
Text("Bearbeiten", style = MaterialTheme.typography.labelLarge)
|
||||||
}
|
}
|
||||||
|
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onClick = {
|
onClick = { /* TODO */ },
|
||||||
onDeleteNote(note)
|
|
||||||
},
|
|
||||||
colors = ButtonDefaults.outlinedButtonColors(
|
colors = ButtonDefaults.outlinedButtonColors(
|
||||||
contentColor = MaterialTheme.colorScheme.error
|
contentColor = MaterialTheme.colorScheme.error
|
||||||
),
|
),
|
||||||
@ -231,7 +133,6 @@ fun NoteCard(note: NoteEntity, onDeleteNote: (NoteEntity) -> Unit, onEditNote: (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -239,11 +140,15 @@ fun NoteCard(note: NoteEntity, onDeleteNote: (NoteEntity) -> Unit, onEditNote: (
|
|||||||
@Composable
|
@Composable
|
||||||
fun MainScreen(
|
fun MainScreen(
|
||||||
onAddNoteClicked: () -> Unit, // Übergib hier deine Logik für den Import
|
onAddNoteClicked: () -> Unit, // Übergib hier deine Logik für den Import
|
||||||
viewModel: NoteViewModel,
|
viewModel: NoteViewModel
|
||||||
onEditNote: (NoteEntity) -> Unit
|
|
||||||
) {
|
) {
|
||||||
val notes by viewModel.filteredNotes.collectAsState(initial = emptyList())
|
val notes by viewModel.notes.observeAsState(emptyList())
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Meine Noten") }
|
||||||
|
)
|
||||||
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = onAddNoteClicked
|
onClick = onAddNoteClicked
|
||||||
@ -260,9 +165,7 @@ fun MainScreen(
|
|||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
) {
|
) {
|
||||||
items(notes) { note ->
|
items(notes) { note ->
|
||||||
NoteCard(note = note, onDeleteNote = { noteEntity ->
|
NoteCard(note = note)
|
||||||
viewModel.deleteNote(noteEntity)
|
|
||||||
}, onEditNote = onEditNote)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
package come.stormborntales.notevault.ui.screens
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material3.Divider
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.OutlinedButton
|
|
||||||
import androidx.compose.material3.Switch
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsScreen() {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(16.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Einstellungen",
|
|
||||||
style = MaterialTheme.typography.headlineMedium,
|
|
||||||
modifier = Modifier.padding(bottom = 16.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
|
|
||||||
// Beispielhafte Einstellung
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Dark Mode",
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
style = MaterialTheme.typography.bodyLarge
|
|
||||||
)
|
|
||||||
Switch(
|
|
||||||
checked = false,
|
|
||||||
onCheckedChange = { /* TODO: Dark Mode aktivieren */ }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Benachrichtigungen",
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
style = MaterialTheme.typography.bodyLarge
|
|
||||||
)
|
|
||||||
Switch(
|
|
||||||
checked = true,
|
|
||||||
onCheckedChange = { /* TODO: Benachrichtigungseinstellungen */ }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
|
||||||
|
|
||||||
OutlinedButton(
|
|
||||||
onClick = { /* TODO: Impressum anzeigen */ },
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text("Impressum")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package come.stormborntales.notevault.ui.screens.notebrowser
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
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.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Slider
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
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.ui.Modifier
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun DeleteCollectionDialog(
|
|
||||||
collectionName: String,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
onConfirm: () -> Unit
|
|
||||||
) {
|
|
||||||
var sliderPosition by remember { mutableStateOf(0f) }
|
|
||||||
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = onDismiss,
|
|
||||||
title = {
|
|
||||||
Text("Collection löschen", style = MaterialTheme.typography.titleLarge)
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Column {
|
|
||||||
Text(
|
|
||||||
text = "Bist du sicher, dass du die Collection \"$collectionName\" löschen möchtest?",
|
|
||||||
style = MaterialTheme.typography.bodyMedium
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
Text(
|
|
||||||
text = "⚠️ Alle enthaltenen Noten werden ebenfalls dauerhaft gelöscht.",
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
color = MaterialTheme.colorScheme.error
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
Text(
|
|
||||||
text = "Zum Bestätigen den Schieberegler ganz nach rechts ziehen.",
|
|
||||||
style = MaterialTheme.typography.bodySmall
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
Slider(
|
|
||||||
value = sliderPosition,
|
|
||||||
onValueChange = { sliderPosition = it },
|
|
||||||
valueRange = 0f..1f,
|
|
||||||
steps = 0,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 4.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
confirmButton = {
|
|
||||||
TextButton(onClick = {
|
|
||||||
if(sliderPosition == 1.0f) {
|
|
||||||
onConfirm()
|
|
||||||
}
|
|
||||||
}, colors = ButtonDefaults.textButtonColors(
|
|
||||||
contentColor = MaterialTheme.colorScheme.error
|
|
||||||
)) {
|
|
||||||
Text("Löschen")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
TextButton(onClick = onDismiss) {
|
|
||||||
Text("Abbrechen")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
package come.stormborntales.notevault.ui.screens.notebrowser
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
|
||||||
import androidx.compose.material.icons.filled.Delete
|
|
||||||
import androidx.compose.material.icons.filled.Edit
|
|
||||||
import androidx.compose.material.icons.filled.Folder
|
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
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.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import coil.compose.AsyncImage
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteCollection
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CollectionItem(
|
|
||||||
collection: NoteCollection,
|
|
||||||
onDeleteCollection: (NoteCollection) -> Unit,
|
|
||||||
onEditCollection: (NoteCollection) -> Unit,
|
|
||||||
) {
|
|
||||||
var showMenu by remember { mutableStateOf(false) }
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.height(120.dp)
|
|
||||||
.clip(RoundedCornerShape(12.dp))
|
|
||||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
|
||||||
.clickable { }
|
|
||||||
.padding(12.dp),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Folder,
|
|
||||||
contentDescription = "Ordner",
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
modifier = Modifier.size(64.dp)
|
|
||||||
)
|
|
||||||
Box {
|
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable { showMenu = true }
|
|
||||||
.padding(top = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = collection.name,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
maxLines = 2,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable(
|
|
||||||
interactionSource = interactionSource,
|
|
||||||
indication = rememberRipple(bounded = true)
|
|
||||||
) {
|
|
||||||
showMenu = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.ArrowDropDown,
|
|
||||||
contentDescription = "Mehr Optionen",
|
|
||||||
tint = MaterialTheme.colorScheme.onSurface
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = showMenu,
|
|
||||||
onDismissRequest = { showMenu = false },
|
|
||||||
modifier = Modifier
|
|
||||||
.width(240.dp)
|
|
||||||
.background(MaterialTheme.colorScheme.background)
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
showMenu = false
|
|
||||||
onEditCollection(collection)
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Edit,
|
|
||||||
contentDescription = "Bearbeiten",
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
modifier = Modifier.size(20.dp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Text("Bearbeiten", color = MaterialTheme.colorScheme.primary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
showMenu = false
|
|
||||||
onDeleteCollection(collection)
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Delete,
|
|
||||||
contentDescription = "Löschen",
|
|
||||||
tint = MaterialTheme.colorScheme.error,
|
|
||||||
modifier = Modifier.size(20.dp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Text("Löschen", color = MaterialTheme.colorScheme.error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
package come.stormborntales.notevault.ui.screens.notebrowser
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
|
||||||
import androidx.compose.material.icons.filled.Delete
|
|
||||||
import androidx.compose.material.icons.filled.Edit
|
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
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.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import coil.compose.AsyncImage
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun NoteItem(
|
|
||||||
note: NoteEntity,
|
|
||||||
onNoteClick: (NoteEntity) -> Unit,
|
|
||||||
onEditTitle: () -> Unit,
|
|
||||||
onDeleteNote: () -> Unit
|
|
||||||
) {
|
|
||||||
var showMenu by remember { mutableStateOf(false) }
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.height(120.dp)
|
|
||||||
.clip(RoundedCornerShape(12.dp))
|
|
||||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
|
||||||
.clickable { onNoteClick(note) }
|
|
||||||
.padding(12.dp),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
AsyncImage(
|
|
||||||
model = note.imagePreview,
|
|
||||||
contentDescription = "Noten-Vorschau",
|
|
||||||
modifier = Modifier
|
|
||||||
.size(64.dp)
|
|
||||||
.clip(RoundedCornerShape(8.dp)),
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
|
|
||||||
Box {
|
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable { showMenu = true }
|
|
||||||
.padding(top = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = note.title,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
maxLines = 2,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable(
|
|
||||||
interactionSource = interactionSource,
|
|
||||||
indication = rememberRipple(bounded = true)
|
|
||||||
) {
|
|
||||||
showMenu = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.ArrowDropDown,
|
|
||||||
contentDescription = "Mehr Optionen",
|
|
||||||
tint = MaterialTheme.colorScheme.onSurface
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = showMenu,
|
|
||||||
onDismissRequest = { showMenu = false },
|
|
||||||
modifier = Modifier
|
|
||||||
.width(240.dp)
|
|
||||||
.background(MaterialTheme.colorScheme.background)
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
showMenu = false
|
|
||||||
onEditTitle()
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Edit,
|
|
||||||
contentDescription = "Bearbeiten",
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
modifier = Modifier.size(20.dp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Text("Bearbeiten", color = MaterialTheme.colorScheme.primary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
showMenu = false
|
|
||||||
onDeleteNote()
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Delete,
|
|
||||||
contentDescription = "Löschen",
|
|
||||||
tint = MaterialTheme.colorScheme.error,
|
|
||||||
modifier = Modifier.size(20.dp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Text("Löschen", color = MaterialTheme.colorScheme.error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,305 +0,0 @@
|
|||||||
package come.stormborntales.notevault.ui.screens.notebrowser
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.activity.compose.BackHandler
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
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.width
|
|
||||||
import androidx.compose.foundation.layout.wrapContentWidth
|
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
|
||||||
import androidx.compose.foundation.lazy.grid.items
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Add
|
|
||||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
|
||||||
import androidx.compose.material.icons.filled.Delete
|
|
||||||
import androidx.compose.material.icons.filled.Edit
|
|
||||||
import androidx.compose.material.icons.filled.Folder
|
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.FloatingActionButton
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import coil.compose.AsyncImage
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteCollection
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
|
||||||
import come.stormborntales.notevault.data.repository.CollectionRepository
|
|
||||||
import come.stormborntales.notevault.data.repository.NoteRepository
|
|
||||||
import come.stormborntales.notevault.ui.viewmodel.NoteBrowserViewModel
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CreateCollectionDialog(
|
|
||||||
editedCollection: NoteCollection?,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
onCreate: (String) -> Unit
|
|
||||||
) {
|
|
||||||
var collectionName by remember { mutableStateOf(editedCollection?.name ?: "") }
|
|
||||||
var isError by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = onDismiss,
|
|
||||||
title = {
|
|
||||||
Text("Neue Collection erstellen")
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Column {
|
|
||||||
OutlinedTextField(
|
|
||||||
value = collectionName,
|
|
||||||
onValueChange = {
|
|
||||||
collectionName = it
|
|
||||||
isError = false
|
|
||||||
},
|
|
||||||
label = { Text("Collection-Name") },
|
|
||||||
isError = isError,
|
|
||||||
singleLine = true
|
|
||||||
)
|
|
||||||
if (isError) {
|
|
||||||
Text(
|
|
||||||
text = "Name darf nicht leer sein",
|
|
||||||
color = MaterialTheme.colorScheme.error,
|
|
||||||
style = MaterialTheme.typography.bodySmall
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
confirmButton = {
|
|
||||||
TextButton(onClick = {
|
|
||||||
if (collectionName.isBlank()) {
|
|
||||||
isError = true
|
|
||||||
} else {
|
|
||||||
onCreate(collectionName.trim())
|
|
||||||
onDismiss()
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Text("Erstellen")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
TextButton(onClick = onDismiss) {
|
|
||||||
Text("Abbrechen")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CollectionBreadcrumbs(
|
|
||||||
path: List<NoteCollection>,
|
|
||||||
onNavigateTo: (index: Int) -> Unit
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
BreadcrumbItem(label = "Start", onClick = { onNavigateTo(-1) })
|
|
||||||
|
|
||||||
path.forEachIndexed { index, collection ->
|
|
||||||
Text(" / ", style = MaterialTheme.typography.labelLarge)
|
|
||||||
|
|
||||||
BreadcrumbItem(label = collection.name, onClick = {
|
|
||||||
Log.d("Breadcrumb", "BreadcrumbItem " + collection.name + " was clicked")
|
|
||||||
onNavigateTo(index)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun BreadcrumbItem(label: String, onClick: () -> Unit) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 4.dp)
|
|
||||||
.clickable(onClick = {
|
|
||||||
Log.d("Individual Breadcrumb", "A simple test " + label)
|
|
||||||
onClick()
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = label,
|
|
||||||
style = MaterialTheme.typography.labelLarge,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
|
||||||
fun NoteGrid(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
collections: List<NoteCollection>,
|
|
||||||
notes: List<NoteEntity>,
|
|
||||||
onCollectionClick: (NoteCollection) -> Unit,
|
|
||||||
onNoteClick: (NoteEntity) -> Unit,
|
|
||||||
onDeleteNote: (NoteEntity) -> Unit,
|
|
||||||
onEditNote: (NoteEntity) ->Unit,
|
|
||||||
onDeleteCollection: (NoteCollection) -> Unit,
|
|
||||||
onEditCollection: (NoteCollection) -> Unit,
|
|
||||||
) {
|
|
||||||
var showCollectionConfirmationDialog by remember { mutableStateOf(false) }
|
|
||||||
var deletedCollection: NoteCollection? by remember { mutableStateOf(null) }
|
|
||||||
LazyVerticalGrid(
|
|
||||||
modifier = modifier.fillMaxSize(),
|
|
||||||
columns = GridCells.Adaptive(minSize = 240.dp),
|
|
||||||
contentPadding = PaddingValues(8.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
items(collections) { collection ->
|
|
||||||
CollectionItem(collection, onDeleteCollection = {
|
|
||||||
showCollectionConfirmationDialog = true
|
|
||||||
deletedCollection = collection
|
|
||||||
}, onEditCollection = onEditCollection)
|
|
||||||
}
|
|
||||||
|
|
||||||
items(notes) { note ->
|
|
||||||
NoteItem(note, onNoteClick = {}, onEditTitle = {onEditNote(note)}, onDeleteNote = {onDeleteNote(note)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(showCollectionConfirmationDialog && deletedCollection != null) {
|
|
||||||
DeleteCollectionDialog(deletedCollection!!.name , {}, {
|
|
||||||
onDeleteCollection(deletedCollection!!)
|
|
||||||
showCollectionConfirmationDialog = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Composable
|
|
||||||
fun NotesScreen(
|
|
||||||
collectionRepository: CollectionRepository,
|
|
||||||
noteRepository: NoteRepository,
|
|
||||||
onImportNotes: (Int?) -> Unit,
|
|
||||||
viewModel: NoteBrowserViewModel,
|
|
||||||
onEditNote: (NoteEntity) -> Unit
|
|
||||||
) {
|
|
||||||
var menuExpanded by remember { mutableStateOf(false) }
|
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
|
||||||
var collectionToEdit by remember { mutableStateOf<NoteCollection?>(null) }
|
|
||||||
|
|
||||||
val collections by viewModel.currentCollections.collectAsState()
|
|
||||||
val notes by viewModel.currentNotes.collectAsState()
|
|
||||||
|
|
||||||
Scaffold(
|
|
||||||
floatingActionButton = {
|
|
||||||
Box {
|
|
||||||
FloatingActionButton(onClick = { menuExpanded = true }) {
|
|
||||||
Icon(Icons.Default.Add, contentDescription = "Open menu")
|
|
||||||
}
|
|
||||||
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = menuExpanded,
|
|
||||||
onDismissRequest = { menuExpanded = false },
|
|
||||||
modifier = Modifier
|
|
||||||
.wrapContentWidth()
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text("Ordner erstellen") },
|
|
||||||
onClick = {
|
|
||||||
menuExpanded = false
|
|
||||||
showDialog = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text("Noten importieren") },
|
|
||||||
onClick = {
|
|
||||||
menuExpanded = false
|
|
||||||
onImportNotes(viewModel.currentParentId.value)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
content = { innerPadding ->
|
|
||||||
|
|
||||||
val path by viewModel.pathStack.collectAsState()
|
|
||||||
|
|
||||||
BackHandler(enabled = path.isNotEmpty()) {
|
|
||||||
viewModel.navigateUp()
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(innerPadding)
|
|
||||||
) {
|
|
||||||
// Breadcrumbs sichtbar & klickbar machen
|
|
||||||
CollectionBreadcrumbs(
|
|
||||||
path = path,
|
|
||||||
onNavigateTo = { index ->
|
|
||||||
Log.d("NoteBrowser", "Navigate to: $index")
|
|
||||||
if (index == -1) viewModel.loadContentForParent(null)
|
|
||||||
else viewModel.navigateToLevel(index)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
NoteGrid(
|
|
||||||
collections = collections,
|
|
||||||
notes = notes,
|
|
||||||
onCollectionClick = { viewModel.loadContentForParent(it.id, it) },
|
|
||||||
onNoteClick = { /* TODO: Öffnen oder Bearbeiten */ },
|
|
||||||
onDeleteNote = {
|
|
||||||
viewModel.removeNote(noteEntity = it)
|
|
||||||
},
|
|
||||||
onEditNote = onEditNote,
|
|
||||||
onDeleteCollection = {
|
|
||||||
viewModel.removeCollection(noteCollection = it)
|
|
||||||
},
|
|
||||||
onEditCollection = {
|
|
||||||
collectionToEdit = it
|
|
||||||
showDialog = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (showDialog) {
|
|
||||||
CreateCollectionDialog(
|
|
||||||
onDismiss = { showDialog = false },
|
|
||||||
onCreate = { name ->
|
|
||||||
if(collectionToEdit != null) {
|
|
||||||
viewModel.updateCollection(collectionToEdit!!, name)
|
|
||||||
} else {
|
|
||||||
// Handle the new collection name
|
|
||||||
viewModel.createCollection(name)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
editedCollection = collectionToEdit
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
package come.stormborntales.notevault.ui.viewmodel
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteCollection
|
|
||||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
|
|
||||||
import come.stormborntales.notevault.data.repository.CollectionRepository
|
|
||||||
import come.stormborntales.notevault.data.repository.NoteRepository
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class NoteBrowserViewModel (
|
|
||||||
private val noteRepository: NoteRepository,
|
|
||||||
private val collectionRepository: CollectionRepository
|
|
||||||
) : ViewModel() {
|
|
||||||
private val _currentCollections = MutableStateFlow<List<NoteCollection>>(emptyList())
|
|
||||||
val currentCollections: StateFlow<List<NoteCollection>> = _currentCollections.asStateFlow()
|
|
||||||
|
|
||||||
private val _currentNotes = MutableStateFlow<List<NoteEntity>>(emptyList())
|
|
||||||
val currentNotes: StateFlow<List<NoteEntity>> = _currentNotes.asStateFlow()
|
|
||||||
|
|
||||||
private val _currentParentId = MutableStateFlow<Int?>(null)
|
|
||||||
val currentParentId: StateFlow<Int?> = _currentParentId.asStateFlow()
|
|
||||||
|
|
||||||
private val _pathStack = MutableStateFlow<List<NoteCollection>>(emptyList())
|
|
||||||
val pathStack: StateFlow<List<NoteCollection>> = _pathStack.asStateFlow()
|
|
||||||
|
|
||||||
init {
|
|
||||||
loadContentForParent(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadContentForParent(parentId: Int?, selectedCollection: NoteCollection? = null) {
|
|
||||||
_currentParentId.value = parentId
|
|
||||||
viewModelScope.launch {
|
|
||||||
launch {
|
|
||||||
collectionRepository.getCollectionsByParent(parentId).collect {
|
|
||||||
_currentCollections.value = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
noteRepository.getNotesForCollection(parentId).collect {
|
|
||||||
Log.d("NoteBrowser", "Noten geladen: ${it.size}")
|
|
||||||
_currentNotes.value = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (selectedCollection != null) {
|
|
||||||
_pathStack.value = _pathStack.value + selectedCollection
|
|
||||||
} else if (parentId == null) {
|
|
||||||
_pathStack.value = emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createCollection(name: String) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
val newCollection = NoteCollection(name = name, parentId = _currentParentId.value)
|
|
||||||
collectionRepository.insertCollection(newCollection)
|
|
||||||
loadContentForParent(_currentParentId.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeNote(noteEntity: NoteEntity) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
noteRepository.delete(noteEntity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeCollection(noteCollection: NoteCollection) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
collectionRepository.deleteCollection(noteCollection)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun navigateToLevel(index: Int) {
|
|
||||||
val newStack = _pathStack.value.take(index + 1)
|
|
||||||
_pathStack.value = newStack
|
|
||||||
val newParent = newStack.lastOrNull()?.id
|
|
||||||
loadContentForParent(newParent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun navigateUp() {
|
|
||||||
val newStack = _pathStack.value.dropLast(1)
|
|
||||||
_pathStack.value = newStack
|
|
||||||
val newParentId = newStack.lastOrNull()?.id
|
|
||||||
loadContentForParent(newParentId)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateCollection(collectionToEdit: NoteCollection, name: String) {
|
|
||||||
if(name.isNotEmpty()) {
|
|
||||||
collectionToEdit.name = name
|
|
||||||
viewModelScope.launch {
|
|
||||||
collectionRepository.updateCollection(collectionToEdit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package come.stormborntales.notevault.ui.viewmodel
|
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import come.stormborntales.notevault.data.repository.CollectionRepository
|
|
||||||
import come.stormborntales.notevault.data.repository.NoteRepository
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
class NoteBrowserViewModelFactory (
|
|
||||||
private val noteRepository: NoteRepository,
|
|
||||||
private val collectionRepository: CollectionRepository
|
|
||||||
) : ViewModelProvider.Factory {
|
|
||||||
|
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
|
||||||
if (modelClass.isAssignableFrom(NoteBrowserViewModel::class.java)) {
|
|
||||||
return NoteBrowserViewModel(noteRepository, collectionRepository) as T
|
|
||||||
}
|
|
||||||
throw IllegalArgumentException("Unknown ViewModel class")
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,35 +14,13 @@ import come.stormborntales.notevault.data.repository.NoteRepository
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.InputStream
|
||||||
import androidx.core.graphics.scale
|
import androidx.core.graphics.scale
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
|
|
||||||
class NoteViewModel(
|
class NoteViewModel(
|
||||||
private val repository: NoteRepository,
|
private val repository: NoteRepository,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
// Sucheingabe als StateFlow
|
val notes = repository.allNotes.asLiveData()
|
||||||
val searchQuery = MutableStateFlow("")
|
|
||||||
|
|
||||||
// Alle Notizen als Flow aus der Datenbank (NICHT blockierend!)
|
|
||||||
private val allNotes: Flow<List<NoteEntity>> = repository.allNotes
|
|
||||||
|
|
||||||
// Gefilterte Notizen basierend auf Sucheingabe
|
|
||||||
val filteredNotes: StateFlow<List<NoteEntity>> = combine(searchQuery, allNotes) { query, notes ->
|
|
||||||
if (query.isBlank()) {
|
|
||||||
notes
|
|
||||||
} else {
|
|
||||||
notes.filter {
|
|
||||||
it.title.contains(query, ignoreCase = true) ||
|
|
||||||
it.description?.contains(query, ignoreCase = true) == true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
|
|
||||||
|
|
||||||
|
|
||||||
fun createPreviewImage(context: Context, uri: Uri): File? {
|
fun createPreviewImage(context: Context, uri: Uri): File? {
|
||||||
return try {
|
return try {
|
||||||
@ -61,7 +39,7 @@ class NoteViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addNote(context: Context, title: String, composer: String?, year: Int?, genre: String?, description: String?, selectedUris: List<Uri>, collectionID: Int?, onDone:() -> Unit) {
|
fun addNote(context: Context, title: String, composer: String?, year: Int?, genre: String?, description: String?, selectedUris: List<Uri>, onDone:() -> Unit) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val copiedUris = selectedUris.mapNotNull { uri ->
|
val copiedUris = selectedUris.mapNotNull { uri ->
|
||||||
try {
|
try {
|
||||||
@ -93,8 +71,7 @@ class NoteViewModel(
|
|||||||
year = year,
|
year = year,
|
||||||
genre = genre,
|
genre = genre,
|
||||||
description = description,
|
description = description,
|
||||||
imagePreview = preview_image_path.toString(),
|
imagePreview = preview_image_path.toString()
|
||||||
collectionId = collectionID
|
|
||||||
)
|
)
|
||||||
|
|
||||||
repository.insert(note)
|
repository.insert(note)
|
||||||
@ -109,26 +86,4 @@ class NoteViewModel(
|
|||||||
repository.delete(note)
|
repository.delete(note)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateNote(
|
|
||||||
editedNote: NoteEntity,
|
|
||||||
updatedTitle: String,
|
|
||||||
updatedComposer: String?,
|
|
||||||
updatedYear: Int?,
|
|
||||||
updatedGenre: String?,
|
|
||||||
updatedDescription: String?,
|
|
||||||
onDone: () -> Unit
|
|
||||||
) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
editedNote.title = updatedTitle
|
|
||||||
editedNote.year = updatedYear;
|
|
||||||
editedNote.composer = updatedComposer
|
|
||||||
editedNote.genre = updatedGenre
|
|
||||||
editedNote.description = updatedDescription
|
|
||||||
|
|
||||||
repository.update(editedNote)
|
|
||||||
|
|
||||||
onDone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,12 @@ espressoCore = "3.6.1"
|
|||||||
lifecycleRuntimeKtx = "2.8.7"
|
lifecycleRuntimeKtx = "2.8.7"
|
||||||
activityCompose = "1.8.0"
|
activityCompose = "1.8.0"
|
||||||
composeBom = "2024.04.01"
|
composeBom = "2024.04.01"
|
||||||
materialIconsExtended = "1.7.8"
|
|
||||||
navigationCompose = "2.8.9"
|
navigationCompose = "2.8.9"
|
||||||
room = "2.7.1"
|
room = "2.7.1"
|
||||||
ksp="2.1.21-RC-2.0.0"
|
ksp="2.1.21-RC-2.0.0"
|
||||||
compose = "1.6.0" # oder was immer deine aktuelle Compose-Version ist
|
compose = "1.6.0" # oder was immer deine aktuelle Compose-Version ist
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
|
|
||||||
coil-compose = { group = "io.coil-kt", name = "coil-compose", version = "2.5.0" } # oder aktueller
|
coil-compose = { group = "io.coil-kt", name = "coil-compose", version = "2.5.0" } # oder aktueller
|
||||||
compose-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "compose" }
|
compose-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "compose" }
|
||||||
lifecycle-livedata-ktx = "androidx.lifecycle:lifecycle-livedata-ktx:2.8.7"
|
lifecycle-livedata-ktx = "androidx.lifecycle:lifecycle-livedata-ktx:2.8.7"
|
||||||
|
Loading…
Reference in New Issue
Block a user