Popular bet and refresh
continuous-integration/drone/push Build is passing Details

pull/5/head
avalin 8 months ago
parent b7491a1134
commit 515f6882c0

@ -1,138 +1,37 @@
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.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.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.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.BetFilter
import fr.iut.alldev.allin.ext.textId
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
import fr.iut.alldev.allin.ui.bet.components.BetScreenLoadedContent
import fr.iut.alldev.allin.ui.core.AllInLoading
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
@Composable
fun BetScreen(
viewModel: BetViewModel = hiltViewModel(),
selectBet: (Bet, Boolean) -> Unit,
) {
val bets by viewModel.bets.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle()
val filters by viewModel.filters.collectAsStateWithLifecycle()
val isRefreshing by viewModel.refreshing.collectAsStateWithLifecycle()
val refreshing by viewModel.isRefreshing.collectAsStateWithLifecycle()
val pullRefreshState = rememberPullRefreshState(refreshing, { viewModel.refresh() })
val progressAnimation by animateFloatAsState(pullRefreshState.progress * 15, label = "")
LazyColumn(
modifier = Modifier
.pullRefresh(pullRefreshState)
.padding(top = with(LocalDensity.current) {
progressAnimation.toDp()
}),
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)
when (val s = state) {
is BetViewModel.State.Loaded -> {
BetScreenLoadedContent(
popularBet = s.popularBet,
filters = filters,
bets = s.bets,
isRefreshing = isRefreshing,
selectBet = selectBet,
toggleFilter = { viewModel.toggleFilter(it) },
refreshData = { viewModel.refreshData() }
)
if (idx != bets.lastIndex) {
Spacer(modifier = Modifier.height(24.dp))
}
}
BetViewModel.State.Loading -> {
AllInLoading(visible = true)
}
}
}

