Add home screen
This commit is contained in:
parent
a9dc65d0b6
commit
b6e4d282b7
7 changed files with 173 additions and 21 deletions
|
|
@ -95,6 +95,7 @@ dependencies {
|
||||||
implementation "androidx.room:room-ktx:$androidx_room_version"
|
implementation "androidx.room:room-ktx:$androidx_room_version"
|
||||||
|
|
||||||
implementation "io.coil-kt:coil:$coil_version"
|
implementation "io.coil-kt:coil:$coil_version"
|
||||||
|
implementation "io.coil-kt:coil-compose:$coil_version"
|
||||||
|
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package org.fnives.test.showcase.ui.compose.screen
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -12,6 +11,9 @@ import androidx.navigation.compose.rememberNavController
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
||||||
import org.fnives.test.showcase.ui.compose.screen.auth.AuthScreen
|
import org.fnives.test.showcase.ui.compose.screen.auth.AuthScreen
|
||||||
|
import org.fnives.test.showcase.ui.compose.screen.auth.rememberAuthScreenState
|
||||||
|
import org.fnives.test.showcase.ui.compose.screen.home.HomeScreen
|
||||||
|
import org.fnives.test.showcase.ui.compose.screen.home.rememberHomeScreenState
|
||||||
import org.fnives.test.showcase.ui.compose.screen.splash.SplashScreen
|
import org.fnives.test.showcase.ui.compose.screen.splash.SplashScreen
|
||||||
import org.koin.androidx.compose.get
|
import org.koin.androidx.compose.get
|
||||||
|
|
||||||
|
|
@ -25,9 +27,23 @@ fun AppNavigation() {
|
||||||
navController.navigate(if (isUserLogeInUseCase.invoke()) "Home" else "Auth")
|
navController.navigate(if (isUserLogeInUseCase.invoke()) "Home" else "Auth")
|
||||||
}
|
}
|
||||||
|
|
||||||
NavHost(navController, startDestination = "Splash", modifier = Modifier.background(MaterialTheme.colors.surface)) {
|
NavHost(
|
||||||
|
navController,
|
||||||
|
startDestination = "Splash",
|
||||||
|
modifier = Modifier.background(MaterialTheme.colors.surface)
|
||||||
|
) {
|
||||||
composable("Splash") { SplashScreen() }
|
composable("Splash") { SplashScreen() }
|
||||||
composable("Auth") { AuthScreen() }
|
composable("Auth") {
|
||||||
composable("Home") { Text("Home") }
|
val authState = rememberAuthScreenState()
|
||||||
|
AuthScreen(authState)
|
||||||
|
if (authState.navigateToHome?.consume() != null) {
|
||||||
|
navController.navigate("Home")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
composable("Home") {
|
||||||
|
HomeScreen(rememberHomeScreenState {
|
||||||
|
navController.navigate("Auth")
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ import org.fnives.test.showcase.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AuthScreen(
|
fun AuthScreen(
|
||||||
authScreenState: AuthScreenState = rememberAuthScreen()
|
authScreenState: AuthScreenState = rememberAuthScreenState()
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import org.fnives.test.showcase.ui.shared.Event
|
||||||
import org.koin.androidx.compose.get
|
import org.koin.androidx.compose.get
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun rememberAuthScreen(
|
fun rememberAuthScreenState(
|
||||||
stateScope: CoroutineScope = rememberCoroutineScope(),
|
stateScope: CoroutineScope = rememberCoroutineScope(),
|
||||||
loginUseCase: LoginUseCase = get(),
|
loginUseCase: LoginUseCase = get(),
|
||||||
): AuthScreenState {
|
): AuthScreenState {
|
||||||
|
|
@ -64,8 +64,7 @@ class AuthScreenState(
|
||||||
when (loginStatus) {
|
when (loginStatus) {
|
||||||
LoginStatus.SUCCESS -> navigateToHome = Event(Unit)
|
LoginStatus.SUCCESS -> navigateToHome = Event(Unit)
|
||||||
LoginStatus.INVALID_CREDENTIALS -> error = Event(ErrorType.INVALID_CREDENTIALS)
|
LoginStatus.INVALID_CREDENTIALS -> error = Event(ErrorType.INVALID_CREDENTIALS)
|
||||||
LoginStatus.INVALID_USERNAME -> error = Event(ErrorType.UNSUPPORTED_USERNAME).also { println("asdasdasd: ${it.hashCode()}")
|
LoginStatus.INVALID_USERNAME -> error = Event(ErrorType.UNSUPPORTED_USERNAME)
|
||||||
}
|
|
||||||
LoginStatus.INVALID_PASSWORD -> error = Event(ErrorType.UNSUPPORTED_PASSWORD)
|
LoginStatus.INVALID_PASSWORD -> error = Event(ErrorType.UNSUPPORTED_PASSWORD)
|
||||||
}
|
}
|
||||||
println("asdasdasd: ${error.hashCode()}")
|
println("asdasdasd: ${error.hashCode()}")
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,100 @@
|
||||||
package org.fnives.test.showcase.ui.compose.screen.home
|
package org.fnives.test.showcase.ui.compose.screen.home
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import coil.compose.rememberImagePainter
|
||||||
import com.google.accompanist.swiperefresh.SwipeRefresh
|
import com.google.accompanist.swiperefresh.SwipeRefresh
|
||||||
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
||||||
import org.fnives.test.showcase.R
|
import org.fnives.test.showcase.R
|
||||||
|
import org.fnives.test.showcase.model.content.FavouriteContent
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen(
|
fun HomeScreen(
|
||||||
homeScreenState = rememberHomeScreenState()
|
homeScreenState: HomeScreenState = rememberHomeScreenState()
|
||||||
) {
|
) {
|
||||||
Column(Modifier.fillMaxSize()) {
|
Column(Modifier.fillMaxSize()) {
|
||||||
Title()
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
SwipeRefresh(state = rememberSwipeRefreshState(isRefreshing = false), onRefresh = { }) {
|
Title(Modifier.weight(1f))
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.logout_24),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(MaterialTheme.colors.primary),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.clickable { homeScreenState.onLogout() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SwipeRefresh(
|
||||||
|
state = rememberSwipeRefreshState(isRefreshing = homeScreenState.loading),
|
||||||
|
onRefresh = {
|
||||||
|
homeScreenState.onRefresh()
|
||||||
|
}) {
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
|
items(homeScreenState.content) { item ->
|
||||||
|
Item(
|
||||||
|
Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
|
favouriteContent = item,
|
||||||
|
onFavouriteToggle = { homeScreenState.onFavouriteToggleClicked(item.content.id) }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Item(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
favouriteContent: FavouriteContent,
|
||||||
|
onFavouriteToggle: () -> Unit,
|
||||||
|
) {
|
||||||
|
Row(modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Image(
|
||||||
|
painter = rememberImagePainter(favouriteContent.content.imageUrl.url),
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier
|
||||||
|
.height(120.dp)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.clip(RoundedCornerShape(12.dp))
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
) {
|
||||||
|
Text(text = favouriteContent.content.title)
|
||||||
|
Text(text = favouriteContent.content.description)
|
||||||
|
}
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = if (favouriteContent.isFavourite) R.drawable.favorite_24 else R.drawable.favorite_border_24),
|
||||||
|
contentDescription = null,
|
||||||
|
Modifier.clickable { onFavouriteToggle() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Title() {
|
private fun Title(modifier: Modifier = Modifier) {
|
||||||
Text(
|
Text(
|
||||||
stringResource(id = R.string.login_title),
|
stringResource(id = R.string.login_title),
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = modifier.padding(16.dp),
|
||||||
style = MaterialTheme.typography.h4
|
style = MaterialTheme.typography.h4
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,116 @@
|
||||||
package org.fnives.test.showcase.ui.compose.screen.home
|
package org.fnives.test.showcase.ui.compose.screen.home
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.fnives.test.showcase.core.content.AddContentToFavouriteUseCase
|
import org.fnives.test.showcase.core.content.AddContentToFavouriteUseCase
|
||||||
import org.fnives.test.showcase.core.content.FetchContentUseCase
|
import org.fnives.test.showcase.core.content.FetchContentUseCase
|
||||||
import org.fnives.test.showcase.core.content.GetAllContentUseCase
|
import org.fnives.test.showcase.core.content.GetAllContentUseCase
|
||||||
import org.fnives.test.showcase.core.content.RemoveContentFromFavouritesUseCase
|
import org.fnives.test.showcase.core.content.RemoveContentFromFavouritesUseCase
|
||||||
import org.fnives.test.showcase.core.login.LogoutUseCase
|
import org.fnives.test.showcase.core.login.LogoutUseCase
|
||||||
|
import org.fnives.test.showcase.model.content.ContentId
|
||||||
|
import org.fnives.test.showcase.model.content.FavouriteContent
|
||||||
|
import org.fnives.test.showcase.model.shared.Resource
|
||||||
import org.koin.androidx.compose.get
|
import org.koin.androidx.compose.get
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun rememberHomeScreenState(
|
fun rememberHomeScreenState(
|
||||||
|
stateScope: CoroutineScope = rememberCoroutineScope(),
|
||||||
getAllContentUseCase: GetAllContentUseCase = get(),
|
getAllContentUseCase: GetAllContentUseCase = get(),
|
||||||
logoutUseCase: LogoutUseCase = get(),
|
logoutUseCase: LogoutUseCase = get(),
|
||||||
fetchContentUseCase: FetchContentUseCase = get(),
|
fetchContentUseCase: FetchContentUseCase = get(),
|
||||||
addContentToFavouriteUseCase: AddContentToFavouriteUseCase = get(),
|
addContentToFavouriteUseCase: AddContentToFavouriteUseCase = get(),
|
||||||
removeContentFromFavouritesUseCase: RemoveContentFromFavouritesUseCase = get(),
|
removeContentFromFavouritesUseCase: RemoveContentFromFavouritesUseCase = get(),
|
||||||
|
onLogout: () -> Unit = {},
|
||||||
): HomeScreenState {
|
): HomeScreenState {
|
||||||
return remember {
|
return remember {
|
||||||
HomeScreenState(
|
HomeScreenState(
|
||||||
|
stateScope,
|
||||||
getAllContentUseCase,
|
getAllContentUseCase,
|
||||||
logoutUseCase,
|
logoutUseCase,
|
||||||
fetchContentUseCase,
|
fetchContentUseCase,
|
||||||
addContentToFavouriteUseCase,
|
addContentToFavouriteUseCase,
|
||||||
removeContentFromFavouritesUseCase
|
removeContentFromFavouritesUseCase,
|
||||||
|
onLogout,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomeScreenState(
|
class HomeScreenState(
|
||||||
|
private val stateScope: CoroutineScope,
|
||||||
private val getAllContentUseCase: GetAllContentUseCase,
|
private val getAllContentUseCase: GetAllContentUseCase,
|
||||||
private val logoutUseCase: LogoutUseCase,
|
private val logoutUseCase: LogoutUseCase,
|
||||||
private val fetchContentUseCase: FetchContentUseCase,
|
private val fetchContentUseCase: FetchContentUseCase,
|
||||||
private val addContentToFavouriteUseCase: AddContentToFavouriteUseCase,
|
private val addContentToFavouriteUseCase: AddContentToFavouriteUseCase,
|
||||||
private val removeContentFromFavouritesUseCase: RemoveContentFromFavouritesUseCase
|
private val removeContentFromFavouritesUseCase: RemoveContentFromFavouritesUseCase,
|
||||||
|
private val logoutEvent: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var loading by mutableStateOf(false)
|
var loading by mutableStateOf(false)
|
||||||
private set
|
private set
|
||||||
|
var isError by mutableStateOf(false)
|
||||||
|
private set
|
||||||
|
var content by mutableStateOf<List<FavouriteContent>>(emptyList())
|
||||||
|
private set
|
||||||
|
|
||||||
|
init {
|
||||||
|
stateScope.launch {
|
||||||
|
fetch().collect {
|
||||||
|
content = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetch() = getAllContentUseCase.get()
|
||||||
|
.mapNotNull {
|
||||||
|
when (it) {
|
||||||
|
is Resource.Error -> {
|
||||||
|
isError = true
|
||||||
|
loading = false
|
||||||
|
return@mapNotNull emptyList<FavouriteContent>()
|
||||||
|
}
|
||||||
|
is Resource.Loading -> {
|
||||||
|
isError = false
|
||||||
|
loading = true
|
||||||
|
return@mapNotNull null
|
||||||
|
}
|
||||||
|
is Resource.Success -> {
|
||||||
|
isError = false
|
||||||
|
loading = false
|
||||||
|
return@mapNotNull it.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onLogout() {
|
||||||
|
stateScope.launch {
|
||||||
|
logoutUseCase.invoke()
|
||||||
|
logoutEvent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRefresh() {
|
||||||
|
if (loading) return
|
||||||
|
loading = true
|
||||||
|
stateScope.launch {
|
||||||
|
fetchContentUseCase.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onFavouriteToggleClicked(contentId: ContentId) {
|
||||||
|
stateScope.launch {
|
||||||
|
val item = content.firstOrNull { it.content.id == contentId } ?: return@launch
|
||||||
|
if (item.isFavourite) {
|
||||||
|
removeContentFromFavouritesUseCase.invoke(contentId)
|
||||||
|
} else {
|
||||||
|
addContentToFavouriteUseCase.invoke(contentId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ project.ext {
|
||||||
coroutines_version = "1.6.0"
|
coroutines_version = "1.6.0"
|
||||||
turbine_version = "0.7.0"
|
turbine_version = "0.7.0"
|
||||||
koin_version = "3.1.2"
|
koin_version = "3.1.2"
|
||||||
coil_version = "1.1.1"
|
coil_version = "1.4.0"
|
||||||
retrofit_version = "2.9.0"
|
retrofit_version = "2.9.0"
|
||||||
okhttp_version = "4.9.1"
|
okhttp_version = "4.9.1"
|
||||||
moshi_version = "1.13.0"
|
moshi_version = "1.13.0"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue