This commit is contained in:
Xaver 2024-12-16 22:36:17 +01:00
parent 133e06db1e
commit 82ecbb2caa
17 changed files with 334 additions and 75 deletions

1
.gitignore vendored
View File

@ -112,3 +112,4 @@ fabric.properties
# Android studio 3.1+ serialized cache file # Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser .idea/caches/build_file_checksums.ser
GameLibraryApp.zip

View File

@ -3,7 +3,7 @@ plugins {
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10"
id("com.google.devtools.ksp") version "1.6.21-1.0.6" id("com.google.devtools.ksp") version "1.9.0-1.0.12"
} }
android { android {

View File

@ -4,5 +4,7 @@ data class Game(
val id: Int, val id: Int,
val name: String, val name: String,
val details: String, val details: String,
val note: String val note: String,
val imageUrl :String,
val inLibrary: Boolean
) )

View File

@ -1,43 +1,56 @@
package at.xaxa.gamelibraryapp.data package at.xaxa.gamelibraryapp.data
import android.util.Log
import at.xaxa.gamelibraryapp.data.db.LibraryDao import at.xaxa.gamelibraryapp.data.db.LibraryDao
import at.xaxa.gamelibraryapp.data.db.LibraryEntity import at.xaxa.gamelibraryapp.data.db.LibraryEntity
import at.xaxa.gamelibraryapp.data.remote.GameDto
import at.xaxa.gamelibraryapp.data.remote.GameRemoteService import at.xaxa.gamelibraryapp.data.remote.GameRemoteService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import kotlin.math.log
class GameRepository(private val libraryDao: LibraryDao, private val gameRemoteService: GameRemoteService) { class GameRepository(private val libraryDao: LibraryDao, private val gameRemoteService: GameRemoteService) {
private val apiKey = "7a2a800a085d41e88621a8a59dc5ea82" private val apiKey = "7a2a800a085d41e88621a8a59dc5ea82"
/*suspend fun loadInitialContacts() { suspend fun searchGames(searchText: String): List<GameDto> {
return withContext(Dispatchers.IO) {
try { try {
val contactDtoList = gameRemoteService.getAllContacts() print(gameRemoteService.searchGames(apiKey, searchText).toString())
contactDtoList.map { gameRemoteService.searchGames(apiKey, searchText).results
Game(0, it., "${it.telephoneNumber}", it.age)
}.forEach {
insertContact(it)
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e("Repository", "Something went wrong! ${e.message}", e) Log.e("GameRepository", "Error searching games from API: ${e.message}", e)
emptyList<GameDto>()
}
}
} }
}*/
fun getAllGamesInLibrary(): Flow<List<Game>> { fun getAllGamesInLibrary(): Flow<List<Game>> {
return libraryDao.getAllEntries().map { return libraryDao.getAllEntries().map {
it.map {item -> Game(item._id, item.name, item.details, item.note) } it.map {item -> Game(item._id, item.name, item.details, item.note, item.imageUrl, item.inLibrary) }
} }
} }
fun searchGameInDB(searchText: String):Flow<List<Game>>{
return libraryDao.getEntriesWithName(searchText).map {
it.map {item -> Game(item._id, item.name, item.details, item.note, item.imageUrl, item.inLibrary) }
}
}
suspend fun findGameById(id: Int): LibraryEntity { suspend fun findGameById(id: Int): LibraryEntity {
val item = libraryDao.findEntryById(id) val item = libraryDao.findEntryById(id)
return LibraryEntity(item._id, item.name, item.details, item.note) //?: throw GameNotFoundException("Game with id $id not found.")
return item
} }
suspend fun addEntry(libraryEntity: LibraryEntity) { suspend fun addEntry(libraryEntity: LibraryEntity) {
libraryDao.addEntry(LibraryEntity(libraryEntity._id, libraryEntity.name, libraryEntity.details, libraryEntity.note)) libraryDao.addEntry(LibraryEntity(libraryEntity._id, libraryEntity.name, libraryEntity.details, libraryEntity.note, libraryEntity.imageUrl, libraryEntity.inLibrary))
} }
suspend fun updateEntry(game: LibraryEntity) { suspend fun updateEntry(game: LibraryEntity) {
libraryDao.updateEntry(LibraryEntity(game._id, game.name, game.details, game.note)) libraryDao.updateEntry(LibraryEntity(game._id, game.name, game.details, game.note, game.imageUrl, game.inLibrary))
} }
} }

View File

@ -22,9 +22,9 @@ interface LibraryDao {
@Query("SELECT * FROM library WHERE _id = :id") @Query("SELECT * FROM library WHERE _id = :id")
suspend fun findEntryById(id: Int): LibraryEntity suspend fun findEntryById(id: Int): LibraryEntity
@Query("SELECT * FROM library") @Query("SELECT * FROM library WHERE inLibrary = 1")
fun getAllEntries(): Flow<List<LibraryEntity>> fun getAllEntries(): Flow<List<LibraryEntity>>
@Query("SELECT * FROM library WHERE name = :entryName") @Query("SELECT * FROM library WHERE name LIKE :entryName AND inLibrary = 1")
fun getEntriesWithName(entryName: String): Flow<List<LibraryEntity>> fun getEntriesWithName(entryName: String): Flow<List<LibraryEntity>>
} }

