Fix: Behebe Build-Kompilierungsfehler und committe alle ausstehenden Änderungen
Dieser Commit behebt die Kompilierungsfehler, die während des Build-Prozesses aufgetreten sind. Im Einzelnen: - Der nicht aufgelöste Verweis auf `saveItem` in `ShoppingListsScreen.kt` wurde korrigiert, indem er in `saveShoppingListItem` geändert wurde. - Der Fehler `No value passed for parameter 'item'` in `ShoppingListsScreen.kt` wurde behoben, indem `itemDetails.toShoppingListItem()` korrekt an `viewModel.saveShoppingListItem()` übergeben wurde. Zusätzlich sind alle anderen ausstehenden Änderungen im Arbeitsverzeichnis, wie gewünscht, in diesem Commit enthalten.
This commit is contained in:
@@ -11,17 +11,93 @@ interface NoteshopRepository {
|
||||
*/
|
||||
fun getAllNotesStream(): Flow<List<Note>>
|
||||
|
||||
/**
|
||||
* Retrieve a specific note from the data source.
|
||||
*/
|
||||
fun getNoteStream(id: Int): Flow<Note?>
|
||||
|
||||
/**
|
||||
* Insert note in the data source
|
||||
*/
|
||||
suspend fun insertNote(note: Note)
|
||||
|
||||
/**
|
||||
* Update note in the data source
|
||||
*/
|
||||
suspend fun updateNote(note: Note)
|
||||
|
||||
/**
|
||||
* Delete note from the data source
|
||||
*/
|
||||
suspend fun deleteNote(note: Note)
|
||||
|
||||
/**
|
||||
* Retrieve all the shopping lists with their items from the data source.
|
||||
*/
|
||||
fun getAllShoppingListsWithItemsStream(): Flow<List<ShoppingListWithItems>>
|
||||
|
||||
// Add other necessary methods for inserting, updating, deleting data
|
||||
/**
|
||||
* Retrieve a specific shopping list with its items from the data source.
|
||||
*/
|
||||
fun getShoppingListWithItemsStream(listId: Int): Flow<ShoppingListWithItems?>
|
||||
|
||||
/**
|
||||
* Insert shopping list in the data source
|
||||
*/
|
||||
suspend fun insertShoppingList(list: ShoppingList)
|
||||
|
||||
/**
|
||||
* Update shopping list in the data source
|
||||
*/
|
||||
suspend fun updateShoppingList(list: ShoppingList)
|
||||
|
||||
/**
|
||||
* Delete shopping list from the data source
|
||||
*/
|
||||
suspend fun deleteShoppingList(list: ShoppingList)
|
||||
|
||||
/**
|
||||
* Insert shopping list item in the data source
|
||||
*/
|
||||
suspend fun insertShoppingListItem(item: ShoppingListItem)
|
||||
|
||||
/**
|
||||
* Update shopping list item in the data source
|
||||
*/
|
||||
suspend fun updateShoppingListItem(item: ShoppingListItem)
|
||||
|
||||
/**
|
||||
* Delete shopping list item from the data source
|
||||
*/
|
||||
suspend fun deleteShoppingListItem(item: ShoppingListItem)
|
||||
|
||||
}
|
||||
|
||||
class OfflineNoteshopRepository(private val noteDao: NoteDao, private val shoppingListDao: ShoppingListDao) : NoteshopRepository {
|
||||
override fun getAllNotesStream(): Flow<List<Note>> = noteDao.getAllNotes()
|
||||
|
||||
override fun getNoteStream(id: Int): Flow<Note?> = noteDao.getNote(id)
|
||||
|
||||
override suspend fun insertNote(note: Note) = noteDao.insert(note)
|
||||
|
||||
override suspend fun updateNote(note: Note) = noteDao.update(note)
|
||||
|
||||
override suspend fun deleteNote(note: Note) = noteDao.delete(note)
|
||||
|
||||
override fun getAllShoppingListsWithItemsStream(): Flow<List<ShoppingListWithItems>> = shoppingListDao.getListsWithItems()
|
||||
|
||||
override fun getShoppingListWithItemsStream(listId: Int): Flow<ShoppingListWithItems?> = shoppingListDao.getListWithItems(listId)
|
||||
|
||||
override suspend fun insertShoppingList(list: ShoppingList) = shoppingListDao.insertList(list)
|
||||
|
||||
override suspend fun updateShoppingList(list: ShoppingList) = shoppingListDao.updateList(list)
|
||||
|
||||
override suspend fun deleteShoppingList(list: ShoppingList) = shoppingListDao.deleteList(list)
|
||||
|
||||
override suspend fun insertShoppingListItem(item: ShoppingListItem) = shoppingListDao.insertItem(item)
|
||||
|
||||
override suspend fun updateShoppingListItem(item: ShoppingListItem) = shoppingListDao.updateItem(item)
|
||||
|
||||
override suspend fun deleteShoppingListItem(item: ShoppingListItem) = shoppingListDao.deleteItem(item)
|
||||
|
||||
}
|
||||
@@ -1,28 +1,166 @@
|
||||
package de.lxtools.noteshop.ui.notes
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
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.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.lxtools.noteshop.AppViewModelProvider
|
||||
import de.lxtools.noteshop.R
|
||||
import de.lxtools.noteshop.data.Note
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun NotesScreen(viewModel: NotesViewModel, modifier: Modifier = Modifier) {
|
||||
fun NotesScreen(viewModel: NotesViewModel = viewModel(factory = AppViewModelProvider.Factory), modifier: Modifier = Modifier) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
val noteDetails by viewModel.noteDetails.collectAsState()
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(text = "Anzahl der Notizen: ${uiState.noteList.size}")
|
||||
// TODO: Implement LazyColumn to display actual notes
|
||||
uiState.noteList.forEach { note ->
|
||||
Text(text = "- ${note.title}: ${note.content}")
|
||||
Scaffold(
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(onClick = {
|
||||
viewModel.resetNoteDetails()
|
||||
showDialog = true
|
||||
}) {
|
||||
Icon(Icons.Default.Add, contentDescription = stringResource(R.string.add_note))
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
if (uiState.noteList.isEmpty()) {
|
||||
Text(text = stringResource(R.string.no_notes_yet))
|
||||
} else {
|
||||
LazyColumn {
|
||||
items(uiState.noteList) { note ->
|
||||
NoteCard(
|
||||
note = note,
|
||||
onEdit = {
|
||||
viewModel.updateNoteDetails(it)
|
||||
showDialog = true
|
||||
},
|
||||
onDelete = {
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteNote(it)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showDialog) {
|
||||
NoteInputDialog(
|
||||
noteDetails = noteDetails,
|
||||
onValueChange = viewModel::updateNoteDetails,
|
||||
onSave = {
|
||||
coroutineScope.launch {
|
||||
viewModel.saveNote()
|
||||
showDialog = false
|
||||
viewModel.resetNoteDetails()
|
||||
}
|
||||
},
|
||||
onDismiss = { showDialog = false },
|
||||
isNewNote = noteDetails.id == 0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NoteCard(note: Note, onEdit: (Note) -> Unit, onDelete: (Note) -> Unit, modifier: Modifier = Modifier) {
|
||||
Card(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp)
|
||||
.clickable { onEdit(note) }
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text(text = note.title, style = MaterialTheme.typography.titleMedium)
|
||||
Text(text = note.content, style = MaterialTheme.typography.bodyMedium)
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
|
||||
TextButton(onClick = { onDelete(note) }) {
|
||||
Text(stringResource(R.string.delete))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun NoteInputDialog(
|
||||
noteDetails: NoteDetails,
|
||||
onValueChange: (NoteDetails) -> Unit,
|
||||
onSave: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
isNewNote: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(text = if (isNewNote) stringResource(R.string.add_note) else stringResource(R.string.edit_note)) },
|
||||
text = {
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
value = noteDetails.title,
|
||||
onValueChange = { onValueChange(noteDetails.copy(title = it)) },
|
||||
label = { Text(stringResource(R.string.note_title)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = noteDetails.content,
|
||||
onValueChange = { onValueChange(noteDetails.copy(content = it)) },
|
||||
label = { Text(stringResource(R.string.note_content)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Button(onClick = onSave, enabled = noteDetails.isValid()) {
|
||||
Text(stringResource(R.string.save))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
@@ -4,12 +4,15 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.lxtools.noteshop.data.Note
|
||||
import de.lxtools.noteshop.data.NoteshopRepository
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class NotesViewModel(noteshopRepository: NoteshopRepository) : ViewModel() {
|
||||
class NotesViewModel(private val noteshopRepository: NoteshopRepository) : ViewModel() {
|
||||
|
||||
val uiState: StateFlow<NotesUiState> = noteshopRepository.getAllNotesStream().map { NotesUiState(it) }
|
||||
.stateIn(
|
||||
@@ -18,6 +21,35 @@ class NotesViewModel(noteshopRepository: NoteshopRepository) : ViewModel() {
|
||||
initialValue = NotesUiState()
|
||||
)
|
||||
|
||||
private val _noteDetails = MutableStateFlow(NoteDetails())
|
||||
val noteDetails: StateFlow<NoteDetails> = _noteDetails.asStateFlow()
|
||||
|
||||
fun updateNoteDetails(note: Note) {
|
||||
_noteDetails.value = NoteDetails(
|
||||
id = note.id,
|
||||
title = note.title,
|
||||
content = note.content
|
||||
)
|
||||
}
|
||||
|
||||
fun updateNoteDetails(noteDetails: NoteDetails) {
|
||||
_noteDetails.value = noteDetails
|
||||
}
|
||||
|
||||
suspend fun saveNote() {
|
||||
if (noteDetails.value.isValid()) {
|
||||
noteshopRepository.insertNote(noteDetails.value.toNote())
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteNote(note: Note) {
|
||||
noteshopRepository.deleteNote(note)
|
||||
}
|
||||
|
||||
fun resetNoteDetails() {
|
||||
_noteDetails.value = NoteDetails()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TIMEOUT_MILLIS = 5_000L
|
||||
}
|
||||
@@ -25,4 +57,20 @@ class NotesViewModel(noteshopRepository: NoteshopRepository) : ViewModel() {
|
||||
|
||||
data class NotesUiState(
|
||||
val noteList: List<Note> = listOf()
|
||||
)
|
||||
)
|
||||
|
||||
data class NoteDetails(
|
||||
val id: Int = 0,
|
||||
val title: String = "",
|
||||
val content: String = ""
|
||||
) {
|
||||
fun toNote(): Note = Note(
|
||||
id = id,
|
||||
title = title,
|
||||
content = content
|
||||
)
|
||||
|
||||
fun isValid(): Boolean {
|
||||
return title.isNotBlank() && content.isNotBlank()
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,295 @@
|
||||
package de.lxtools.noteshop.ui.shopping
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
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.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
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.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.lxtools.noteshop.AppViewModelProvider
|
||||
import de.lxtools.noteshop.R
|
||||
import de.lxtools.noteshop.data.ShoppingList
|
||||
import de.lxtools.noteshop.data.ShoppingListItem
|
||||
import de.lxtools.noteshop.data.ShoppingListWithItems
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ShoppingListsScreen(viewModel: ShoppingListsViewModel, modifier: Modifier = Modifier) {
|
||||
fun ShoppingListsScreen(viewModel: ShoppingListsViewModel = viewModel(factory = AppViewModelProvider.Factory), modifier: Modifier = Modifier) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
val listDetails by viewModel.listDetails.collectAsState()
|
||||
val itemDetails by viewModel.itemDetails.collectAsState()
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(text = "Anzahl der Einkaufslisten: ${uiState.shoppingLists.size}")
|
||||
// TODO: Implement LazyColumn to display actual shopping lists
|
||||
uiState.shoppingLists.forEach { listWithItems ->
|
||||
Text(text = "- ${listWithItems.shoppingList.name} (${listWithItems.items.size} Artikel)")
|
||||
var showListDialog by remember { mutableStateOf(false) }
|
||||
var showItemDialog by remember { mutableStateOf(false) }
|
||||
var currentSelectedListId by remember { mutableStateOf(0) }
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
Scaffold(
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(onClick = {
|
||||
viewModel.resetListDetails()
|
||||
showListDialog = true
|
||||
}) {
|
||||
Icon(Icons.Default.Add, contentDescription = stringResource(R.string.add_shopping_list))
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
if (uiState.shoppingLists.isEmpty()) {
|
||||
Text(text = stringResource(R.string.no_shopping_lists_yet))
|
||||
} else {
|
||||
LazyColumn {
|
||||
items(uiState.shoppingLists) { listWithItems ->
|
||||
ShoppingListCard(
|
||||
listWithItems = listWithItems,
|
||||
onEditList = {
|
||||
viewModel.updateListDetails(it.shoppingList)
|
||||
showListDialog = true
|
||||
},
|
||||
onDeleteList = {
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteList(it.shoppingList)
|
||||
}
|
||||
},
|
||||
onAddItem = {
|
||||
currentSelectedListId = it.shoppingList.id
|
||||
viewModel.resetItemDetails(it.shoppingList.id)
|
||||
showItemDialog = true
|
||||
},
|
||||
onEditItem = {
|
||||
viewModel.updateItemDetails(it)
|
||||
showItemDialog = true
|
||||
},
|
||||
onToggleItemChecked = {
|
||||
coroutineScope.launch {
|
||||
viewModel.saveShoppingListItem(it.copy(isChecked = !it.isChecked))
|
||||
}
|
||||
},
|
||||
onDeleteItem = {
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteItem(it)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showListDialog) {
|
||||
ShoppingListInputDialog(
|
||||
listDetails = listDetails,
|
||||
onValueChange = viewModel::updateListDetails,
|
||||
onSave = {
|
||||
coroutineScope.launch {
|
||||
viewModel.saveList()
|
||||
showListDialog = false
|
||||
viewModel.resetListDetails()
|
||||
}
|
||||
},
|
||||
onDismiss = { showListDialog = false },
|
||||
isNewList = listDetails.id == 0
|
||||
)
|
||||
}
|
||||
|
||||
if (showItemDialog) {
|
||||
ShoppingListItemInputDialog(
|
||||
itemDetails = itemDetails,
|
||||
onValueChange = viewModel::updateItemDetails,
|
||||
onSave = {
|
||||
coroutineScope.launch {
|
||||
viewModel.saveShoppingListItem(itemDetails.toShoppingListItem())
|
||||
showItemDialog = false
|
||||
viewModel.resetItemDetails(currentSelectedListId)
|
||||
}
|
||||
},
|
||||
onDismiss = { showItemDialog = false },
|
||||
isNewItem = itemDetails.id == 0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShoppingListCard(
|
||||
listWithItems: ShoppingListWithItems,
|
||||
onEditList: (ShoppingListWithItems) -> Unit,
|
||||
onDeleteList: (ShoppingListWithItems) -> Unit,
|
||||
onAddItem: (ShoppingListWithItems) -> Unit,
|
||||
onEditItem: (ShoppingListItem) -> Unit,
|
||||
onToggleItemChecked: (ShoppingListItem) -> Unit,
|
||||
onDeleteItem: (ShoppingListItem) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = listWithItems.shoppingList.name,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
TextButton(onClick = { onEditList(listWithItems) }) {
|
||||
Text(stringResource(R.string.edit))
|
||||
}
|
||||
TextButton(onClick = { onDeleteList(listWithItems) }) {
|
||||
Text(stringResource(R.string.delete))
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(text = stringResource(R.string.items_in_list))
|
||||
listWithItems.items.forEach { item ->
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Checkbox(
|
||||
checked = item.isChecked,
|
||||
onCheckedChange = { onToggleItemChecked(item) }
|
||||
)
|
||||
Text(
|
||||
text = item.name,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.clickable { onEditItem(item) }
|
||||
)
|
||||
TextButton(onClick = { onDeleteItem(item) }) {
|
||||
Text(stringResource(R.string.delete))
|
||||
}
|
||||
}
|
||||
}
|
||||
Button(onClick = { onAddItem(listWithItems) }, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(stringResource(R.string.add_item))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ShoppingListInputDialog(
|
||||
listDetails: ShoppingListDetails,
|
||||
onValueChange: (ShoppingListDetails) -> Unit,
|
||||
onSave: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
isNewList: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(text = if (isNewList) stringResource(R.string.add_shopping_list) else stringResource(R.string.edit_shopping_list)) },
|
||||
text = {
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
value = listDetails.name,
|
||||
onValueChange = { onValueChange(listDetails.copy(name = it)) },
|
||||
label = { Text(stringResource(R.string.list_name)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Button(onClick = onSave, enabled = listDetails.isValid()) {
|
||||
Text(stringResource(R.string.save))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ShoppingListItemInputDialog(
|
||||
itemDetails: ShoppingListItemDetails,
|
||||
onValueChange: (ShoppingListItemDetails) -> Unit,
|
||||
onSave: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
isNewItem: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(text = if (isNewItem) stringResource(R.string.add_item) else stringResource(R.string.edit_item)) },
|
||||
text = {
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
value = itemDetails.name,
|
||||
onValueChange = { onValueChange(itemDetails.copy(name = it)) },
|
||||
label = { Text(stringResource(R.string.item_name)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
// Checkbox for isChecked status
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(
|
||||
checked = itemDetails.isChecked,
|
||||
onCheckedChange = { onValueChange(itemDetails.copy(isChecked = it)) }
|
||||
)
|
||||
Text(stringResource(R.string.item_checked))
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Button(onClick = onSave, enabled = itemDetails.isValid()) {
|
||||
Text(stringResource(R.string.save))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
@@ -3,13 +3,18 @@ package de.lxtools.noteshop.ui.shopping
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.lxtools.noteshop.data.NoteshopRepository
|
||||
import de.lxtools.noteshop.data.ShoppingList
|
||||
import de.lxtools.noteshop.data.ShoppingListItem
|
||||
import de.lxtools.noteshop.data.ShoppingListWithItems
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ShoppingListsViewModel(noteshopRepository: NoteshopRepository) : ViewModel() {
|
||||
class ShoppingListsViewModel(private val noteshopRepository: NoteshopRepository) : ViewModel() {
|
||||
|
||||
val uiState: StateFlow<ShoppingListsUiState> = noteshopRepository.getAllShoppingListsWithItemsStream().map { ShoppingListsUiState(it) }
|
||||
.stateIn(
|
||||
@@ -18,6 +23,64 @@ class ShoppingListsViewModel(noteshopRepository: NoteshopRepository) : ViewModel
|
||||
initialValue = ShoppingListsUiState()
|
||||
)
|
||||
|
||||
private val _listDetails = MutableStateFlow(ShoppingListDetails())
|
||||
val listDetails: StateFlow<ShoppingListDetails> = _listDetails.asStateFlow()
|
||||
|
||||
private val _itemDetails = MutableStateFlow(ShoppingListItemDetails())
|
||||
val itemDetails: StateFlow<ShoppingListItemDetails> = _itemDetails.asStateFlow()
|
||||
|
||||
fun updateListDetails(list: ShoppingList) {
|
||||
_listDetails.value = ShoppingListDetails(
|
||||
id = list.id,
|
||||
name = list.name
|
||||
)
|
||||
}
|
||||
|
||||
fun updateListDetails(listDetails: ShoppingListDetails) {
|
||||
_listDetails.value = listDetails
|
||||
}
|
||||
|
||||
suspend fun saveList() {
|
||||
if (listDetails.value.isValid()) {
|
||||
noteshopRepository.insertShoppingList(listDetails.value.toShoppingList())
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteList(list: ShoppingList) {
|
||||
noteshopRepository.deleteShoppingList(list)
|
||||
}
|
||||
|
||||
fun resetListDetails() {
|
||||
_listDetails.value = ShoppingListDetails()
|
||||
}
|
||||
|
||||
fun updateItemDetails(item: ShoppingListItem) {
|
||||
_itemDetails.value = ShoppingListItemDetails(
|
||||
id = item.id,
|
||||
name = item.name,
|
||||
isChecked = item.isChecked,
|
||||
listId = item.listId
|
||||
)
|
||||
}
|
||||
|
||||
fun updateItemDetails(itemDetails: ShoppingListItemDetails) {
|
||||
_itemDetails.value = itemDetails
|
||||
}
|
||||
|
||||
suspend fun saveShoppingListItem(item: ShoppingListItem) {
|
||||
if (item.name.isNotBlank()) {
|
||||
noteshopRepository.insertShoppingListItem(item)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteItem(item: ShoppingListItem) {
|
||||
noteshopRepository.deleteShoppingListItem(item)
|
||||
}
|
||||
|
||||
fun resetItemDetails(listId: Int) {
|
||||
_itemDetails.value = ShoppingListItemDetails(listId = listId)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TIMEOUT_MILLIS = 5_000L
|
||||
}
|
||||
@@ -25,4 +88,36 @@ class ShoppingListsViewModel(noteshopRepository: NoteshopRepository) : ViewModel
|
||||
|
||||
data class ShoppingListsUiState(
|
||||
val shoppingLists: List<ShoppingListWithItems> = listOf()
|
||||
)
|
||||
)
|
||||
|
||||
data class ShoppingListDetails(
|
||||
val id: Int = 0,
|
||||
val name: String = ""
|
||||
) {
|
||||
fun toShoppingList(): ShoppingList = ShoppingList(
|
||||
id = id,
|
||||
name = name
|
||||
)
|
||||
|
||||
fun isValid(): Boolean {
|
||||
return name.isNotBlank()
|
||||
}
|
||||
}
|
||||
|
||||
data class ShoppingListItemDetails(
|
||||
val id: Int = 0,
|
||||
val name: String = "",
|
||||
val isChecked: Boolean = false,
|
||||
val listId: Int = 0
|
||||
) {
|
||||
fun toShoppingListItem(): ShoppingListItem = ShoppingListItem(
|
||||
id = id,
|
||||
name = name,
|
||||
isChecked = isChecked,
|
||||
listId = listId
|
||||
)
|
||||
|
||||
fun isValid(): Boolean {
|
||||
return name.isNotBlank() && listId != 0
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,24 @@
|
||||
<string name="menu_notes">Notizen</string>
|
||||
<string name="menu_shopping_lists">Einkaufslisten</string>
|
||||
<string name="menu_open">Menü öffnen</string>
|
||||
|
||||
<string name="add_note">Notiz hinzufügen</string>
|
||||
<string name="edit_note">Notiz bearbeiten</string>
|
||||
<string name="delete">Löschen</string>
|
||||
<string name="no_notes_yet">Noch keine Notizen. Klicke auf + um eine hinzuzufügen!</string>
|
||||
<string name="note_title">Titel</string>
|
||||
<string name="note_content">Inhalt</string>
|
||||
<string name="save">Speichern</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
|
||||
<string name="add_shopping_list">Einkaufsliste hinzufügen</string>
|
||||
<string name="edit_shopping_list">Einkaufsliste bearbeiten</string>
|
||||
<string name="no_shopping_lists_yet">Noch keine Einkaufslisten. Klicke auf + um eine hinzuzufügen!</string>
|
||||
<string name="list_name">Listenname</string>
|
||||
<string name="items_in_list">Artikel in Liste:</string>
|
||||
<string name="add_item">Artikel hinzufügen</string>
|
||||
<string name="edit_item">Artikel bearbeiten</string>
|
||||
<string name="item_name">Artikelname</string>
|
||||
<string name="item_checked">Abgehakt</string>
|
||||
<string name="edit">Bearbeiten</string>
|
||||
</resources>
|
||||
@@ -4,4 +4,24 @@
|
||||
<string name="menu_notes">Notes</string>
|
||||
<string name="menu_shopping_lists">Shopping Lists</string>
|
||||
<string name="menu_open">Open menu</string>
|
||||
|
||||
<string name="add_note">Add Note</string>
|
||||
<string name="edit_note">Edit Note</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="no_notes_yet">No notes yet. Click + to add one!</string>
|
||||
<string name="note_title">Title</string>
|
||||
<string name="note_content">Content</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
|
||||
<string name="add_shopping_list">Add Shopping List</string>
|
||||
<string name="edit_shopping_list">Edit Shopping List</string>
|
||||
<string name="no_shopping_lists_yet">No shopping lists yet. Click + to add one!</string>
|
||||
<string name="list_name">List Name</string>
|
||||
<string name="items_in_list">Items in List:</string>
|
||||
<string name="add_item">Add Item</string>
|
||||
<string name="edit_item">Edit Item</string>
|
||||
<string name="item_name">Item Name</string>
|
||||
<string name="item_checked">Checked</string>
|
||||
<string name="edit">Edit</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user