ADD: Breadcrumbs + navigation with "Zurücktaste"

This commit is contained in:
sebastian 2025-05-10 11:34:16 +02:00
parent a61493c272
commit 828a4e0fd3
3 changed files with 75 additions and 3 deletions

View File

@ -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-03T08:34:29.354537334Z"> <DropdownSelection timestamp="2025-05-10T09:28:03.000292036Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=R52N50NLGRT" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=R52N50NLGRT" />

View File

@ -1,11 +1,14 @@
package come.stormborntales.notevault.ui.screens package come.stormborntales.notevault.ui.screens
import android.util.Log import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
@ -37,6 +40,7 @@ import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import come.stormborntales.notevault.data.local.AppDatabase import come.stormborntales.notevault.data.local.AppDatabase
import come.stormborntales.notevault.data.local.entity.NoteCollection
import come.stormborntales.notevault.data.repository.CollectionRepository 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.viewmodel.NoteBrowserViewModel import come.stormborntales.notevault.ui.viewmodel.NoteBrowserViewModel
@ -97,6 +101,39 @@ fun CreateCollectionDialog(
) )
} }
@Composable
fun CollectionBreadcrumbs(
path: List<NoteCollection>,
onNavigateTo: (index: Int) -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Start",
modifier = Modifier
.clickable { onNavigateTo(-1) }
.padding(horizontal = 4.dp),
style = MaterialTheme.typography.labelLarge
)
path.forEachIndexed { index, collection ->
Text(" / ", style = MaterialTheme.typography.labelLarge)
Text(
text = collection.name,
modifier = Modifier
.clickable { onNavigateTo(index) }
.padding(horizontal = 4.dp),
style = MaterialTheme.typography.labelLarge
)
}
}
}
@Composable @Composable
fun NotesScreen( fun NotesScreen(
collectionRepository: CollectionRepository, collectionRepository: CollectionRepository,
@ -145,6 +182,19 @@ fun NotesScreen(
} }
}, },
content = { innerPadding -> content = { innerPadding ->
val path by viewModel.pathStack.collectAsState()
BackHandler(enabled = path.isNotEmpty()) {
viewModel.navigateUp()
}
CollectionBreadcrumbs(
path = path,
onNavigateTo = { index ->
if (index == -1) viewModel.loadContentForParent(null)
else viewModel.navigateToLevel(index)
}
)
LazyColumn( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -162,7 +212,7 @@ fun NotesScreen(
ListItem( ListItem(
headlineContent = { Text(collection.name) }, headlineContent = { Text(collection.name) },
modifier = Modifier modifier = Modifier
.clickable { viewModel.loadContentForParent(collection.id) } .clickable { viewModel.loadContentForParent(collection.id, collection) }
.padding(horizontal = 8.dp) .padding(horizontal = 8.dp)
) )
} }

View File

@ -24,11 +24,14 @@ class NoteBrowserViewModel (
private val _currentParentId = MutableStateFlow<Int?>(null) private val _currentParentId = MutableStateFlow<Int?>(null)
val currentParentId: StateFlow<Int?> = _currentParentId.asStateFlow() val currentParentId: StateFlow<Int?> = _currentParentId.asStateFlow()
private val _pathStack = MutableStateFlow<List<NoteCollection>>(emptyList())
val pathStack: StateFlow<List<NoteCollection>> = _pathStack.asStateFlow()
init { init {
loadContentForParent(null) loadContentForParent(null)
} }
fun loadContentForParent(parentId: Int?) { fun loadContentForParent(parentId: Int?, selectedCollection: NoteCollection? = null) {
_currentParentId.value = parentId _currentParentId.value = parentId
viewModelScope.launch { viewModelScope.launch {
launch { launch {
@ -41,6 +44,11 @@ class NoteBrowserViewModel (
_currentNotes.value = it _currentNotes.value = it
} }
} }
if (selectedCollection != null) {
_pathStack.value = _pathStack.value + selectedCollection
} else if (parentId == null) {
_pathStack.value = emptyList()
}
} }
} }
@ -51,4 +59,18 @@ class NoteBrowserViewModel (
loadContentForParent(_currentParentId.value) loadContentForParent(_currentParentId.value)
} }
} }
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)
}
} }