1.0
This commit is contained in:
parent
133e06db1e
commit
82ecbb2caa
1
.gitignore
vendored
1
.gitignore
vendored
@ -112,3 +112,4 @@ fabric.properties
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
GameLibraryApp.zip
|
||||
|
@ -3,7 +3,7 @@ plugins {
|
||||
alias(libs.plugins.kotlin.android)
|
||||
|
||||
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 {
|
||||
|
@ -4,5 +4,7 @@ data class Game(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
val details: String,
|
||||
val note: String
|
||||
val note: String,
|
||||
val imageUrl :String,
|
||||
val inLibrary: Boolean
|
||||
)
|
||||
|
@ -1,43 +1,56 @@
|
||||
package at.xaxa.gamelibraryapp.data
|
||||
|
||||
import android.util.Log
|
||||
import at.xaxa.gamelibraryapp.data.db.LibraryDao
|
||||
import at.xaxa.gamelibraryapp.data.db.LibraryEntity
|
||||
import at.xaxa.gamelibraryapp.data.remote.GameDto
|
||||
import at.xaxa.gamelibraryapp.data.remote.GameRemoteService
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.math.log
|
||||
|
||||
class GameRepository(private val libraryDao: LibraryDao, private val gameRemoteService: GameRemoteService) {
|
||||
private val apiKey = "7a2a800a085d41e88621a8a59dc5ea82"
|
||||
|
||||
/*suspend fun loadInitialContacts() {
|
||||
suspend fun searchGames(searchText: String): List<GameDto> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val contactDtoList = gameRemoteService.getAllContacts()
|
||||
contactDtoList.map {
|
||||
Game(0, it., "${it.telephoneNumber}", it.age)
|
||||
}.forEach {
|
||||
insertContact(it)
|
||||
}
|
||||
print(gameRemoteService.searchGames(apiKey, searchText).toString())
|
||||
gameRemoteService.searchGames(apiKey, searchText).results
|
||||
} 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>> {
|
||||
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 {
|
||||
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) {
|
||||
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) {
|
||||
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))
|
||||
}
|
||||
}
|
@ -22,9 +22,9 @@ interface LibraryDao {
|
||||
@Query("SELECT * FROM library WHERE _id = :id")
|
||||
suspend fun findEntryById(id: Int): LibraryEntity
|
||||
|
||||
@Query("SELECT * FROM library")
|
||||
@Query("SELECT * FROM library WHERE inLibrary = 1")
|
||||
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>>
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import at.xaxa.gamelibraryapp.LibraryApplication
|
||||
|
||||
@Database(entities = [LibraryEntity::class], version = 2)
|
||||
@Database(entities = [LibraryEntity::class], version = 3)
|
||||
abstract class LibraryDatabase : RoomDatabase() {
|
||||
abstract fun libraryDao(): LibraryDao
|
||||
|
||||
|
@ -9,5 +9,7 @@ data class LibraryEntity(
|
||||
val _id: Int,
|
||||
val name: String,
|
||||
val details: String,
|
||||
val note: String
|
||||
val note: String,
|
||||
val imageUrl :String,
|
||||
val inLibrary: Boolean
|
||||
)
|
@ -9,14 +9,5 @@ import retrofit2.http.Query
|
||||
// TODO Implement Remote Service
|
||||
interface GameRemoteService {
|
||||
@GET("games")
|
||||
suspend fun getAllGames(@Query("key") apiKey: String): List<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)
|
||||
suspend fun searchGames(@Query("key") apiKey: String, @Query("search") searchText: String): ApiResponse
|
||||
}
|
@ -6,6 +6,8 @@ import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import at.xaxa.gamelibraryapp.LibraryApplication
|
||||
import at.xaxa.gamelibraryapp.ui.Details.DetailsViewModel
|
||||
import at.xaxa.gamelibraryapp.ui.GameList.GameListViewModel
|
||||
import at.xaxa.gamelibraryapp.ui.Search.SearchListViewModel
|
||||
|
||||
object AppViewModelProvider {
|
||||
val Factory = viewModelFactory {
|
||||
@ -13,10 +15,14 @@ object AppViewModelProvider {
|
||||
DetailsViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LibraryApplication).libraryRepository)
|
||||
}
|
||||
|
||||
/*initializer {
|
||||
ContactsViewModel((this[APPLICATION_KEY] as ContactsApplication).contactsRepository)
|
||||
initializer {
|
||||
GameListViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LibraryApplication).libraryRepository)
|
||||
}
|
||||
|
||||
initializer {
|
||||
SearchListViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LibraryApplication).libraryRepository)
|
||||
}
|
||||
/*
|
||||
initializer {
|
||||
ContactDetailsViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as ContactsApplication).contactsRepository)
|
||||
}
|
||||
|
@ -1,25 +1,66 @@
|
||||
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.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
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.navigation.NavBackStackEntry
|
||||
import at.xaxa.gamelibraryapp.ui.AppViewModelProvider
|
||||
import at.xaxa.gamelibraryapp.ui.DetailCard
|
||||
import at.xaxa.gamelibraryapp.ui.LayoutMediaText
|
||||
import at.xaxa.gamelibraryapp.ui.ShowPicture
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DetailView(
|
||||
navBackStackEntry: NavBackStackEntry,
|
||||
viewModel: DetailsViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
// Extract arguments here
|
||||
val gameId = navBackStackEntry.arguments?.getInt("gameId") // Or `Int` if needed
|
||||
val libraryEntity = viewModel.editUiState.libraryEntity
|
||||
|
||||
val buttonText = if (libraryEntity.inLibrary) "Remove from library" else "Add to library"
|
||||
|
||||
Column {
|
||||
DetailCard(modifier,
|
||||
title = "Game Title $gameId", // Use the extracted gameId
|
||||
details = "details",
|
||||
imageUrl = "https://media.rawg.io/media/games/b7f/b7ffc4c4776e61eca19d36d3c227f89a.jpg",
|
||||
note = "note"
|
||||
title = libraryEntity.name,
|
||||
details = libraryEntity.details,
|
||||
imageUrl = libraryEntity.imageUrl,
|
||||
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") }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -13,10 +13,13 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
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"])
|
||||
|
||||
@ -34,12 +37,11 @@ class DetailsViewModel(private val savedStateHandle: SavedStateHandle, private v
|
||||
|
||||
fun updateGame(libraryEntity: LibraryEntity) {
|
||||
editUiState = editUiState.copy(libraryEntity = libraryEntity)
|
||||
}
|
||||
|
||||
fun saveLibrary() {
|
||||
viewModelScope.launch {
|
||||
gameRepository.updateEntry(editUiState.libraryEntity)
|
||||
withContext(Dispatchers.IO) {
|
||||
gameRepository.updateEntry(libraryEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -14,7 +14,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
data class GameDetailUi(
|
||||
val game: LibraryEntity = LibraryEntity(0, "", "", "")
|
||||
val game: LibraryEntity = LibraryEntity(0, "", "", "", "", false)
|
||||
)
|
||||
|
||||
class GameDetailsViewModel(savedStateHandle: SavedStateHandle, private val gameRepository: GameRepository): ViewModel() {
|
||||
|
@ -5,20 +5,36 @@ 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.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.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.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.Details.DetailsViewModel
|
||||
import at.xaxa.gamelibraryapp.ui.HorizontalCard
|
||||
import kotlinx.coroutines.flow.count
|
||||
import androidx.compose.foundation.lazy.items
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@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("") }
|
||||
viewModel.searchGamesInDB(searchText)
|
||||
|
||||
Column(modifier = modifier) {
|
||||
// Search Bar
|
||||
@ -28,19 +44,22 @@ fun GameList(modifier: Modifier = Modifier, onCardClick: (Int) -> Unit) {
|
||||
label = { Text("Search games") },
|
||||
modifier = Modifier
|
||||
.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
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
items(16) { index ->
|
||||
items(gameListState) { game ->
|
||||
HorizontalCard(
|
||||
modifier = modifier,
|
||||
title = "Game $index",
|
||||
details = "Details about game $index",
|
||||
imageUrl = "https://media.rawg.io/media/games/b7f/b7ffc4c4776e61eca19d36d3c227f89a.jpg",
|
||||
title = game.name,
|
||||
details = game.details,
|
||||
imageUrl = game.imageUrl,
|
||||
onClick = {
|
||||
onCardClick(index)
|
||||
onCardClick(game.id)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -1,2 +1,47 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.List
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
@ -99,7 +100,6 @@ fun LibraryApp(modifier: Modifier = Modifier) {
|
||||
) {
|
||||
backStackEntry ->
|
||||
DetailView(
|
||||
navBackStackEntry = backStackEntry,
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
@ -114,7 +114,9 @@ fun DetailCard(
|
||||
title: String,
|
||||
details: String,
|
||||
note: String,
|
||||
imageUrl: String) {
|
||||
imageUrl: String,
|
||||
onClick: () -> Unit,
|
||||
buttonText: String) {
|
||||
Surface(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
@ -125,6 +127,13 @@ fun DetailCard(
|
||||
Column(modifier) {
|
||||
ShowPicture(modifier = Modifier.height(200.dp), imageUrl)
|
||||
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
|
||||
@Composable
|
||||
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")
|
||||
}
|
@ -1,22 +1,70 @@
|
||||
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.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.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.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 androidx.compose.foundation.lazy.items
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SearchList(modifier: Modifier = Modifier, onCardClick: (Int) -> Unit){
|
||||
LazyColumn{
|
||||
items(16) { index ->
|
||||
fun SearchList(
|
||||
modifier: Modifier = Modifier,
|
||||
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,
|
||||
"test $index",
|
||||
"details $index",
|
||||
"https://media.rawg.io/media/games/6e0/6e0c19bb111bd4fa20cf0eb72a049519.jpg",
|
||||
game.name,
|
||||
game.details,
|
||||
game.imageUrl,//"https://media.rawg.io/media/games/6e0/6e0c19bb111bd4fa20cf0eb72a049519.jpg",
|
||||
onClick = {
|
||||
onCardClick(index)
|
||||
viewModel.addGameToDB(game)
|
||||
onCardClick(game.id)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +1,80 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user