nextNoteVault #23
@ -4,10 +4,10 @@
 | 
			
		||||
    <selectionStates>
 | 
			
		||||
      <SelectionState runConfigName="app">
 | 
			
		||||
        <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">
 | 
			
		||||
            <handle>
 | 
			
		||||
              <DeviceId pluginId="LocalEmulator" identifier="path=/home/sebastian/.android/avd/Small_Phone_API_36.avd" />
 | 
			
		||||
              <DeviceId pluginId="PhysicalDevice" identifier="serial=R52N50NLGRT" />
 | 
			
		||||
            </handle>
 | 
			
		||||
          </Target>
 | 
			
		||||
        </DropdownSelection>
 | 
			
		||||
 | 
			
		||||
@ -7,10 +7,15 @@ import androidx.activity.ComponentActivity
 | 
			
		||||
import androidx.activity.compose.rememberLauncherForActivityResult
 | 
			
		||||
import androidx.activity.compose.setContent
 | 
			
		||||
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
 | 
			
		||||
@ -21,15 +26,19 @@ 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.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.graphics.Color
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
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.entity.NoteEntity
 | 
			
		||||
@ -109,13 +118,69 @@ class MainActivity : ComponentActivity() {
 | 
			
		||||
                ) {
 | 
			
		||||
                    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 = { 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 = {
 | 
			
		||||
                                    IconButton(onClick = {
 | 
			
		||||
                                        scope.launch { drawerState.open() }
 | 
			
		||||
                                    }) {
 | 
			
		||||
                                        Icon(Icons.Default.Menu, contentDescription = "Menu")
 | 
			
		||||
                                    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
 | 
			
		||||
                                                }
 | 
			
		||||
                                            )
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            )
 | 
			
		||||
@ -179,7 +244,5 @@ class MainActivity : ComponentActivity() {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -242,7 +242,7 @@ fun MainScreen(
 | 
			
		||||
    viewModel: NoteViewModel,
 | 
			
		||||
    onEditNote: (NoteEntity) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    val notes by viewModel.notes.observeAsState(emptyList())
 | 
			
		||||
    val notes by viewModel.filteredNotes.collectAsState(initial = emptyList())
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        floatingActionButton = {
 | 
			
		||||
            FloatingActionButton(
 | 
			
		||||
 | 
			
		||||
@ -15,11 +15,34 @@ import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import java.io.File
 | 
			
		||||
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(
 | 
			
		||||
    private val repository: NoteRepository,
 | 
			
		||||
) : 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? {
 | 
			
		||||
       return try {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user