Add delete all history with confirm dialog.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-01-21 15:48:07 +01:00
parent 52a73bf204
commit ad0236556e
10 changed files with 110 additions and 30 deletions

View File

@@ -15,7 +15,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
@@ -115,8 +114,23 @@ class MainActivity : BaseActivity() {
NavigationAction { scope.launch { drawerState.open() } } NavigationAction { scope.launch { drawerState.open() } }
} }
composable("history") { composable("history") {
HistoryList(historyViewModel) { navController.navigate("counter") }
mainViewModel.topBarActions = emptyList() var openDialog by remember { mutableStateOf(false) }
HistoryList(historyViewModel, openDialog, { deleteAll ->
if (deleteAll) {
mainViewModel.deleteAllInactiveGames()
}
openDialog = false
}) { navController.navigate("counter") }
mainViewModel.topBarActions = listOf(
TopBarAction(
Icons.Outlined.DeleteForever,
true
) {
openDialog = true
}
)
mainViewModel.topBarIcon = Icons.Outlined.ArrowBack mainViewModel.topBarIcon = Icons.Outlined.ArrowBack
mainViewModel.topBarTitle = stringResource(R.string.menu_history) mainViewModel.topBarTitle = stringResource(R.string.menu_history)
mainViewModel.topBarNavigationAction = mainViewModel.topBarNavigationAction =

View File

@@ -6,6 +6,9 @@ import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface RoundDao : DaoBase<Round> { interface RoundDao : DaoBase<Round> {
@Query("SELECT * FROM round")
fun getAll(): List<Round>
@Query("SELECT * FROM round WHERE gameId is :gameId") @Query("SELECT * FROM round WHERE gameId is :gameId")
fun getAllForGame(gameId: Long?): List<Round> fun getAllForGame(gameId: Long?): List<Round>

View File

@@ -99,4 +99,21 @@ class GameRepository @Inject constructor(
} }
} }
} }
suspend fun deleteAllInactive() {
withContext(Dispatchers.IO) {
try {
gameDao.getAll().take(1).collect() { games ->
val activeId = games.first { it.active }.uid
val gamesToDelete = games.filter { !it.active }
val roundsToDelete = roundDao.getAll().filter { it.gameId != activeId }
gameDao.delete(gamesToDelete)
roundDao.delete(roundsToDelete)
}
} catch (_: NullPointerException) {
}
}
}
} }

View File

@@ -83,4 +83,10 @@ class MainViewModel @Inject constructor(
gameRepository.newGame() gameRepository.newGame()
} }
} }
fun deleteAllInactiveGames() {
viewModelScope.launch {
gameRepository.deleteAllInactive()
}
}
} }

View File

