Add instrumented test to test repository together with room database. Improve data handling on first boot.
Some checks failed
continuous-integration/drone/push Build was killed

This commit is contained in:
2023-02-17 15:19:00 +01:00
parent 4108512139
commit a611de6da4
9 changed files with 331 additions and 80 deletions

View File

@@ -1,9 +1,6 @@
package me.zobrist.tichucounter.data
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Update
import androidx.room.*
@Dao
interface DaoBase<T> {

View File

@@ -12,7 +12,7 @@ interface GameDao : DaoBase<Game> {
fun getAll(): Flow<List<Game>>
@Transaction
@Query("SELECT * FROM game where uid ")
@Query("SELECT * FROM game")
fun getGamesWithRounds(): Flow<List<GameWithScores>>
@Transaction
@@ -20,10 +20,13 @@ interface GameDao : DaoBase<Game> {
fun getActiveWithRounds(): Flow<GameWithScores?>
@Query("SELECT * FROM game WHERE uid is :gameId")
fun getGameById(gameId: Long): Flow<Game>
fun getGameById(gameId: Long): Game
@Query("SELECT * FROM game WHERE active is 1")
fun getActive(): Flow<Game?>
fun getActiveAsFlow(): Flow<Game?>
@Query("SELECT * FROM game WHERE active is 1")
fun getActive(): Game?
@Query("UPDATE game SET active = 1 WHERE uid is :gameId;")

View File

@@ -5,13 +5,14 @@ import androidx.room.Entity
import androidx.room.Relation
import me.zobrist.tichucounter.data.entity.Game
import me.zobrist.tichucounter.data.entity.Round
import java.util.*
@Entity
data class GameWithScores(
@Embedded val game: Game,
@Embedded val game: Game = Game(),
@Relation(
parentColumn = "uid",
entityColumn = "gameId"
)
val rounds: List<Round>
val rounds: List<Round> = emptyList()
)

View File

@@ -6,10 +6,10 @@ import java.util.*
@Entity
data class Game(
var active: Boolean,
var nameA: String,
var nameB: String,
val created: Date,
var modified: Date,
var active: Boolean = true,
var nameA: String = "TeamA",
var nameB: String = "TeamB",
val created: Date = Date(),
var modified: Date = Date(),
@PrimaryKey(autoGenerate = true) override val uid: Long = 0
) : IEntity

View File

@@ -1,11 +1,7 @@
package me.zobrist.tichucounter.repository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import me.zobrist.tichucounter.data.GameDao
import me.zobrist.tichucounter.data.GameWithScores
import me.zobrist.tichucounter.data.RoundDao
@@ -19,20 +15,15 @@ class GameRepository @Inject constructor(
private val roundDao: RoundDao
) {
private var _activeGame: Game? = null
val activeGame: Game
get() {
return _activeGame!!
}
private var activeGame: Game = Game(true, "TeamA", "TeamB", Date(), Date())
init {
CoroutineScope(Dispatchers.IO).launch {
gameDao.getActive().collect {
gameDao.getActiveAsFlow().collect {
if (it == null) {
gameDao.insert(Game(true, "TeamA", "TeamB", Date(), Date()))
newGame()
} else {
_activeGame = it
activeGame = it
}
}
}
@@ -40,16 +31,25 @@ class GameRepository @Inject constructor(
suspend fun newGame() {
withContext(Dispatchers.IO) {
val id =
gameDao.insert(Game(true, activeGame.nameA, activeGame.nameB, Date(), Date()))
val id = gameDao.insert(Game(true, activeGame.nameA, activeGame.nameB, Date(), Date()))
setActive(id)
}
}
suspend fun updateGame(game: Game) {
game.modified = Date()
suspend fun updateActiveTeamName(nameA: String? = null, nameB: String? = null) {
val newA = nameA ?: activeGame.nameA
val newB = nameB ?: activeGame.nameB
if(newA == activeGame.nameA && newB == activeGame.nameB) {
return
}
activeGame.modified = Date()
activeGame.nameA = newA
activeGame.nameB = newB
withContext(Dispatchers.IO) {
gameDao.update(game)
gameDao.update(activeGame)
}
}
@@ -92,11 +92,10 @@ class GameRepository @Inject constructor(
suspend fun deleteGame(uid: Long) {
withContext(Dispatchers.IO) {
try {
gameDao.getGameById(uid).take(1).collect {
gameDao.delete(it)
val rounds = roundDao.getAllForGame(it.uid)
roundDao.delete(rounds)
}
val game = gameDao.getGameById(uid)
gameDao.delete(game)
val rounds = roundDao.getAllForGame(game.uid)
roundDao.delete(rounds)
} catch (_: NullPointerException) {
}
}
@@ -107,9 +106,8 @@ class GameRepository @Inject constructor(
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 }
val gamesToDelete = games.filter { it.uid != activeGame.uid }
val roundsToDelete = roundDao.getAll().filter { it.gameId != activeGame.uid }
gameDao.delete(gamesToDelete)
roundDao.delete(roundsToDelete)
@@ -119,8 +117,8 @@ class GameRepository @Inject constructor(
}
}
fun getActiveGameFlow(): Flow<GameWithScores?> {
return gameDao.getActiveWithRounds()
fun getActiveGameFlow(): Flow<GameWithScores> {
return gameDao.getActiveWithRounds().filter { it != null }.map { it!! }
}
fun getAllWithRoundFlow(): Flow<List<GameWithScores>> {

View File

@@ -34,17 +34,15 @@ class MainViewModel @Inject constructor(
gameRepository.getActiveGameFlow().collect {
activeGameHasRounds = it?.rounds?.isNotEmpty() == true
activeGameHasRounds = it.rounds.isNotEmpty() == true
if (it != null) {
isUndoActionActive = it.rounds.isNotEmpty()
isUndoActionActive = it.rounds.isNotEmpty()
if (expectedRoundCount != it.rounds.count()) {
redoRounds.clear()
}
expectedRoundCount = it.rounds.count()
if (expectedRoundCount != it.rounds.count()) {
redoRounds.clear()
}
expectedRoundCount = it.rounds.count()
}
}
}

View File

@@ -245,17 +245,13 @@ class CounterViewModel @Inject constructor(
override fun updateNameA(value: String) {
viewModelScope.launch {
val game = gameRepository.activeGame
game.nameA = value
gameRepository.updateGame(game)
gameRepository.updateActiveTeamName(nameA = value)
}
}
override fun updateNameB(value: String) {
viewModelScope.launch {
val game = gameRepository.activeGame
game.nameB = value
gameRepository.updateGame(game)
gameRepository.updateActiveTeamName(nameB = value)
}
}