View File

@ -5,7 +5,7 @@ import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import at.xaxa.gamelibraryapp.LibraryApplication import at.xaxa.gamelibraryapp.LibraryApplication
@Database(entities = [LibraryEntity::class], version = 2) @Database(entities = [LibraryEntity::class], version = 3)
abstract class LibraryDatabase : RoomDatabase() { abstract class LibraryDatabase : RoomDatabase() {
abstract fun libraryDao(): LibraryDao abstract fun libraryDao(): LibraryDao

View File

@ -9,5 +9,7 @@ data class LibraryEntity(
val _id: Int, val _id: Int,
val name: String, val name: String,
val details: String, val details: String,
val note: String val note: String,
val imageUrl :String,
val inLibrary: Boolean
) )

View File

@ -9,14 +9,5 @@ import retrofit2.http.Query
// TODO Implement Remote Service // TODO Implement Remote Service
interface GameRemoteService { interface GameRemoteService {
@GET("games") @GET("games")
suspend fun getAllGames(@Query("key") apiKey: String): List<ApiResponse> suspend fun searchGames(@Query("key") apiKey: String, @Query("search") searchText: String): ApiResponse
@GET("contacts/{contactId}")
suspend fun getContactById(@Path("contactId") contactId: Int)
@GET("contacts/search") // becomes contacts/search?filter=<content of filterText>
suspend fun findContacts(@Query("filter") filterText : String): List<ApiResponse>
@POST("contacts")
suspend fun addContact(@Body contactDto: ApiResponse)
} }

View File

@ -6,6 +6,8 @@ import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory import androidx.lifecycle.viewmodel.viewModelFactory
import at.xaxa.gamelibraryapp.LibraryApplication import at.xaxa.gamelibraryapp.LibraryApplication
import at.xaxa.gamelibraryapp.ui.Details.DetailsViewModel import at.xaxa.gamelibraryapp.ui.Details.DetailsViewModel
import at.xaxa.gamelibraryapp.ui.GameList.GameListViewModel
import at.xaxa.gamelibraryapp.ui.Search.SearchListViewModel
object AppViewModelProvider { object AppViewModelProvider {
val Factory = viewModelFactory { val Factory = viewModelFactory {
@ -13,10 +15,14 @@ object AppViewModelProvider {
DetailsViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LibraryApplication).libraryRepository) DetailsViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LibraryApplication).libraryRepository)
} }
/*initializer { initializer {
ContactsViewModel((this[APPLICATION_KEY] as ContactsApplication).contactsRepository) GameListViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LibraryApplication).libraryRepository)
} }
initializer {
SearchListViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LibraryApplication).libraryRepository)
}
/*
initializer { initializer {
ContactDetailsViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as ContactsApplication).contactsRepository) ContactDetailsViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as ContactsApplication).contactsRepository)
} }

View File

@ -1,25 +1,66 @@
package at.xaxa.gamelibraryapp.ui.Details package at.xaxa.gamelibraryapp.ui.Details
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
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.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavBackStackEntry
import at.xaxa.gamelibraryapp.ui.AppViewModelProvider import at.xaxa.gamelibraryapp.ui.AppViewModelProvider
import at.xaxa.gamelibraryapp.ui.DetailCard import at.xaxa.gamelibraryapp.ui.DetailCard
import at.xaxa.gamelibraryapp.ui.LayoutMediaText
import at.xaxa.gamelibraryapp.ui.ShowPicture
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun DetailView( fun DetailView(
navBackStackEntry: NavBackStackEntry,
viewModel: DetailsViewModel = viewModel(factory = AppViewModelProvider.Factory), viewModel: DetailsViewModel = viewModel(factory = AppViewModelProvider.Factory),
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
// Extract arguments here val libraryEntity = viewModel.editUiState.libraryEntity
val gameId = navBackStackEntry.arguments?.getInt("gameId") // Or `Int` if needed
val buttonText = if (libraryEntity.inLibrary) "Remove from library" else "Add to library"
Column {
DetailCard(modifier, DetailCard(modifier,
title = "Game Title $gameId", // Use the extracted gameId title = libraryEntity.name,
details = "details", details = libraryEntity.details,
imageUrl = "https://media.rawg.io/media/games/b7f/b7ffc4c4776e61eca19d36d3c227f89a.jpg", imageUrl = libraryEntity.imageUrl,
note = "note" note = libraryEntity.note,
onClick = {
viewModel.updateGame(libraryEntity.copy(inLibrary = !libraryEntity.inLibrary))
},
buttonText = buttonText
) )
OutlinedTextField(
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 4.dp)
.fillMaxSize(),
shape = RoundedCornerShape(12.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.DarkGray,
unfocusedBorderColor = Color.LightGray),
value = libraryEntity.note,
onValueChange = {
viewModel.updateGame(libraryEntity.copy(note = it))
},
label = { Text("Notes") }
)
}
} }

View File

@ -13,10 +13,13 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
data class GameEditUi( data class GameEditUi(
val libraryEntity: LibraryEntity = LibraryEntity(0, "", "", "") val libraryEntity: LibraryEntity = LibraryEntity(0, "", "", "", "",true)
) )
class DetailsViewModel(private val savedStateHandle: SavedStateHandle, private val gameRepository: GameRepository) : ViewModel() { class DetailsViewModel(
private val savedStateHandle: SavedStateHandle,
private val gameRepository: GameRepository
) : ViewModel() {
private val gameId: Int = checkNotNull(savedStateHandle["gameId"]) private val gameId: Int = checkNotNull(savedStateHandle["gameId"])
@ -33,13 +36,12 @@ class DetailsViewModel(private val savedStateHandle: SavedStateHandle, private v
} }
fun updateGame(libraryEntity: LibraryEntity) { fun updateGame(libraryEntity: LibraryEntity) {
editUiState = editUiState.copy(libraryEntity=libraryEntity) editUiState = editUiState.copy(libraryEntity = libraryEntity)
}
fun saveLibrary() {
viewModelScope.launch { viewModelScope.launch {
gameRepository.updateEntry(editUiState.libraryEntity) withContext(Dispatchers.IO) {
gameRepository.updateEntry(libraryEntity)
}
} }
} }
} }

View File

@ -14,7 +14,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
data class GameDetailUi( data class GameDetailUi(
val game: LibraryEntity = LibraryEntity(0, "", "", "") val game: LibraryEntity = LibraryEntity(0, "", "", "", "", false)
) )
class GameDetailsViewModel(savedStateHandle: SavedStateHandle, private val gameRepository: GameRepository): ViewModel() { class GameDetailsViewModel(savedStateHandle: SavedStateHandle, private val gameRepository: GameRepository): ViewModel() {

View File

@ -5,20 +5,36 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import at.xaxa.gamelibraryapp.ui.AppViewModelProvider
import at.xaxa.gamelibraryapp.ui.Details.DetailsViewModel
import at.xaxa.gamelibraryapp.ui.HorizontalCard import at.xaxa.gamelibraryapp.ui.HorizontalCard
import kotlinx.coroutines.flow.count
import androidx.compose.foundation.lazy.items
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun GameList(modifier: Modifier = Modifier, onCardClick: (Int) -> Unit) { fun GameList(modifier: Modifier = Modifier,
viewModel: GameListViewModel = viewModel(factory = AppViewModelProvider.Factory),
onCardClick: (Int) -> Unit) {
//val gameList = viewModel.editUiState.libraryEntity
val gameListState by viewModel.editUiState.libraryEntity.collectAsState(initial = emptyList())
var searchText by remember { mutableStateOf("") } var searchText by remember { mutableStateOf("") }
viewModel.searchGamesInDB(searchText)
Column(modifier = modifier) { Column(modifier = modifier) {
// Search Bar // Search Bar
@ -28,19 +44,22 @@ fun GameList(modifier: Modifier = Modifier, onCardClick: (Int) -> Unit) {
label = { Text("Search games") }, label = { Text("Search games") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 4.dp) .padding(horizontal = 16.dp, vertical = 4.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.DarkGray,
unfocusedBorderColor = Color.LightGray)
) )
// Game List // Game List
LazyColumn(modifier = Modifier.fillMaxSize()) { LazyColumn(modifier = Modifier.fillMaxSize()) {
items(16) { index -> items(gameListState) { game ->
HorizontalCard( HorizontalCard(
modifier = modifier, modifier = modifier,
title = "Game $index", title = game.name,
details = "Details about game $index", details = game.details,
imageUrl = "https://media.rawg.io/media/games/b7f/b7ffc4c4776e61eca19d36d3c227f89a.jpg", imageUrl = game.imageUrl,
onClick = { onClick = {
onCardClick(index) onCardClick(game.id)
} }
) )
} }

View File

@ -1,2 +1,47 @@
package at.xaxa.gamelibraryapp.ui.GameList package at.xaxa.gamelibraryapp.ui.GameList
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import at.xaxa.gamelibraryapp.data.Game
import at.xaxa.gamelibraryapp.data.GameRepository
import at.xaxa.gamelibraryapp.data.db.LibraryEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
data class GameListUi(
val libraryEntity: Flow<List<Game>> = flowOf(emptyList())
)
class GameListViewModel(private val savedStateHandle: SavedStateHandle, private val gameRepository: GameRepository) : ViewModel() {
var editUiState by mutableStateOf(GameListUi())
private set
init {
viewModelScope.launch {
val games = withContext(Dispatchers.IO) {
gameRepository.getAllGamesInLibrary()
}
editUiState = GameListUi(games)
}
}
fun searchGamesInDB(searchString: String) {
viewModelScope.launch {
val searchResults = withContext(Dispatchers.IO) {
gameRepository.searchGameInDB("%$searchString%")
}
editUiState = GameListUi(searchResults)
}
}
}

View File

@ -16,6 +16,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@ -99,7 +100,6 @@ fun LibraryApp(modifier: Modifier = Modifier) {
) { ) {
backStackEntry -> backStackEntry ->
DetailView( DetailView(
navBackStackEntry = backStackEntry,
modifier = Modifier modifier = Modifier
) )
} }
@ -114,7 +114,9 @@ fun DetailCard(
title: String, title: String,
details: String, details: String,
note: String, note: String,
imageUrl: String) { imageUrl: String,
onClick: () -> Unit,
buttonText: String) {
Surface( Surface(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
@ -125,6 +127,13 @@ fun DetailCard(
Column(modifier) { Column(modifier) {
ShowPicture(modifier = Modifier.height(200.dp), imageUrl) ShowPicture(modifier = Modifier.height(200.dp), imageUrl)
LayoutMediaText(modifier = Modifier, title, details) LayoutMediaText(modifier = Modifier, title, details)
FilledTonalButton(
shape = RoundedCornerShape(12.dp),
modifier = Modifier.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
onClick = { onClick() }) {
Text(buttonText)
}
} }
} }
} }
@ -270,5 +279,7 @@ private fun HorizontalCardPreview() {
@Preview @Preview
@Composable @Composable
private fun DetailCardPreview() { private fun DetailCardPreview() {
DetailCard(Modifier, "Uncharted 3", "Action Adventure, 2011", "test", "https://media.rawg.io/media/games/b7f/b7ffc4c4776e61eca19d36d3c227f89a.jpg") DetailCard(Modifier, "Uncharted 3", "Action Adventure, 2011", "test", "https://media.rawg.io/media/games/b7f/b7ffc4c4776e61eca19d36d3c227f89a.jpg", onClick = {
println("clicked")
}, "Add to library")
} }

View File

@ -1,22 +1,70 @@
package at.xaxa.gamelibraryapp.ui.Search package at.xaxa.gamelibraryapp.ui.Search
import android.util.Log
import androidx.compose.foundation.layout.Column
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.LazyColumn
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable 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.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import at.xaxa.gamelibraryapp.ui.AppViewModelProvider
import at.xaxa.gamelibraryapp.ui.HorizontalCard import at.xaxa.gamelibraryapp.ui.HorizontalCard
import androidx.compose.foundation.lazy.items
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SearchList(modifier: Modifier = Modifier, onCardClick: (Int) -> Unit){ fun SearchList(
LazyColumn{ modifier: Modifier = Modifier,
items(16) { index -> viewModel: SearchListViewModel = viewModel(factory = AppViewModelProvider.Factory),
onCardClick: (Int) -> Unit
) {
var searchText by remember { mutableStateOf("") }
val gamesList by viewModel.editUiState.games.collectAsState(initial = emptyList())
Column(modifier = modifier) {
// Search field
OutlinedTextField(
value = searchText,
onValueChange = {
searchText = it
// Call searchGames when text changes
viewModel.searchGames(searchText)
},
label = { Text("Search games") },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 4.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.DarkGray,
unfocusedBorderColor = Color.LightGray
)
)
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(gamesList) { game ->
HorizontalCard(modifier, HorizontalCard(modifier,
"test $index", game.name,
"details $index", game.details,
"https://media.rawg.io/media/games/6e0/6e0c19bb111bd4fa20cf0eb72a049519.jpg", game.imageUrl,//"https://media.rawg.io/media/games/6e0/6e0c19bb111bd4fa20cf0eb72a049519.jpg",
onClick = { onClick = {
onCardClick(index) viewModel.addGameToDB(game)
onCardClick(game.id)
} }
) )
} }
} }
}
} }

View File

@ -1,2 +1,80 @@
package at.xaxa.gamelibraryapp.ui.Search package at.xaxa.gamelibraryapp.ui.Search
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import at.xaxa.gamelibraryapp.data.Game
import at.xaxa.gamelibraryapp.data.GameRepository
import at.xaxa.gamelibraryapp.data.db.LibraryEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
// UI State to hold a list of games
data class GameListUi(
val games: Flow<List<Game>> = flow{emit(emptyList()) }
)
class SearchListViewModel(
private val savedStateHandle: SavedStateHandle,
private val gameRepository: GameRepository
) : ViewModel() {
var editUiState by mutableStateOf(GameListUi())
private set
// Function to search games based on search text
fun searchGames(searchText: String) {
viewModelScope.launch {
// Launching a background task to fetch the data from the repository
val games = withContext(Dispatchers.IO) {
gameRepository.searchGames(searchText) // Get the list of games
}
// Now transform the data before emitting
val mappedGames = games.map { game ->
// Transform each game as needed
Game(
id = game.id,
name = game.name,
details = game.genres.firstOrNull()?.name ?: "Genre Unknown",
note = "",
imageUrl = game.background_image,
inLibrary = false
)
}
editUiState = GameListUi(games = flow { emit(mappedGames) })
}
}
fun addGameToDB(game: Game){
viewModelScope.launch {
try {
val libraryEntity = LibraryEntity(
_id = game.id,
name = game.name,
details = game.details,
note = game.note,
imageUrl = game.imageUrl,
inLibrary = false
)
withContext(Dispatchers.IO) {
gameRepository.addEntry(libraryEntity) // Add game to the database
}
// Optionally, log or update UI state to reflect that the game was added
Log.d("GameLibraryApp", "Game added to DB: ${game.name}")
} catch (e: Exception) {
Log.e("GameLibraryApp", "Error adding game to DB", e)
}
}
}
}