@ -8,14 +8,13 @@ import fr.iut.alldev.allin.data.model.bet.BetFilter
import fr.iut.alldev.allin.data.repository.BetRepository
import fr.iut.alldev.allin.keystore.AllInKeystoreManager
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@HiltViewModel
class BetViewModel @Inject constructor(
@ -23,33 +22,23 @@ class BetViewModel @Inject constructor(
private val betRepository: BetRepository
) : ViewModel() {
private val _isRefreshing by lazy { MutableStateFlow(false) }
val isRefreshing: StateFlow<Boolean> get() = _isRefreshing.asStateFlow()
private val _bets: MutableStateFlow<List<Bet>> by lazy {
MutableStateFlow(emptyList())
}
val bets: StateFlow<List<Bet>> by lazy {
_bets.asStateFlow()
.filterNotNull()
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000L),
emptyList()
)
}
private val _filters: MutableStateFlow<List<BetFilter>> by lazy {
MutableStateFlow(BetFilter.entries)
}
private val _state: MutableStateFlow<State> by lazy { MutableStateFlow(State.Loading) }
val state: StateFlow<State> by lazy { _state.asStateFlow() }
private val _filters: MutableStateFlow<List<BetFilter>> by lazy { MutableStateFlow(emptyList()) }
val filters get() = _filters.asStateFlow()
private val _refreshing by lazy { MutableStateFlow(false) }
val refreshing by lazy { _refreshing.asStateFlow() }
init {
viewModelScope.launch {
refreshBets()
filters.collect { refreshBets() }
filters
.debounce(1.seconds)
.collect {
refreshBets()
}
}
}
@ -67,10 +56,18 @@ class BetViewModel @Inject constructor(
private suspend fun refreshBets() {
try {
_bets.emit(
betRepository.getAllBets(
token = keystoreManager.getTokenOrEmpty(),
filters = filters.value
val token = keystoreManager.getTokenOrEmpty()
_state.emit(
State.Loaded(
bets = betRepository.getAllBets(
token = token,
filters = filters.value
),
popularBet = try {
betRepository.getPopularBet(token)
} catch (e: Exception) {
null
}
)
)
} catch (e: Exception) {
@ -78,12 +75,17 @@ class BetViewModel @Inject constructor(
}
}
fun refresh() {
fun refreshData() {
viewModelScope.launch {
_isRefreshing.emit(true)
_refreshing.emit(true)
refreshBets()
_isRefreshing.emit(false)
_refreshing.emit(false)
}
}
sealed interface State {
data object Loading : State
data class Loaded(val bets: List<Bet>, val popularBet: Bet?) : State
}
}

@ -36,14 +36,16 @@ fun BetScreenCard(
date: String,
time: String,
players: List<User>,
modifier: Modifier = Modifier,
onClickParticipate: () -> Unit,
onClickCard: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true
) {
AllInBouncyCard(
modifier = modifier.fillMaxWidth(),
radius = 16.dp,
onClick = onClickCard
onClick = onClickCard,
enabled = enabled
) {
Column(
Modifier.padding(horizontal = 19.dp, vertical = 11.dp)
@ -71,8 +73,10 @@ fun BetScreenCard(
.padding(7.dp),
verticalAlignment = Alignment.CenterVertically
) {
BetProfilePictureRow(pictures = players.map { it.username to null })
Spacer(modifier = Modifier.width(12.dp))
if (players.isNotEmpty()) {
BetProfilePictureRow(pictures = players.map { it.username to null })
Spacer(modifier = Modifier.width(12.dp))
}
Text(
text = pluralStringResource(
id = R.plurals.bet_players_waiting_format,
@ -86,7 +90,8 @@ fun BetScreenCard(
RainbowButton(
modifier = Modifier.padding(6.dp),
text = stringResource(id = R.string.bet_participate),
onClick = onClickParticipate
onClick = onClickParticipate,
enabled = enabled
)
}
}
@ -110,4 +115,41 @@ private fun BetScreenCardPreview() {
onClickCard = {}
)
}
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun BetScreenCardNoPlayersPreview() {
AllInTheme {
BetScreenCard(
creator = "Lucas",
category = "Études",
title = "Emre va réussir son TP de CI/CD mercredi?",
date = "12 Sept.",
time = "13:00",
players = emptyList(),
onClickParticipate = {},
onClickCard = {}
)
}
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun BetScreenCardDisabledPreview() {
AllInTheme {
BetScreenCard(
creator = "Lucas",
category = "Études",
title = "Emre va réussir son TP de CI/CD mercredi?",
date = "12 Sept.",
time = "13:00",
players = emptyList(),
onClickParticipate = {},
onClickCard = {},
enabled = false
)
}
}

@ -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 = { }
)
}
}

@ -26,7 +26,7 @@ import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.ext.shadow
import fr.iut.alldev.allin.theme.AllInColorToken
import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.core.AllInCard
import fr.iut.alldev.allin.ui.core.AllInBouncyCard
import fr.iut.alldev.allin.ui.core.HighlightedText
import kotlin.math.ceil
@ -36,9 +36,11 @@ fun BetScreenPopularCard(
points: Float,
pointUnit: String,
title: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true
) {
AllInCard(
AllInBouncyCard(
modifier = modifier
.let {
if (isSystemInDarkTheme()) {
@ -63,7 +65,9 @@ fun BetScreenPopularCard(
.fillMaxWidth(),
backgroundColor = AllInColorToken.allInDark,
borderWidth = 2.dp,
borderBrush = AllInColorToken.allInMainGradient
borderBrush = AllInColorToken.allInMainGradient,
onClick = onClick,
enabled = enabled
) {
Column(modifier = Modifier.padding(13.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
@ -143,7 +147,8 @@ private fun BetScreenPopularCardPreview() {
nbPlayers = 12,
points = 2.35f,
pointUnit = "k",
title = "Emre va réussir son TP de CI/CD mercredi?"
title = "Emre va réussir son TP de CI/CD mercredi?",
onClick = {}
)
}
}
@ -156,7 +161,8 @@ private fun BetScreenPopularCardSingularPreview() {
nbPlayers = 1,
points = 1.0f,
pointUnit = "",
title = "Emre va réussir son TP de CI/CD mercredi?"
title = "Emre va réussir son TP de CI/CD mercredi?",
onClick = {}
)
}
}

@ -121,11 +121,13 @@ fun AllInBouncyCard(
AllInCard(
modifier = modifier
.combinedClickable(
interactionSource = interactionSource,
indication = null,
onClick = { onClick?.let { it() } }
)
.let {
if (enabled) it.combinedClickable(
interactionSource = interactionSource,
indication = null,
onClick = { onClick?.let { it() } }
) else it
}
.scale(scale),
onClick = null,
radius = radius,

@ -2,8 +2,11 @@ package fr.iut.alldev.allin.ui.core
import android.content.res.Configuration
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -17,12 +20,12 @@ import fr.iut.alldev.allin.theme.AllInColorToken
import fr.iut.alldev.allin.theme.AllInTheme
import racra.compose.smooth_corner_rect_library.AbsoluteSmoothCornerShape
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AllInChip(
text: String,
modifier: Modifier = Modifier,
isSelected: Boolean = false,
enabled: Boolean = true,
onClick: () -> Unit = {},
radius: Dp = 50.dp,
selectedColor: Color = AllInColorToken.allInPurple,
@ -34,10 +37,12 @@ fun AllInChip(
onClick = onClick,
border = if (!isSelected) BorderStroke(1.dp, AllInTheme.colors.border) else null,
colors = CardDefaults.cardColors(
containerColor = if (isSelected) selectedColor else unselectedColor
)
containerColor = if (isSelected) selectedColor else unselectedColor,
disabledContainerColor = if (isSelected) selectedColor else unselectedColor
),
enabled = enabled
) {
Box {
Box{
Text(
text = text,
modifier = Modifier

@ -34,13 +34,9 @@ import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.DialogWindowProvider
import fr.iut.alldev.allin.theme.AllInColorToken
import fr.iut.alldev.allin.theme.AllInTheme
import kotlin.math.PI
@ -59,34 +55,23 @@ fun AllInLoading(
enter = fadeIn(),
exit = fadeOut()
) {
Dialog(
onDismissRequest = {},
properties = DialogProperties(
dismissOnBackPress = false,
dismissOnClickOutside = false,
decorFitsSystemWindows = false,
usePlatformDefaultWidth = false
)
) {
(LocalView.current.parent as DialogWindowProvider).window.setDimAmount(0f)
Box(
modifier = modifier
.fillMaxSize()
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = {}
)
.background(AllInTheme.colors.mainSurface.copy(alpha = .4f))
) {
AllInCircularProgressIndicator(
modifier = Modifier
.align(Alignment.Center)
.size(50.dp),
brush = brush,
strokeWidth = 7.dp
Box(
modifier = modifier
.fillMaxSize()
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = {}
)
}
.background(AllInTheme.colors.mainSurface.copy(alpha = .4f))
) {
AllInCircularProgressIndicator(
modifier = Modifier
.align(Alignment.Center)
.size(50.dp),
brush = brush,
strokeWidth = 7.dp
)
}
}
}
@ -112,7 +97,7 @@ fun AllInCircularProgressIndicator(
durationMillis = RotationDuration * RotationsPerCycle,
easing = LinearEasing
)
)
), label = ""
)
val baseRotation = transition.animateFloat(
0f,

@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@HiltViewModel
class FriendsScreenViewModel @Inject constructor(
@ -40,7 +41,7 @@ class FriendsScreenViewModel @Inject constructor(
}
_search
.debounce(1_000L)
.debounce(1.seconds)
.collect { itSearch ->
try {
_state.emit(

@ -6,6 +6,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import fr.iut.alldev.allin.data.model.FriendStatus
import fr.iut.alldev.allin.data.model.User
import fr.iut.alldev.allin.data.repository.FriendRepository
import fr.iut.alldev.allin.data.repository.UserRepository
import fr.iut.alldev.allin.keystore.AllInKeystoreManager
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
@ -16,6 +17,7 @@ import javax.inject.Inject
@HiltViewModel
class RankingViewModel @Inject constructor(
private val friendRepository: FriendRepository,
private val userRepository: UserRepository,
private val keystoreManager: AllInKeystoreManager
) : ViewModel() {
private val _state by lazy { MutableStateFlow<State>(State.Loading) }
@ -26,9 +28,17 @@ class RankingViewModel @Inject constructor(
try {
_state.emit(
State.Loaded(
friends = friendRepository.getFriends(
token = keystoreManager.getTokenOrEmpty()
).filter { it.friendStatus == FriendStatus.FRIEND }
friends = buildList {
addAll(
friendRepository.getFriends(
token = keystoreManager.getTokenOrEmpty()
).filter { it.friendStatus == FriendStatus.FRIEND }
)
userRepository.currentUserState.value?.let {
add(it)
}
}
)
)
} catch (e: Exception) {

@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import timber.log.Timber
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@HiltViewModel
class SplashScreenViewModel @Inject constructor(
@ -20,7 +21,7 @@ class SplashScreenViewModel @Inject constructor(
) : ViewModel() {
val state: StateFlow<State> by lazy {
flow {
delay(1_000L)
delay(1.seconds)
keystoreManager.getToken()?.let { token ->
runCatching {

@ -78,6 +78,9 @@ interface AllInApi {
@Body body: RequestBetFilters
): List<ResponseBet>
@GET("bets/popular")
suspend fun getPopularBet(@Header("Authorization") token: String): ResponseBet?
@GET("bets/toConfirm")
suspend fun getToConfirm(@Header("Authorization") token: String): List<ResponseBetDetail>

@ -47,7 +47,7 @@ class MockAllInApi : AllInApi {
if (date >= bet.endBet) {
mockBets[idx] = bet.copy(status = BetStatus.CLOSING)
} else {
mockBets[idx] = bet.copy(status = BetStatus.IN_PROGRESS)
mockBets[idx] = bet.copy(status = BetStatus.WAITING)
}
}
}
@ -120,7 +120,7 @@ class MockAllInApi : AllInApi {
isPrivate = body.isPrivate,
response = body.response,
type = BetType.BINARY,
status = BetStatus.WAITING,
status = BetStatus.IN_PROGRESS,
createdBy = getUserFromToken(token)?.first?.username ?: ""
)
)
@ -225,6 +225,10 @@ class MockAllInApi : AllInApi {
}
}
override suspend fun getPopularBet(token: String): ResponseBet? {
return mockBets.firstOrNull()
}
override suspend fun getToConfirm(token: String): List<ResponseBetDetail> {
val user = getUserFromToken(token) ?: throw MockAllInApiException("Invalid login/password.")
return mockBets.filter {

@ -13,6 +13,7 @@ abstract class BetRepository {
abstract suspend fun getBet(id: String, token: String): BetDetail
abstract suspend fun participateToBet(participation: Participation, token: String)
abstract suspend fun getAllBets(token: String, filters: List<BetFilter>): List<Bet>
abstract suspend fun getPopularBet(token: String): Bet?
abstract suspend fun confirmBet(token: String, id: String, response: String)
abstract suspend fun getToConfirm(token: String): List<BetDetail>
abstract suspend fun getWon(token: String): List<BetResultDetail>

@ -54,6 +54,9 @@ class BetRepositoryImpl @Inject constructor(
RequestBetFilters(filters)
).map { it.toBet() }
override suspend fun getPopularBet(token: String): Bet? =
api.getPopularBet(token.formatBearerToken())?.toBet()
override suspend fun getToConfirm(token: String): List<BetDetail> =
api.getToConfirm(token.formatBearerToken()).map { it.toBetDetail() }

Loading…
Cancel
Save