@@ -170,10 +170,9 @@ fun KeyboardTextButton(text: String, onClicked: () -> Unit) {
val screenWidth = configuration.screenWidthDp.dp val screenWidth = configuration.screenWidthDp.dp
val style = if(screenWidth < 350.dp) val style = if (screenWidth < 350.dp) {
{ MaterialTheme.typography.labelSmall
MaterialTheme.typography.labelSmall } else {
}else {
MaterialTheme.typography.labelLarge MaterialTheme.typography.labelLarge
} }

View File

@@ -21,7 +21,8 @@ fun TeamNamesView(
) { ) {
val color = TextFieldDefaults.textFieldColors( val color = TextFieldDefaults.textFieldColors(
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)) containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)
)
Row { Row {
TextField( TextField(

View File

@@ -6,7 +6,6 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.DeleteForever
import androidx.compose.material.icons.outlined.OpenInFull import androidx.compose.material.icons.outlined.OpenInFull
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -22,19 +21,54 @@ import java.util.*
@Composable @Composable
fun HistoryList(viewModel: HistoryViewModel, navigateToCalculator: () -> Unit) { fun HistoryList(
viewModel: HistoryViewModel,
showDeleteDialog: Boolean,
onDialogExecuted: (Boolean) -> Unit,
navigateToCalculator: () -> Unit
) {
DeleteConfirmDialog(showDeleteDialog, onDialogExecuted)
HistoryList(viewModel.gameAndHistory, HistoryList(viewModel.gameAndHistory,
{ {
viewModel.activateGame(it) viewModel.activateGame(it)
navigateToCalculator() navigateToCalculator()
}, },
{viewModel.deleteGame(it)}) { viewModel.deleteGame(it) })
}
@Preview
@Composable
fun DeleteConfirmDialog(show: Boolean = true, onExecuted: (Boolean) -> Unit = {}) {
if (show) {
AlertDialog(
onDismissRequest = { onExecuted(false) },
dismissButton = {
TextButton({ onExecuted(false) })
{
Text(stringResource(R.string.cancel))
}
},
confirmButton = {
TextButton({ onExecuted(true) })
{
Text(stringResource(R.string.ok))
}
},
title = { Text(stringResource(R.string.delete_inactive_title)) },
text = { Text(stringResource(R.string.delete_inactive_text)) },
)
}
} }
@Composable @Composable
fun HistoryList(games: List<GameAndScore>, fun HistoryList(
onOpenClicked: (GameId: Long) -> Unit, games: List<GameAndScore>,
onDeleteClicked: (GameId: Long) -> Unit) { onOpenClicked: (GameId: Long) -> Unit,
onDeleteClicked: (GameId: Long) -> Unit
) {
Row { Row {
LazyColumn { LazyColumn {
items(games) { items(games) {
@@ -48,20 +82,19 @@ fun HistoryList(games: List<GameAndScore>,
fun HistoryListItem( fun HistoryListItem(
game: GameAndScore, game: GameAndScore,
onOpenClicked: (GameId: Long) -> Unit, onOpenClicked: (GameId: Long) -> Unit,
onDeleteClicked: (GameId: Long) -> Unit) { onDeleteClicked: (GameId: Long) -> Unit
) {
val format = val format =
DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault()) DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
val cardColor = if(game.active) val cardColor = if (game.active) {
{
CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.secondaryContainer) CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.secondaryContainer)
} else } else {
{
CardDefaults.cardColors() CardDefaults.cardColors()
} }
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -70,8 +103,9 @@ fun HistoryListItem(
) { ) {
Row( Row(
Modifier Modifier
.padding(all = 12.dp)){ .padding(all = 12.dp)
Column(Modifier.weight(4f)){ ) {
Column(Modifier.weight(4f)) {
Text( Text(
text = game.nameA + " vs " + game.nameB, text = game.nameA + " vs " + game.nameB,
maxLines = 1, maxLines = 1,
@@ -91,13 +125,15 @@ fun HistoryListItem(
Column( Column(
Modifier Modifier
.wrapContentSize() .wrapContentSize()
.width(70.dp)){ .width(70.dp)
) {
ElevatedButton(onClick = { onOpenClicked(game.gameId) }, enabled = true) { ElevatedButton(onClick = { onOpenClicked(game.gameId) }, enabled = true) {
Icon(Icons.Outlined.OpenInFull, null) Icon(Icons.Outlined.OpenInFull, null)
} }
ElevatedButton( ElevatedButton(
onClick = { onDeleteClicked(game.gameId) }, enabled = !game.active ) { onClick = { onDeleteClicked(game.gameId) }, enabled = !game.active
) {
Icon(Icons.Outlined.Delete, null) Icon(Icons.Outlined.Delete, null)
} }
} }

View File

@@ -30,15 +30,13 @@ class HistoryViewModel @Inject constructor(
} }
} }
fun deleteGame(gameId: Long) fun deleteGame(gameId: Long) {
{
viewModelScope.launch { viewModelScope.launch {
gameRepository.deleteGame(gameId) gameRepository.deleteGame(gameId)
} }
} }
fun activateGame(gameId: Long) fun activateGame(gameId: Long) {
{
viewModelScope.launch { viewModelScope.launch {
gameRepository.setActive(gameId) gameRepository.setActive(gameId)
} }

View File

@@ -15,6 +15,9 @@
<string name="newGame">Neues Spiel</string> <string name="newGame">Neues Spiel</string>
<string name="created">"Erstellt: %s "</string> <string name="created">"Erstellt: %s "</string>
<string name="modified">Bearbeitet: %s</string> <string name="modified">Bearbeitet: %s</string>
<string name="delete_all">Alle löschen</string> <string name="delete_inactive_title">Verlauf löschen</string>
<string name="delete_inactive_text">Wirklich den gesamten Verlauf löschen? Diese Aktion kann nicht rückgängig gemacht werden.</string>
<string name="cancel">Abbrechen</string>
<string name="ok">Ok</string>
</resources> </resources>

View File

@@ -18,5 +18,8 @@
<string name="newGame">New Game</string> <string name="newGame">New Game</string>
<string name="created">Created: %s</string> <string name="created">Created: %s</string>
<string name="modified">Modified: %s</string> <string name="modified">Modified: %s</string>
<string name="delete_all">Delete all</string> <string name="delete_inactive_title">Delete history</string>
<string name="delete_inactive_text">You really want to delete the the history? This action can\'t be undone.</string>
<string name="cancel">Cancel</string>
<string name="ok">Ok</string>
</resources> </resources>