Skip to content
Snippets Groups Projects
Commit 84cfe418 authored by Baryshnikov Oleg's avatar Baryshnikov Oleg
Browse files

Implement the favorite character screen.

Remove the search icon from the favorite screen.
parent a2f883d7
Branches master
No related tags found
No related merge requests found
Showing with 128 additions and 15 deletions
......@@ -12,6 +12,7 @@ import cz.fel.barysole.ackeetesttask.ui.screen.Screen
import cz.fel.barysole.ackeetesttask.ui.screen.ScreenAction
import cz.fel.barysole.ackeetesttask.ui.screen.characterdetail.CharacterDetailScreen
import cz.fel.barysole.ackeetesttask.ui.screen.characterlist.CharacterListScreen
import cz.fel.barysole.ackeetesttask.ui.screen.favorite.FavoriteCharacterListScreen
import kotlinx.coroutines.flow.Flow
@Composable
......@@ -39,7 +40,14 @@ fun MyNavHost(
}
)
}
composable(Screen.Favorite.route) { onTopBarTitleChange("") }
composable(Screen.Favorite.route) { onTopBarTitleChange("")
FavoriteCharacterListScreen(
onItemSelected = { characterId ->
navController.navigate(Screen.CharacterDetail.routeWithoutArgument + "/" + characterId) {
launchSingleTop = true
}
})
}
composable(
Screen.CharacterDetail.route,
arguments = listOf(navArgument("characterId") { type = NavType.LongType })
......
......@@ -16,9 +16,12 @@ interface CharacterDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(repos: List<CharacterInfo>)
@Query("SELECT * FROM CharacterInfo")
@Query("SELECT * FROM CharacterInfo ORDER BY id ASC")
fun getAll(): PagingSource<Int, CharacterInfo>
@Query("SELECT * FROM CharacterInfo WHERE isFavorite = 1 ORDER BY id ASC")
fun getFavorite(): PagingSource<Int, CharacterInfo>
@Query("SELECT * FROM CharacterInfo WHERE id=:id")
suspend fun getById(id: Long): CharacterInfo?
......@@ -28,7 +31,4 @@ interface CharacterDao {
"ORDER BY id ASC"
)
fun getCharactersByName(characterName: String): PagingSource<Int, CharacterInfo>
@Query("DELETE FROM CharacterInfo WHERE isFavorite = 'false'")
suspend fun deleteNotFavorite()
}
\ No newline at end of file
......@@ -10,6 +10,8 @@ interface CharacterRepository {
fun getCharactersFlow(): Flow<PagingData<CharacterInfo>>
fun getFavoriteCharactersFlow(): Flow<PagingData<CharacterInfo>>
suspend fun getCharacter(characterId: Long): CharacterInfo?
suspend fun changeCharacterFavoriteStatus(characterId: Long)
......
......@@ -4,17 +4,12 @@ import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import cz.fel.barysole.ackeetesttask.api.RickAndMortyApi
import cz.fel.barysole.ackeetesttask.db.room.AppDatabase
import cz.fel.barysole.ackeetesttask.db.room.dao.CharacterDao
import cz.fel.barysole.ackeetesttask.model.CharacterInfo
import cz.fel.barysole.ackeetesttask.model.PaginationInfo
import cz.fel.barysole.ackeetesttask.repository.pagination.PaginationDataType
import kotlinx.coroutines.flow.Flow
import retrofit2.HttpException
import java.io.IOException
import javax.inject.Inject
import javax.inject.Singleton
......@@ -31,7 +26,7 @@ class CharacterRepositoryImpl @Inject constructor(
pageSize = NETWORK_PAGE_SIZE,
enablePlaceholders = false
),
pagingSourceFactory = { CharactersPagingSource(rickAndMortyApi, characterNameQuery) }
pagingSourceFactory = { CharactersSearchPagingSource(rickAndMortyApi, characterNameQuery) }
).flow
}
......@@ -47,6 +42,16 @@ class CharacterRepositoryImpl @Inject constructor(
).flow
}
override fun getFavoriteCharactersFlow(): Flow<PagingData<CharacterInfo>> {
return Pager(
config = PagingConfig(
pageSize = NETWORK_PAGE_SIZE,
enablePlaceholders = false
),
pagingSourceFactory = { appDatabase.characterDao().getFavorite() }
).flow
}
override suspend fun getCharacter(characterId: Long): CharacterInfo? {
val response = rickAndMortyApi.getCharacterById(characterId)
appDatabase.withTransaction {
......@@ -71,7 +76,6 @@ class CharacterRepositoryImpl @Inject constructor(
// Save isFavorite flag during items update in the DB
suspend fun insertCharacterItems(items: List<CharacterInfo>, characterDao: CharacterDao) {
// clear the character table in the database
characterDao.deleteNotFavorite()
for (item in items) {
val itemInDb = characterDao.getById(item.id)
if (itemInDb?.isFavorite == true) {
......
......@@ -7,7 +7,7 @@ import cz.fel.barysole.ackeetesttask.model.CharacterInfo
import retrofit2.HttpException
import java.io.IOException
class CharactersPagingSource(
class CharactersSearchPagingSource(
private val rickAndMortyApi: RickAndMortyApi,
private val characterName: String
) : PagingSource<Int, CharacterInfo>() {
......
......@@ -22,8 +22,7 @@ sealed class Screen(
object Favorite : Screen(
"favorite",
R.string.favorite,
R.drawable.baseline_star_24,
actionList = listOf(ScreenAction.SearchCharacterScreenAction)
R.drawable.baseline_star_24
)
object CharacterDetail : Screen(
......
package cz.fel.barysole.ackeetesttask.ui.screen.favorite
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import cz.fel.barysole.ackeetesttask.ui.uielement.character.CharacterList
@Composable
fun FavoriteCharacterListScreen(
onItemSelected: (id: Long) -> Unit,
favoriteCharacterListViewModel: FavoriteCharacterListViewModel = hiltViewModel()
) {
favoriteCharacterListViewModel.refreshList()
val favoriteCharacters =
favoriteCharacterListViewModel.pagingDataFlow.collectAsLazyPagingItems()
Surface(
color = MaterialTheme.colorScheme.background
) {
if (favoriteCharacters.itemCount == 0) {
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("There is no favorite characters yet.")
}
} else {
CharacterList(favoriteCharacters, onItemSelected)
}
}
}
\ No newline at end of file
package cz.fel.barysole.ackeetesttask.ui.screen.favorite
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.room.withTransaction
import cz.fel.barysole.ackeetesttask.db.room.AppDatabase
import cz.fel.barysole.ackeetesttask.model.CharacterInfo
import cz.fel.barysole.ackeetesttask.repository.characters.CharacterRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import javax.inject.Inject
@OptIn(ExperimentalCoroutinesApi::class)
@HiltViewModel
class FavoriteCharacterListViewModel @Inject constructor(
private val characterRepository: CharacterRepository,
private val appDatabase: AppDatabase
) : ViewModel() {
// The UI state
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
val pagingDataFlow: Flow<PagingData<CharacterInfo>>
private val getFavoriteCharacters = MutableSharedFlow<Unit>()
init {
pagingDataFlow = getFavoriteCharacters
.onStart { emit(Unit) }
.flatMapLatest { characterRepository.getFavoriteCharactersFlow() }
.cachedIn(viewModelScope)
}
fun refreshList() {
viewModelScope.launch { getFavoriteCharacters.emit(Unit) }
}
fun showLoadingError(hasError: Boolean) {
_uiState.value = UiState(showError = hasError)
}
data class UiState(
val showError: Boolean = false
)
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment