nextNoteVault #23

Merged
sebastian merged 57 commits from nextNoteVault into master 2025-05-10 06:23:23 +00:00
4 changed files with 97 additions and 11 deletions
Showing only changes of commit ad8e180134 - Show all commits

View File

@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-05-03T08:26:48.052108137Z"> <DropdownSelection timestamp="2025-05-03T08:34:29.354537334Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/home/sebastian/.android/avd/Small_Phone_API_36.avd" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=R52N50NLGRT" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

View File

@ -7,10 +7,15 @@ 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.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.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.DrawerValue import androidx.compose.material3.DrawerValue
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@ -21,15 +26,19 @@ import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.NavigationDrawerItemDefaults import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.rememberDrawerState import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier 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.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.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController 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.local.entity.NoteEntity
@ -109,13 +118,69 @@ class MainActivity : ComponentActivity() {
) { ) {
Scaffold( Scaffold(
topBar = { topBar = {
var searchQuery by remember { mutableStateOf("") }
var isMenuExpanded by remember { mutableStateOf(false) }
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
TopAppBar( TopAppBar(
title = { Text("NoteVault") }, 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 = { navigationIcon = {
IconButton(onClick = { IconButton(onClick = { scope.launch { drawerState.open() } }) {
scope.launch { drawerState.open() } Icon(Icons.Default.Menu, contentDescription = "Menü öffnen")
}) { }
Icon(Icons.Default.Menu, contentDescription = "Menu") },
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
}
)
}
} }
} }
) )
@ -179,7 +244,5 @@ class MainActivity : ComponentActivity() {
} }
} }
} }
} }
} }

View File

@ -242,7 +242,7 @@ fun MainScreen(
viewModel: NoteViewModel, viewModel: NoteViewModel,
onEditNote: (NoteEntity) -> Unit onEditNote: (NoteEntity) -> Unit
) { ) {
val notes by viewModel.notes.observeAsState(emptyList()) val notes by viewModel.filteredNotes.collectAsState(initial = emptyList())
Scaffold( Scaffold(
floatingActionButton = { floatingActionButton = {
FloatingActionButton( FloatingActionButton(

View File

@ -15,11 +15,34 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File
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() {
val notes = repository.allNotes.asLiveData() // Sucheingabe als StateFlow
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 {