Popular bet and refresh
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
b7491a1134
commit
515f6882c0
@ -1,138 +1,37 @@
|
|||||||
package fr.iut.alldev.allin.ui.bet
|
package fr.iut.alldev.allin.ui.bet
|
||||||
|
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.Brush
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear
|
|
||||||
import fr.iut.alldev.allin.data.ext.formatToTime
|
|
||||||
import fr.iut.alldev.allin.data.model.bet.Bet
|
import fr.iut.alldev.allin.data.model.bet.Bet
|
||||||
import fr.iut.alldev.allin.data.model.bet.BetFilter
|
import fr.iut.alldev.allin.ui.bet.components.BetScreenLoadedContent
|
||||||
import fr.iut.alldev.allin.ext.textId
|
import fr.iut.alldev.allin.ui.core.AllInLoading
|
||||||
import fr.iut.alldev.allin.theme.AllInTheme
|
|
||||||
import fr.iut.alldev.allin.ui.bet.components.BetScreenCard
|
|
||||||
import fr.iut.alldev.allin.ui.bet.components.BetScreenPopularCard
|
|
||||||
import fr.iut.alldev.allin.ui.core.AllInChip
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BetScreen(
|
fun BetScreen(
|
||||||
viewModel: BetViewModel = hiltViewModel(),
|
viewModel: BetViewModel = hiltViewModel(),
|
||||||
selectBet: (Bet, Boolean) -> Unit,
|
selectBet: (Bet, Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
val bets by viewModel.bets.collectAsStateWithLifecycle()
|
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||||
val filters by viewModel.filters.collectAsStateWithLifecycle()
|
val filters by viewModel.filters.collectAsStateWithLifecycle()
|
||||||
|
val isRefreshing by viewModel.refreshing.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
val refreshing by viewModel.isRefreshing.collectAsStateWithLifecycle()
|
when (val s = state) {
|
||||||
val pullRefreshState = rememberPullRefreshState(refreshing, { viewModel.refresh() })
|
is BetViewModel.State.Loaded -> {
|
||||||
val progressAnimation by animateFloatAsState(pullRefreshState.progress * 15, label = "")
|
BetScreenLoadedContent(
|
||||||
|
popularBet = s.popularBet,
|
||||||
LazyColumn(
|
filters = filters,
|
||||||
modifier = Modifier
|
bets = s.bets,
|
||||||
.pullRefresh(pullRefreshState)
|
isRefreshing = isRefreshing,
|
||||||
.padding(top = with(LocalDensity.current) {
|
selectBet = selectBet,
|
||||||
progressAnimation.toDp()
|
toggleFilter = { viewModel.toggleFilter(it) },
|
||||||
}),
|
refreshData = { viewModel.refreshData() }
|
||||||
contentPadding = WindowInsets.navigationBars.asPaddingValues(),
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
Box(
|
|
||||||
Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
BetScreenPopularCard(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = 13.dp, bottom = 10.dp)
|
|
||||||
.padding(horizontal = 13.dp),
|
|
||||||
nbPlayers = 12,
|
|
||||||
points = 2.35f,
|
|
||||||
pointUnit = "k",
|
|
||||||
title = "Emre va réussir son TP de CI/CD mercredi?"
|
|
||||||
)
|
|
||||||
PullRefreshIndicator(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.TopCenter),
|
|
||||||
refreshing = refreshing,
|
|
||||||
state = pullRefreshState
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stickyHeader {
|
|
||||||
LazyRow(
|
|
||||||
modifier = Modifier
|
|
||||||
.background(
|
|
||||||
Brush.verticalGradient(
|
|
||||||
0.5f to AllInTheme.colors.mainSurface,
|
|
||||||
1f to Color.Transparent
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.padding(top = 5.dp, bottom = 19.dp),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(9.dp),
|
|
||||||
contentPadding = PaddingValues(horizontal = 23.dp)
|
|
||||||
) {
|
|
||||||
items(BetFilter.entries) {
|
|
||||||
val isSelected by remember {
|
|
||||||
derivedStateOf {
|
|
||||||
filters.contains(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AllInChip(
|
|
||||||
text = stringResource(id = it.textId()),
|
|
||||||
isSelected = isSelected,
|
|
||||||
onClick = { viewModel.toggleFilter(it) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
itemsIndexed(
|
|
||||||
items = bets,
|
|
||||||
key = { _, it -> it.id }
|
|
||||||
) { idx, it ->
|
|
||||||
BetScreenCard(
|
|
||||||
creator = it.creator,
|
|
||||||
category = it.theme,
|
|
||||||
title = it.phrase,
|
|
||||||
date = it.endRegisterDate.formatToMediumDateNoYear(),
|
|
||||||
time = it.endRegisterDate.formatToTime(),
|
|
||||||
players = emptyList(), // TODO : Players
|
|
||||||
onClickParticipate = { selectBet(it, true) },
|
|
||||||
onClickCard = { selectBet(it, false) },
|
|
||||||
modifier = Modifier
|
|
||||||
.animateItemPlacement()
|
|
||||||
.padding(horizontal = 23.dp)
|
|
||||||
)
|
)
|
||||||
if (idx != bets.lastIndex) {
|
}
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
}
|
BetViewModel.State.Loading -> {
|
||||||
|
AllInLoading(visible = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
package fr.iut.alldev.allin.ui.bet.components
|
||||||
|
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||||
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.zIndex
|
||||||
|
import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear
|
||||||
|
import fr.iut.alldev.allin.data.ext.formatToTime
|
||||||
|
import fr.iut.alldev.allin.data.model.bet.Bet
|
||||||
|
import fr.iut.alldev.allin.data.model.bet.BetFilter
|
||||||
|
import fr.iut.alldev.allin.data.model.bet.BetStatus
|
||||||
|
import fr.iut.alldev.allin.data.model.bet.BinaryBet
|
||||||
|
import fr.iut.alldev.allin.ext.textId
|
||||||
|
import fr.iut.alldev.allin.theme.AllInTheme
|
||||||
|
import fr.iut.alldev.allin.ui.core.AllInChip
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
|
private const val DISABLED_OPACITY = .5f
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BetScreenLoadedContent(
|
||||||
|
popularBet: Bet?,
|
||||||
|
filters: List<BetFilter>,
|
||||||
|
bets: List<Bet>,
|
||||||
|
isRefreshing: Boolean,
|
||||||
|
selectBet: (Bet, Boolean) -> Unit,
|
||||||
|
toggleFilter: (BetFilter) -> Unit,
|
||||||
|
refreshData: () -> Unit
|
||||||
|
) {
|
||||||
|
val pullRefreshState = rememberPullRefreshState(isRefreshing, refreshData)
|
||||||
|
val progressAnimation by animateFloatAsState(pullRefreshState.progress * 15, label = "")
|
||||||
|
|
||||||
|
Box(Modifier.fillMaxSize()) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.pullRefresh(pullRefreshState)
|
||||||
|
.padding(top = with(LocalDensity.current) {
|
||||||
|
progressAnimation.toDp()
|
||||||
|
}),
|
||||||
|
contentPadding = WindowInsets.navigationBars.asPaddingValues(),
|
||||||
|
) {
|
||||||
|
popularBet?.let {
|
||||||
|
item {
|
||||||
|
Box(Modifier.fillMaxWidth()) {
|
||||||
|
BetScreenPopularCard(
|
||||||
|
nbPlayers = 12, // Todo : Players
|
||||||
|
points = 2.35f, // Todo : Points
|
||||||
|
pointUnit = "k",
|
||||||
|
title = it.phrase,
|
||||||
|
onClick = { selectBet(it, false) },
|
||||||
|
enabled = !isRefreshing,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 13.dp, bottom = 10.dp)
|
||||||
|
.padding(horizontal = 13.dp)
|
||||||
|
.let {
|
||||||
|
if (isRefreshing) it.alpha(DISABLED_OPACITY)
|
||||||
|
else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stickyHeader {
|
||||||
|
LazyRow(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
Brush.verticalGradient(
|
||||||
|
0.5f to AllInTheme.colors.mainSurface,
|
||||||
|
1f to Color.Transparent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.zIndex(1f),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(9.dp),
|
||||||
|
contentPadding = PaddingValues(horizontal = 23.dp)
|
||||||
|
) {
|
||||||
|
items(BetFilter.entries) {
|
||||||
|
val isSelected by remember(filters) {
|
||||||
|
derivedStateOf {
|
||||||
|
filters.contains(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AllInChip(
|
||||||
|
text = stringResource(id = it.textId()),
|
||||||
|
isSelected = isSelected,
|
||||||
|
onClick = { toggleFilter(it) },
|
||||||
|
enabled = !isRefreshing,
|
||||||
|
modifier = Modifier.let {
|
||||||
|
if (isRefreshing) it.alpha(DISABLED_OPACITY)
|
||||||
|
else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemsIndexed(
|
||||||
|
items = bets,
|
||||||
|
key = { _, it -> it.id }
|
||||||
|
) { idx, it ->
|
||||||
|
BetScreenCard(
|
||||||
|
creator = it.creator,
|
||||||
|
category = it.theme,
|
||||||
|
title = it.phrase,
|
||||||
|
date = it.endRegisterDate.formatToMediumDateNoYear(),
|
||||||
|
time = it.endRegisterDate.formatToTime(),
|
||||||
|
players = emptyList(), // TODO : Players
|
||||||
|
onClickParticipate = { selectBet(it, true) },
|
||||||
|
onClickCard = { selectBet(it, false) },
|
||||||
|
enabled = !isRefreshing,
|
||||||
|
modifier = Modifier
|
||||||
|
.animateItemPlacement()
|
||||||
|
.padding(horizontal = 23.dp)
|
||||||
|
.let {
|
||||||
|
if (isRefreshing) it.alpha(DISABLED_OPACITY)
|
||||||
|
else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (idx != bets.lastIndex) {
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PullRefreshIndicator(
|
||||||
|
modifier = Modifier.align(Alignment.TopCenter),
|
||||||
|
refreshing = isRefreshing,
|
||||||
|
state = pullRefreshState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun BetScreenLoadedContentPreview() {
|
||||||
|
AllInTheme {
|
||||||
|
BetScreenLoadedContent(
|
||||||
|
popularBet = BinaryBet(
|
||||||
|
id = "Arleen",
|
||||||
|
creator = "Omar",
|
||||||
|
theme = "Kyli",
|
||||||
|
phrase = "Leigha",
|
||||||
|
endRegisterDate = ZonedDateTime.now(),
|
||||||
|
endBetDate = ZonedDateTime.now(),
|
||||||
|
isPublic = false,
|
||||||
|
betStatus = BetStatus.IN_PROGRESS
|
||||||
|
),
|
||||||
|
filters = emptyList(),
|
||||||
|
bets = emptyList(),
|
||||||
|
isRefreshing = true,
|
||||||
|
selectBet = { _, _ -> },
|
||||||
|
toggleFilter = { },
|
||||||
|
refreshData = { }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue