Fix events
continuous-integration/drone/push Build is passing Details

pull/4/head
Arthur VALIN 1 year ago
parent 58d788f58f
commit 53b6eacfff

@ -11,7 +11,7 @@ object Bets {
endRegisterDate = ZonedDateTime.now(), endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(),
isPublic = true, isPublic = true,
betStatus = BetStatus.InProgress, betStatus = BetStatus.IN_PROGRESS,
creator = "creator", creator = "creator",
id = "" id = ""
), ),
@ -21,7 +21,7 @@ object Bets {
endRegisterDate = ZonedDateTime.now(), endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(),
isPublic = true, isPublic = true,
betStatus = BetStatus.InProgress, betStatus = BetStatus.IN_PROGRESS,
nameTeam1 = "Team_1", nameTeam1 = "Team_1",
nameTeam2 = "Team_2", nameTeam2 = "Team_2",
creator = "creator", creator = "creator",
@ -33,7 +33,7 @@ object Bets {
endRegisterDate = ZonedDateTime.now(), endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(),
isPublic = true, isPublic = true,
betStatus = BetStatus.InProgress, betStatus = BetStatus.IN_PROGRESS,
creator = "creator", creator = "creator",
possibleAnswers = listOf( possibleAnswers = listOf(
"Answer 1", "Answer 1",

@ -6,24 +6,24 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import fr.iut.alldev.allin.R import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus.LOST
import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus.WON
import fr.iut.alldev.allin.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.theme.AllInTheme
@StringRes @StringRes
fun BetStatus.getTitleId(): Int { fun BetStatus.getTitleId(): Int {
return when (this) { return when (this) {
is BetStatus.Finished -> R.string.bet_status_finished BetStatus.IN_PROGRESS -> R.string.bet_status_in_progress
BetStatus.InProgress -> R.string.bet_status_in_progress BetStatus.WAITING -> R.string.bet_status_waiting
BetStatus.Waiting -> R.string.bet_status_waiting BetStatus.CLOSING -> R.string.bet_status_closing
BetStatus.FINISHED -> R.string.bet_status_finished
BetStatus.CANCELLED -> R.string.bet_status_cancelled
} }
} }
@StringRes @StringRes
fun BetStatus.getDateStartLabelId(): Int { fun BetStatus.getDateStartLabelId(): Int {
return when (this) { return when (this) {
is BetStatus.Finished -> R.string.Started BetStatus.CLOSING, BetStatus.FINISHED, BetStatus.CANCELLED -> R.string.Started
else -> R.string.Starting else -> R.string.Starting
} }
} }
@ -31,7 +31,7 @@ fun BetStatus.getDateStartLabelId(): Int {
@StringRes @StringRes
fun BetStatus.getDateEndLabelId(): Int { fun BetStatus.getDateEndLabelId(): Int {
return when (this) { return when (this) {
is BetStatus.Finished -> R.string.Ended BetStatus.CLOSING, BetStatus.FINISHED, BetStatus.CANCELLED -> R.string.Ended
else -> R.string.Ends else -> R.string.Ends
} }
} }
@ -39,40 +39,38 @@ fun BetStatus.getDateEndLabelId(): Int {
@Composable @Composable
fun BetStatus.getColor(): Color { fun BetStatus.getColor(): Color {
return when (this) { return when (this) {
is BetStatus.Finished -> AllInTheme.colors.allInBetFinish BetStatus.FINISHED -> AllInTheme.colors.allInBetFinish
BetStatus.InProgress -> AllInTheme.colors.allInBetInProgress BetStatus.IN_PROGRESS -> AllInTheme.colors.allInBetInProgress
BetStatus.Waiting -> AllInTheme.colors.allInBetWaiting BetStatus.WAITING -> AllInTheme.colors.allInBetWaiting
else -> AllInTheme.colors.allInBetFinish // TODO
} }
} }
@Composable @Composable
fun BetStatus.getTextColor(): Color { fun BetStatus.getTextColor(): Color {
return when (this) { return when (this) {
is BetStatus.Finished -> AllInTheme.colors.allInBetFinishText BetStatus.FINISHED -> AllInTheme.colors.allInBetFinishText
BetStatus.InProgress -> AllInTheme.colors.allInBetInProgressText BetStatus.IN_PROGRESS -> AllInTheme.colors.allInBetInProgressText
BetStatus.Waiting -> AllInTheme.colors.allInBetWaitingText BetStatus.WAITING -> AllInTheme.colors.allInBetWaitingText
else -> AllInTheme.colors.allInBetFinishText // TODO
} }
} }
@StringRes @StringRes
fun BetStatus.getBetHistoryPhrase(): Int { fun BetStatus.getBetHistoryPhrase(won: Boolean): Int {
return when (this) { return when (this) {
is BetStatus.Finished -> when (this.status) { BetStatus.FINISHED ->
WON -> R.string.bet_history_status_won if (won) R.string.bet_history_status_won else R.string.bet_history_status_lost
LOST -> R.string.bet_history_status_lost
}
else -> R.string.bet_history_status_in_progress else -> R.string.bet_history_status_in_progress
} }
} }
@Composable @Composable
fun BetStatus.getBetHistoryStatusColor(): Brush { fun BetStatus.getBetHistoryStatusColor(won: Boolean): Brush {
return when (this) { return when (this) {
is BetStatus.Finished -> when (this.status) { BetStatus.FINISHED ->
WON -> AllInTheme.colors.allInMainGradient if (won) AllInTheme.colors.allInMainGradient else AllInTheme.colors.allInDarkGradient
LOST -> AllInTheme.colors.allInDarkGradient
}
else -> SolidColor(AllInTheme.colors.allInDarkGrey100) else -> SolidColor(AllInTheme.colors.allInDarkGrey100)
} }

@ -12,7 +12,7 @@ import fr.iut.alldev.allin.data.model.bet.BetType
@StringRes @StringRes
fun BetType.getTitleId(): Int { fun BetType.getTitleId(): Int {
return when (this) { return when (this) {
BetType.YES_NO -> R.string.yes_no BetType.BINARY -> R.string.yes_no
BetType.MATCH -> R.string.sport_match BetType.MATCH -> R.string.sport_match
BetType.CUSTOM -> R.string.custom_answers BetType.CUSTOM -> R.string.custom_answers
} }
@ -20,7 +20,7 @@ fun BetType.getTitleId(): Int {
fun BetType.getIcon(): ImageVector { fun BetType.getIcon(): ImageVector {
return when (this) { return when (this) {
BetType.YES_NO -> Icons.AutoMirrored.Default.HelpOutline BetType.BINARY -> Icons.AutoMirrored.Default.HelpOutline
BetType.MATCH -> Icons.Default.SportsSoccer BetType.MATCH -> Icons.Default.SportsSoccer
BetType.CUSTOM -> Icons.Default.Edit BetType.CUSTOM -> Icons.Default.Edit
} }

@ -8,4 +8,5 @@ abstract class AllInKeystoreManager {
abstract fun putToken(token: String) abstract fun putToken(token: String)
abstract fun getToken(): String? abstract fun getToken(): String?
abstract fun deleteToken() abstract fun deleteToken()
fun getTokenOrEmpty() = getToken() ?: ""
} }

@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import fr.iut.alldev.allin.data.model.bet.Bet import fr.iut.alldev.allin.data.model.bet.Bet
import fr.iut.alldev.allin.data.repository.BetRepository import fr.iut.alldev.allin.data.repository.BetRepository
import fr.iut.alldev.allin.keystore.AllInKeystoreManager
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -16,6 +17,7 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class BetViewModel @Inject constructor( class BetViewModel @Inject constructor(
private val keystoreManager: AllInKeystoreManager,
private val betRepository: BetRepository private val betRepository: BetRepository
) : ViewModel() { ) : ViewModel() {
@ -45,7 +47,7 @@ class BetViewModel @Inject constructor(
private suspend fun refreshData() { private suspend fun refreshData() {
runCatching { runCatching {
_bets.emit(betRepository.getAllBets()) _bets.emit(betRepository.getAllBets(keystoreManager.getTokenOrEmpty()))
} }
} }

@ -41,7 +41,6 @@ import androidx.core.os.ConfigurationCompat
import fr.iut.alldev.allin.R import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear
import fr.iut.alldev.allin.data.ext.formatToTime import fr.iut.alldev.allin.data.ext.formatToTime
import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus
import fr.iut.alldev.allin.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.data.model.bet.CustomBet import fr.iut.alldev.allin.data.model.bet.CustomBet
import fr.iut.alldev.allin.data.model.bet.MatchBet import fr.iut.alldev.allin.data.model.bet.MatchBet
@ -140,7 +139,8 @@ fun ConfirmationAnswers(
onClick: (String) -> Unit onClick: (String) -> Unit
) { ) {
val configuration = LocalConfiguration.current val configuration = LocalConfiguration.current
val locale = remember { ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault() } val locale =
remember { ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault() }
LazyColumn( LazyColumn(
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(8.dp)
@ -148,7 +148,10 @@ fun ConfirmationAnswers(
when (betDetail.bet) { when (betDetail.bet) {
is CustomBet -> items((betDetail.bet as CustomBet).possibleAnswers) { is CustomBet -> items((betDetail.bet as CustomBet).possibleAnswers) {
betDetail.getAnswerOfResponse(it)?.let { betDetail.getAnswerOfResponse(it)?.let {
val opacity by animateFloatAsState(targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f, label = "") val opacity by animateFloatAsState(
targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f,
label = ""
)
BetConfirmationBottomSheetAnswer( BetConfirmationBottomSheetAnswer(
@ -166,7 +169,10 @@ fun ConfirmationAnswers(
val bet = (betDetail.bet as MatchBet) val bet = (betDetail.bet as MatchBet)
item { item {
betDetail.getAnswerOfResponse(bet.nameTeam1)?.let { betDetail.getAnswerOfResponse(bet.nameTeam1)?.let {
val opacity by animateFloatAsState(targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f, label = "") val opacity by animateFloatAsState(
targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f,
label = ""
)
BetConfirmationBottomSheetAnswer( BetConfirmationBottomSheetAnswer(
text = it.response, text = it.response,
odds = it.odds, odds = it.odds,
@ -179,7 +185,10 @@ fun ConfirmationAnswers(
} }
item { item {
betDetail.getAnswerOfResponse(bet.nameTeam2)?.let { betDetail.getAnswerOfResponse(bet.nameTeam2)?.let {
val opacity by animateFloatAsState(targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f, label = "") val opacity by animateFloatAsState(
targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f,
label = ""
)
BetConfirmationBottomSheetAnswer( BetConfirmationBottomSheetAnswer(
text = it.response, text = it.response,
@ -198,7 +207,10 @@ fun ConfirmationAnswers(
is YesNoBet -> { is YesNoBet -> {
item { item {
betDetail.getAnswerOfResponse(YES_VALUE)?.let { betDetail.getAnswerOfResponse(YES_VALUE)?.let {
val opacity by animateFloatAsState(targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f, label = "") val opacity by animateFloatAsState(
targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f,
label = ""
)
val scale by animateFloatAsState( val scale by animateFloatAsState(
targetValue = if (selectedAnswer == null) 1f targetValue = if (selectedAnswer == null) 1f
else if (selectedAnswer != it.response) .95f else 1.05f, else if (selectedAnswer != it.response) .95f else 1.05f,
@ -219,10 +231,13 @@ fun ConfirmationAnswers(
} }
item { item {
betDetail.getAnswerOfResponse(NO_VALUE)?.let { betDetail.getAnswerOfResponse(NO_VALUE)?.let {
val opacity by animateFloatAsState(targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f, label = "") val opacity by animateFloatAsState(
targetValue = if (selectedAnswer != null && selectedAnswer != it.response) .5f else 1f,
label = ""
)
val scale by animateFloatAsState( val scale by animateFloatAsState(
targetValue = if (selectedAnswer == null) 1f targetValue = if (selectedAnswer == null) 1f
else if (selectedAnswer != it.response) .95f else 1.05f, else if (selectedAnswer != it.response) .95f else 1f,
label = "" label = ""
) )
@ -358,7 +373,7 @@ private fun BetConfirmationBottomSheetContentPreview() {
endRegisterDate = ZonedDateTime.now(), endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(),
isPublic = true, isPublic = true,
betStatus = BetStatus.Finished(BetFinishedStatus.WON), betStatus = BetStatus.FINISHED,
creator = "creator", creator = "creator",
), ),
answers = listOf( answers = listOf(

@ -30,7 +30,7 @@ class BetCreationViewModel @Inject constructor(
val registerDate = mutableStateOf(ZonedDateTime.now()) val registerDate = mutableStateOf(ZonedDateTime.now())
val betDate = mutableStateOf(ZonedDateTime.now()) val betDate = mutableStateOf(ZonedDateTime.now())
var isPublic = mutableStateOf(true) var isPublic = mutableStateOf(true)
var selectedBetType = mutableStateOf(BetType.YES_NO) var selectedBetType = mutableStateOf(BetType.BINARY)
val themeError = mutableStateOf<FieldErrorState>(FieldErrorState.NoError) val themeError = mutableStateOf<FieldErrorState>(FieldErrorState.NoError)
val phraseError = mutableStateOf<FieldErrorState>(FieldErrorState.NoError) val phraseError = mutableStateOf<FieldErrorState>(FieldErrorState.NoError)
@ -111,7 +111,7 @@ class BetCreationViewModel @Inject constructor(
possibleAnswers = listOf(), possibleAnswers = listOf(),
creator = currentUser.username creator = currentUser.username
) )
betRepository.createBet(bet, keystoreManager.getToken() ?: "") betRepository.createBet(bet, keystoreManager.getTokenOrEmpty())
onSuccess() onSuccess()
} catch (e: AllInAPIException) { } catch (e: AllInAPIException) {
Timber.e(e) Timber.e(e)

@ -43,7 +43,7 @@ fun BetCreationScreenAnswerTab(
) )
Spacer(modifier = Modifier.height(26.dp)) Spacer(modifier = Modifier.height(26.dp))
when (selectedBetType) { when (selectedBetType) {
BetType.YES_NO -> { BetType.BINARY -> {
Column( Column(
modifier = Modifier.padding(vertical = 20.dp), modifier = Modifier.padding(vertical = 20.dp),
verticalArrangement = Arrangement.spacedBy(17.dp) verticalArrangement = Arrangement.spacedBy(17.dp)

@ -0,0 +1,30 @@
package fr.iut.alldev.allin.ui.betHistory
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear
import fr.iut.alldev.allin.data.ext.formatToTime
import fr.iut.alldev.allin.ui.betHistory.components.GenericHistory
@Composable
fun BetCurrentScreen(
viewModel: BetCurrentViewModel = hiltViewModel()
) {
val bets by viewModel.bets.collectAsState()
GenericHistory(
title = stringResource(id = R.string.bet_history_current_title),
bets = bets,
getTitle = { it.bet.phrase },
getCreator = { it.bet.creator },
getCategory = { it.bet.theme },
getEndRegisterDate = { it.bet.endRegisterDate.formatToMediumDateNoYear() },
getEndBetTime = { it.bet.endBetDate.formatToTime() },
getStatus = { it.bet.betStatus },
getNbCoins = { it.userParticipation?.stake ?: 0 },
getWon = { true }
)
}

@ -0,0 +1,44 @@
package fr.iut.alldev.allin.ui.betHistory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import fr.iut.alldev.allin.data.model.bet.vo.BetDetail
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.launch
import javax.inject.Inject
@HiltViewModel
class BetCurrentViewModel @Inject constructor(
private val betRepository: BetRepository,
private val keystoreManager: AllInKeystoreManager
) : ViewModel() {
private val _bets: MutableStateFlow<List<BetDetail>> by lazy {
MutableStateFlow(emptyList())
}
val bets: StateFlow<List<BetDetail>> by lazy {
_bets.asStateFlow()
.filterNotNull()
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000L),
emptyList()
)
}
init {
viewModelScope.launch {
_bets.emit(
betRepository.getToConfirm(keystoreManager.getTokenOrEmpty())
)
}
}
}

@ -1,65 +1,30 @@
package fr.iut.alldev.allin.ui.betHistory package fr.iut.alldev.allin.ui.betHistory
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import fr.iut.alldev.allin.R import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear
import fr.iut.alldev.allin.data.ext.formatToTime import fr.iut.alldev.allin.data.ext.formatToTime
import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.ui.betHistory.components.GenericHistory
import fr.iut.alldev.allin.ui.betHistory.components.BetHistoryScreenCard
@Composable @Composable
fun BetHistoryScreen( fun BetHistoryScreen(
isCurrent: Boolean, viewModel: BetHistoryViewModel = hiltViewModel()
viewModel: BetHistoryViewModel = hiltViewModel(),
) { ) {
val bets by viewModel.bets.collectAsState() val bets by viewModel.bets.collectAsState()
GenericHistory(
LazyColumn( title = stringResource(id = R.string.bet_history_title),
modifier = Modifier.fillMaxSize(), bets = bets,
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 18.dp), getTitle = { it.bet.phrase },
verticalArrangement = Arrangement.spacedBy(18.dp), getCreator = { it.bet.creator },
) { getCategory = { it.bet.theme },
item { getEndRegisterDate = { it.bet.endRegisterDate.formatToMediumDateNoYear() },
Text( getEndBetTime = { it.bet.endBetDate.formatToTime() },
text = stringResource( getStatus = { it.bet.betStatus },
id = if (isCurrent) R.string.bet_history_current_title getNbCoins = { it.amount },
else R.string.bet_history_title getWon = { it.won }
),
style = AllInTheme.typography.h1,
color = AllInTheme.colors.allInGrey,
fontSize = 24.sp,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
}
bets?.let { bets ->
items(bets) {
BetHistoryScreenCard(
title = it.phrase,
creator = it.creator,
category = it.theme,
date = it.endRegisterDate.formatToMediumDateNoYear(),
time = it.endRegisterDate.formatToTime(),
status = it.betStatus,
nbCoins = 230
) )
}
}
}
} }

@ -1,35 +1,44 @@
package fr.iut.alldev.allin.ui.betHistory package fr.iut.alldev.allin.ui.betHistory
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import fr.iut.alldev.allin.data.model.bet.Bet import fr.iut.alldev.allin.data.model.bet.BetResultDetail
import fr.iut.alldev.allin.data.repository.BetRepository import fr.iut.alldev.allin.data.repository.BetRepository
import fr.iut.alldev.allin.ui.navigation.NavArguments import fr.iut.alldev.allin.keystore.AllInKeystoreManager
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class BetHistoryViewModel @Inject constructor( class BetHistoryViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val betRepository: BetRepository, private val betRepository: BetRepository,
private val keystoreManager: AllInKeystoreManager
) : ViewModel() { ) : ViewModel() {
private val isCurrent: Boolean? = savedStateHandle[NavArguments.ARG_BET_HISTORY_IS_CURRENT] private val _bets: MutableStateFlow<List<BetResultDetail>> by lazy {
MutableStateFlow(emptyList())
}
val bets: StateFlow<List<Bet>?> by lazy { val bets: StateFlow<List<BetResultDetail>> by lazy {
flowOf(isCurrent).filterNotNull().flatMapConcat { _bets.asStateFlow()
if (it) betRepository.getCurrentBets() .filterNotNull()
else betRepository.getHistory() .stateIn(
}.stateIn(
viewModelScope, viewModelScope,
SharingStarted.WhileSubscribed(5_000L), SharingStarted.WhileSubscribed(5_000L),
null emptyList()
) )
} }
init {
viewModelScope.launch {
_bets.emit(
betRepository.getHistory(keystoreManager.getTokenOrEmpty())
)
}
}
} }

@ -51,14 +51,15 @@ val betHistoryStatusInlineContent = mapOf(
@Composable @Composable
fun BetHistoryBetStatus( fun BetHistoryBetStatus(
status: BetStatus, status: BetStatus,
won: Boolean,
nbCoins: Int, nbCoins: Int,
) { ) {
val betHistoryPhrase = stringResource(id = status.getBetHistoryPhrase(), nbCoins) val betHistoryPhrase = stringResource(id = status.getBetHistoryPhrase(won), nbCoins)
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(status.getBetHistoryStatusColor()) .background(status.getBetHistoryStatusColor(won))
.padding(16.dp), .padding(16.dp),
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
@ -85,7 +86,8 @@ private fun BetHistoryBetStatusPreview(
AllInTheme { AllInTheme {
BetHistoryBetStatus( BetHistoryBetStatus(
status = betStatus, status = betStatus,
nbCoins = 230 nbCoins = 230,
won = true
) )
} }
} }

@ -20,6 +20,7 @@ fun BetHistoryScreenCard(
time: String, time: String,
status: BetStatus, status: BetStatus,
nbCoins: Int, nbCoins: Int,
won: Boolean
) { ) {
BetCard( BetCard(
title = title, title = title,
@ -32,7 +33,8 @@ fun BetHistoryScreenCard(
) { ) {
BetHistoryBetStatus( BetHistoryBetStatus(
status = status, status = status,
nbCoins = nbCoins nbCoins = nbCoins,
won = won
) )
} }
} }
@ -51,7 +53,8 @@ private fun BetHistoryScreenCardPreview(
date = "Date", date = "Date",
time = "Time", time = "Time",
status = betStatus, status = betStatus,
nbCoins = 123 nbCoins = 123,
won = true
) )
} }
} }

@ -0,0 +1,60 @@
package fr.iut.alldev.allin.ui.betHistory.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.theme.AllInTheme
@Composable
fun <T> GenericHistory(
title: String,
bets: List<T>,
getTitle: (T) -> String,
getCreator: (T) -> String,
getCategory: (T) -> String,
getEndRegisterDate: (T) -> String,
getEndBetTime: (T) -> String,
getStatus: (T) -> BetStatus,
getNbCoins: (T) -> Int,
getWon: (T) -> Boolean,
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 18.dp),
verticalArrangement = Arrangement.spacedBy(18.dp),
) {
item {
Text(
text = title,
style = AllInTheme.typography.h1,
color = AllInTheme.colors.allInGrey,
fontSize = 24.sp,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
}
items(bets) {
BetHistoryScreenCard(
title = getTitle(it),
creator = getCreator(it),
category = getCategory(it),
date = getEndRegisterDate(it),
time = getEndBetTime(it),
status = getStatus(it),
nbCoins = getNbCoins(it),
won = getWon(it)
)
}
}
}

@ -139,7 +139,7 @@ private fun BetResultBottomSheetContentPreview() {
endRegisterDate = ZonedDateTime.now(), endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(),
isPublic = true, isPublic = true,
betStatus = BetStatus.InProgress, betStatus = BetStatus.IN_PROGRESS,
creator = "creator", creator = "creator",
), ),
stake = 4175, stake = 4175,

@ -4,7 +4,6 @@ import android.content.res.Configuration
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus
import fr.iut.alldev.allin.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.core.bet.BetCard import fr.iut.alldev.allin.ui.core.bet.BetCard
@ -51,7 +50,7 @@ private fun BetResultBottomSheetBetCardPreview() {
title = "Title", title = "Title",
date = "Date", date = "Date",
time = "Time", time = "Time",
status = BetStatus.Finished(BetFinishedStatus.WON), status = BetStatus.FINISHED,
stake = 2446, stake = 2446,
winnings = 6930, winnings = 6930,
odds = 2.3f odds = 2.3f

@ -1,9 +1,21 @@
package fr.iut.alldev.allin.ui.betStatus package fr.iut.alldev.allin.ui.betStatus
import androidx.compose.animation.* import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.* import androidx.compose.animation.slideInVertically
import androidx.compose.material3.* import androidx.compose.animation.slideOutVertically
import androidx.compose.runtime.* import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SheetState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import fr.iut.alldev.allin.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.BetStatus
@ -56,7 +68,7 @@ fun BetStatusBottomSheet(
scrimColor = Color.Transparent scrimColor = Color.Transparent
) { ) {
var selectedAnswer by remember { mutableStateOf(0) } var selectedAnswer by remember { mutableIntStateOf(0) }
var stake by remember { mutableStateOf<Int?>(null) } var stake by remember { mutableStateOf<Int?>(null) }
Column( Column(
@ -67,7 +79,9 @@ fun BetStatusBottomSheet(
displayBet(it) displayBet(it)
BetStatusParticipationBottomSheet( BetStatusParticipationBottomSheet(
sheetVisibility = participateSheetVisibility && betDetail.bet.betStatus == BetStatus.Waiting && state.hasExpandedState, sheetVisibility = participateSheetVisibility &&
betDetail.bet.betStatus == BetStatus.IN_PROGRESS &&
state.hasExpandedState,
safeBottomPadding = paddingValues.calculateBottomPadding(), safeBottomPadding = paddingValues.calculateBottomPadding(),
odds = betDetail.answers.getOrNull(selectedAnswer)?.odds ?: 1f, odds = betDetail.answers.getOrNull(selectedAnswer)?.odds ?: 1f,
betPhrase = betDetail.bet.phrase, betPhrase = betDetail.bet.phrase,

@ -2,7 +2,19 @@ package fr.iut.alldev.allin.ui.betStatus.vo
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -12,7 +24,9 @@ import androidx.compose.material.icons.filled.WorkspacePremium
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.graphics.vector.rememberVectorPainter
@ -65,7 +79,8 @@ class BetStatusBottomSheetBetDisplayer(
) { ) {
val safeBottomPadding = paddingValues.value.calculateBottomPadding() val safeBottomPadding = paddingValues.value.calculateBottomPadding()
val configuration = LocalConfiguration.current val configuration = LocalConfiguration.current
val locale = remember { ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault() } val locale =
remember { ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault() }
val response1Answer = remember { betDetail.getAnswerOfResponse(response1) } val response1Answer = remember { betDetail.getAnswerOfResponse(response1) }
val response2Answer = remember { betDetail.getAnswerOfResponse(response2) } val response2Answer = remember { betDetail.getAnswerOfResponse(response2) }
@ -99,7 +114,7 @@ class BetStatusBottomSheetBetDisplayer(
} }
Spacer(modifier = Modifier.height(20.dp)) Spacer(modifier = Modifier.height(20.dp))
} }
if (betDetail.bet.betStatus is BetStatus.Finished) { if (betDetail.bet.betStatus == BetStatus.FINISHED) {
BetStatusWinner( BetStatusWinner(
answer = response1Display, answer = response1Display,
color = AllInTheme.colors.allInBlue, color = AllInTheme.colors.allInBlue,
@ -119,8 +134,10 @@ class BetStatusBottomSheetBetDisplayer(
Spacer(modifier = Modifier.height(20.dp)) Spacer(modifier = Modifier.height(20.dp))
BinaryStatBar( BinaryStatBar(
response1Percentage = remember { response1Percentage = remember {
val total = (response1Answer?.totalParticipants ?: 0) + (response2Answer?.totalParticipants ?: 0) val total = (response1Answer?.totalParticipants
if (total == 0) .5f else (response1Answer?.totalParticipants ?: 0) / total.toFloat() ?: 0) + (response2Answer?.totalParticipants ?: 0)
if (total == 0) .5f else (response1Answer?.totalParticipants
?: 0) / total.toFloat()
}, },
response1 = response1Display, response1 = response1Display,
response2 = response2Display response2 = response2Display
@ -184,13 +201,13 @@ class BetStatusBottomSheetBetDisplayer(
} }
} }
} }
if (betDetail.bet.betStatus !is BetStatus.Finished && betDetail.userParticipation == null) { if (betDetail.bet.betStatus != BetStatus.FINISHED && betDetail.userParticipation == null) {
RainbowButton( RainbowButton(
modifier = Modifier modifier = Modifier
.align(Alignment.BottomCenter) .align(Alignment.BottomCenter)
.padding(horizontal = 7.dp), .padding(horizontal = 7.dp),
text = stringResource(id = R.string.Participate), text = stringResource(id = R.string.Participate),
enabled = betDetail.bet.betStatus == BetStatus.Waiting, enabled = betDetail.bet.betStatus == BetStatus.IN_PROGRESS,
onClick = openParticipateSheet onClick = openParticipateSheet
) )
} }

@ -68,8 +68,8 @@ private fun BetCardPreview() {
title = "Title", title = "Title",
date = "Date", date = "Date",
time = "Time", time = "Time",
status = BetStatus.Waiting status = BetStatus.WAITING
){ ) {
Text("Content") Text("Content")
} }
} }

@ -2,17 +2,30 @@ package fr.iut.alldev.allin.ui.main
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Column
import androidx.compose.material3.* import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.* import androidx.compose.foundation.layout.padding
import androidx.compose.material3.DrawerState
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SheetValue
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.rememberDrawerState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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 androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.betConfirmation.BetConfirmationBottomSheet
import fr.iut.alldev.allin.ui.betResult.BetResultBottomSheet
import fr.iut.alldev.allin.ui.betStatus.BetStatusBottomSheet import fr.iut.alldev.allin.ui.betStatus.BetStatusBottomSheet
import fr.iut.alldev.allin.ui.betStatus.vo.BetStatusBottomSheetBetDisplayer import fr.iut.alldev.allin.ui.betStatus.vo.BetStatusBottomSheetBetDisplayer
import fr.iut.alldev.allin.ui.core.AllInLoading import fr.iut.alldev.allin.ui.core.AllInLoading
@ -33,28 +46,6 @@ private val topLevelDestinations = listOf(
TopLevelDestination.CurrentBets TopLevelDestination.CurrentBets
) )
@Composable
private fun rememberBetStatusVisibilities()
: Triple<MutableState<Boolean>, MutableState<Boolean>, (Boolean) -> Unit> {
val statusVisibility = remember {
mutableStateOf(false)
}
val sheetBackVisibility = remember {
mutableStateOf(false)
}
val setStatusVisibility = { it: Boolean ->
statusVisibility.value = it
if (it) sheetBackVisibility.value = true
}
return Triple(
statusVisibility,
sheetBackVisibility,
setStatusVisibility,
)
}
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun MainScreen( fun MainScreen(
@ -66,15 +57,19 @@ fun MainScreen(
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
var loading by remember { mainViewModel.loading } val (loading, setLoading) = remember { mainViewModel.loading }
val currentUser = remember { mainViewModel.currentUserState } val currentUser = remember { mainViewModel.currentUserState }
val selectedBet by remember { mainViewModel.selectedBet } val selectedBet by remember { mainViewModel.selectedBet }
val wonBet by remember { mainViewModel.wonBet } val statusVisibility = remember { mutableStateOf(false) }
val toConfirm by remember { mainViewModel.toConfirmBet } val sheetBackVisibility = remember { mutableStateOf(false) }
val (statusVisibility, sheetBackVisibility, setStatusVisibility) = rememberBetStatusVisibilities() val setStatusVisibility = { it: Boolean ->
statusVisibility.value = it
if (it) sheetBackVisibility.value = true
}
val (participateSheetVisibility, setParticipateSheetVisibility) = remember { mutableStateOf(false) } val (participateSheetVisibility, setParticipateSheetVisibility) = remember { mutableStateOf(false) }
val (displayResult, setDisplayResult) = remember { mutableStateOf(true) } val events = remember { mainViewModel.events }
val eventBottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val betStatusDisplayer = remember { val betStatusDisplayer = remember {
BetStatusBottomSheetBetDisplayer( BetStatusBottomSheetBetDisplayer(
@ -113,10 +108,6 @@ fun MainScreen(
} }
) )
val resultBottomSheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true
)
AllInDrawer( AllInDrawer(
drawerState = drawerState, drawerState = drawerState,
destinations = topLevelDestinations, destinations = topLevelDestinations,
@ -126,6 +117,7 @@ fun MainScreen(
nbBets = 35, nbBets = 35,
bestWin = 362, bestWin = 362,
navigateTo = { route -> navigateTo = { route ->
mainViewModel.fetchEvents()
navController.popUpTo(route, startDestination) navController.popUpTo(route, startDestination)
}, },
logout = { logout = {
@ -135,7 +127,7 @@ fun MainScreen(
) { ) {
AllInScaffold( AllInScaffold(
onMenuClicked = { scope.launch { drawerState.open() } }, onMenuClicked = { scope.launch { drawerState.open() } },
coinAmount = currentUser.userCoins.value, coinAmount = currentUser.userCoins.intValue,
drawerState = drawerState, drawerState = drawerState,
snackbarHostState = snackbarHostState snackbarHostState = snackbarHostState
) { ) {
@ -156,34 +148,26 @@ fun MainScreen(
setParticipateSheetVisibility(participate) setParticipateSheetVisibility(participate)
setStatusVisibility(true) setStatusVisibility(true)
}, },
setLoading = { loading = it }, setLoading = setLoading,
putSnackbarContent = { mainViewModel.putSnackbarContent(it) } putSnackbarContent = { mainViewModel.putSnackbarContent(it) },
) backHandlers = {
BackHandler(enabled = drawerState.isOpen) {
scope.launch {
drawerState.close()
} }
} }
} }
wonBet?.let {
BetResultBottomSheet(
state = resultBottomSheetState,
sheetVisibility = displayResult,
onDismiss = { setDisplayResult(false) },
bet = it,
username = currentUser.user.username,
coinAmount = 1630,
stake = 1630,
winnings = 1630,
odds = 3.62f
) )
} }
}
}
toConfirm?.let {
BetConfirmationBottomSheet( events.firstOrNull()?.let {
state = resultBottomSheetState, it.Display(sheetState = eventBottomSheetState) {
sheetVisibility = displayResult, mainViewModel.dismissedEvents += it
betDetail = it, events.removeFirstOrNull()
onDismiss = { setDisplayResult(false) } }
) { /*TODO*/ }
} }
BetStatusBottomSheet( BetStatusBottomSheet(
@ -200,14 +184,6 @@ fun MainScreen(
setParticipateSheetVisibility = setParticipateSheetVisibility setParticipateSheetVisibility = setParticipateSheetVisibility
) )
AllInLoading(visible = loading) AllInLoading(visible = loading)
BackHandler(
enabled = drawerState.isOpen
) {
scope.launch {
drawerState.close()
}
}
} }

@ -2,28 +2,25 @@ package fr.iut.alldev.allin.ui.main
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import fr.iut.alldev.allin.data.model.User import fr.iut.alldev.allin.data.model.User
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.BetFinishedStatus
import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.data.model.bet.NO_VALUE
import fr.iut.alldev.allin.data.model.bet.Participation import fr.iut.alldev.allin.data.model.bet.Participation
import fr.iut.alldev.allin.data.model.bet.YES_VALUE
import fr.iut.alldev.allin.data.model.bet.YesNoBet
import fr.iut.alldev.allin.data.model.bet.vo.BetAnswerDetail
import fr.iut.alldev.allin.data.model.bet.vo.BetDetail import fr.iut.alldev.allin.data.model.bet.vo.BetDetail
import fr.iut.alldev.allin.data.repository.BetRepository import fr.iut.alldev.allin.data.repository.BetRepository
import fr.iut.alldev.allin.di.AllInCurrentUser import fr.iut.alldev.allin.di.AllInCurrentUser
import fr.iut.alldev.allin.keystore.AllInKeystoreManager import fr.iut.alldev.allin.keystore.AllInKeystoreManager
import fr.iut.alldev.allin.ui.core.snackbar.SnackbarType import fr.iut.alldev.allin.ui.core.snackbar.SnackbarType
import fr.iut.alldev.allin.ui.main.event.AllInEvent
import fr.iut.alldev.allin.ui.main.event.ToConfirmBet
import fr.iut.alldev.allin.ui.main.event.WonBet
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.time.ZonedDateTime
import javax.inject.Inject import javax.inject.Inject
class UserState(val user: User) { class UserState(val user: User) {
@ -41,61 +38,49 @@ class MainViewModel @Inject constructor(
val currentUserState = UserState(currentUser) val currentUserState = UserState(currentUser)
val selectedBet = mutableStateOf<BetDetail?>(null) val selectedBet = mutableStateOf<BetDetail?>(null)
val wonBet = mutableStateOf<Bet?>( val dismissedEvents = mutableStateListOf<AllInEvent>()
null val events = mutableStateListOf<AllInEvent>()
/* YesNoBet(
id = "1",
theme = "Theme",
phrase = "Phrase",
endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(),
isPublic = true,
betStatus = BetStatus.Finished(BetFinishedStatus.WON),
creator = "creator"
)*/
)
val toConfirmBet = mutableStateOf<BetDetail?>(
BetDetail(
bet = YesNoBet(
id = "1",
theme = "Theme",
phrase = "Phrase",
endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(),
isPublic = true,
betStatus = BetStatus.Finished(BetFinishedStatus.WON),
creator = "creator",
),
answers = listOf(
BetAnswerDetail(
response = YES_VALUE,
totalStakes = 300,
totalParticipants = 2,
highestStake = 200,
odds = 1.0f
),
BetAnswerDetail(
response = NO_VALUE,
totalStakes = 150,
totalParticipants = 1,
highestStake = 150,
odds = 2.0f
)
),
participations = emptyList(),
userParticipation = null
)
)
val snackbarContent: MutableState<SnackbarContent?> by lazy { mutableStateOf(null) } val snackbarContent: MutableState<SnackbarContent?> by lazy { mutableStateOf(null) }
fun putSnackbarContent(content: SnackbarContent) { fun putSnackbarContent(content: SnackbarContent) {
snackbarContent.value = content snackbarContent.value = content
} }
init {
fetchEvents()
}
fun fetchEvents() {
viewModelScope.launch {
val token = keystoreManager.getTokenOrEmpty()
events.addAll(
buildList {
addAll(betRepository.getToConfirm(token).map { bet ->
ToConfirmBet(
betDetail = bet,
onConfirm = {
confirmBet(
response = it,
betId = bet.bet.id
)
}
)
})
addAll(betRepository.getWon(token).map { result ->
WonBet(
user = currentUser,
betResult = result
)
})
}.filter { it !in dismissedEvents }
)
}
}
fun openBetDetail(bet: Bet) { fun openBetDetail(bet: Bet) {
viewModelScope.launch { viewModelScope.launch {
selectedBet.value = betRepository.getBet(bet.id, keystoreManager.getToken() ?: "") selectedBet.value = betRepository.getBet(bet.id, keystoreManager.getTokenOrEmpty())
} }
} }
@ -117,13 +102,23 @@ class MainViewModel @Inject constructor(
response = response, response = response,
stake = stake stake = stake
) )
betRepository.participateToBet(participation, keystoreManager.getToken() ?: "") betRepository.participateToBet(participation, keystoreManager.getTokenOrEmpty())
} }
loading.value = false loading.value = false
} }
} }
} }
private fun confirmBet(response: String, betId: String) {
viewModelScope.launch {
betRepository.confirmBet(
token = keystoreManager.getTokenOrEmpty(),
id = betId,
response = response
)
}
}
class SnackbarContent( class SnackbarContent(
val text: String, val text: String,
val type: SnackbarType = SnackbarType.STANDARD val type: SnackbarType = SnackbarType.STANDARD

@ -0,0 +1,12 @@
package fr.iut.alldev.allin.ui.main.event
import androidx.compose.material3.SheetState
import androidx.compose.runtime.Composable
sealed class AllInEvent {
@Composable
abstract fun Display(
sheetState: SheetState,
onDismiss: () -> Unit
)
}

@ -0,0 +1,39 @@
package fr.iut.alldev.allin.ui.main.event
import androidx.compose.material3.SheetState
import androidx.compose.runtime.Composable
import fr.iut.alldev.allin.data.model.bet.vo.BetDetail
import fr.iut.alldev.allin.ui.betConfirmation.BetConfirmationBottomSheet
data class ToConfirmBet(
private val betDetail: BetDetail,
private val onConfirm: (String) -> Unit
) : AllInEvent() {
@Composable
override fun Display(
sheetState: SheetState,
onDismiss: () -> Unit
) {
BetConfirmationBottomSheet(
state = sheetState,
sheetVisibility = true,
betDetail = betDetail,
onDismiss = onDismiss,
onConfirm = onConfirm
)
}
override fun hashCode(): Int {
return betDetail.hashCode()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ToConfirmBet
return betDetail == other.betDetail
}
}

@ -0,0 +1,31 @@
package fr.iut.alldev.allin.ui.main.event
import androidx.compose.material3.SheetState
import androidx.compose.runtime.Composable
import fr.iut.alldev.allin.data.model.User
import fr.iut.alldev.allin.data.model.bet.BetResultDetail
import fr.iut.alldev.allin.ui.betResult.BetResultBottomSheet
data class WonBet(
private val user: User,
private val betResult: BetResultDetail,
) : AllInEvent() {
@Composable
override fun Display(
sheetState: SheetState,
onDismiss: () -> Unit
) {
BetResultBottomSheet(
state = sheetState,
sheetVisibility = true,
onDismiss = onDismiss,
bet = betResult.bet,
username = user.username,
coinAmount = betResult.amount,
stake = betResult.participation.stake,
winnings = betResult.amount,
odds = 1f
)
}
}

@ -12,19 +12,17 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import fr.iut.alldev.allin.R import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.data.model.bet.Bet import fr.iut.alldev.allin.data.model.bet.Bet
import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.bet.BetScreen import fr.iut.alldev.allin.ui.bet.BetScreen
import fr.iut.alldev.allin.ui.betCreation.BetCreationScreen import fr.iut.alldev.allin.ui.betCreation.BetCreationScreen
import fr.iut.alldev.allin.ui.betHistory.BetCurrentScreen
import fr.iut.alldev.allin.ui.betHistory.BetHistoryScreen import fr.iut.alldev.allin.ui.betHistory.BetHistoryScreen
import fr.iut.alldev.allin.ui.core.snackbar.SnackbarType import fr.iut.alldev.allin.ui.core.snackbar.SnackbarType
import fr.iut.alldev.allin.ui.login.LoginScreen import fr.iut.alldev.allin.ui.login.LoginScreen
@ -41,14 +39,11 @@ object Routes {
const val PUBLIC_BETS = "PUBLIC_BETS" const val PUBLIC_BETS = "PUBLIC_BETS"
const val BET_CREATION = "BET_CREATION" const val BET_CREATION = "BET_CREATION"
const val BET_HISTORY = "BET_HISTORY" const val BET_HISTORY = "BET_HISTORY"
const val BET_CURRENT = "BET_CURRENT"
const val FRIENDS = "FRIENDS" const val FRIENDS = "FRIENDS"
} }
object NavArguments {
const val ARG_BET_HISTORY_IS_CURRENT = "ARG_BET_HISTORY_IS_CURRENT"
}
internal fun NavHostController.popUpTo(route: String, baseRoute: String) { internal fun NavHostController.popUpTo(route: String, baseRoute: String) {
this.navigate(route) { this.navigate(route) {
launchSingleTop = true launchSingleTop = true
@ -99,7 +94,8 @@ internal fun AllInDrawerNavHost(
selectBet: (Bet, Boolean) -> Unit, selectBet: (Bet, Boolean) -> Unit,
startDestination: String = Routes.PUBLIC_BETS, startDestination: String = Routes.PUBLIC_BETS,
setLoading: (Boolean) -> Unit, setLoading: (Boolean) -> Unit,
putSnackbarContent: (MainViewModel.SnackbarContent) -> Unit putSnackbarContent: (MainViewModel.SnackbarContent) -> Unit,
backHandlers: @Composable () -> Unit
) { ) {
NavHost( NavHost(
navController = navController, navController = navController,
@ -108,12 +104,15 @@ internal fun AllInDrawerNavHost(
enterTransition = { EnterTransition.None }, enterTransition = { EnterTransition.None },
exitTransition = { ExitTransition.None } exitTransition = { ExitTransition.None }
) { ) {
composable(route = Routes.PUBLIC_BETS) { composable(route = Routes.PUBLIC_BETS) {
backHandlers()
BetScreen( BetScreen(
selectBet = selectBet selectBet = selectBet
) )
} }
composable(route = Routes.BET_CREATION) { composable(route = Routes.BET_CREATION) {
backHandlers()
val creationSuccessMessage = stringResource(id = R.string.bet_creation_success_message) val creationSuccessMessage = stringResource(id = R.string.bet_creation_success_message)
BetCreationScreen( BetCreationScreen(
setLoading = setLoading, setLoading = setLoading,
@ -130,20 +129,17 @@ internal fun AllInDrawerNavHost(
} }
composable( composable(
route = "${Routes.BET_HISTORY}/{${NavArguments.ARG_BET_HISTORY_IS_CURRENT}}", route = Routes.BET_HISTORY
arguments = listOf( ) {
navArgument(NavArguments.ARG_BET_HISTORY_IS_CURRENT) { backHandlers()
type = NavType.BoolType BetHistoryScreen()
} }
)
composable(
route = Routes.BET_CURRENT
) { ) {
val isCurrent = backHandlers()
it.arguments?.getBoolean(NavArguments.ARG_BET_HISTORY_IS_CURRENT) ?: false BetCurrentScreen()
BetHistoryScreen(
isCurrent = isCurrent,
viewModel = hiltViewModel(it, isCurrent.toString())
)
} }
} }
} }

@ -23,7 +23,7 @@ sealed class TopLevelDestination(
) )
data object BetHistory : TopLevelDestination( data object BetHistory : TopLevelDestination(
route = "${Routes.BET_HISTORY}/false", route = Routes.BET_HISTORY,
title = R.string.bet_history, title = R.string.bet_history,
subtitle = R.string.bet_history_subtitle, subtitle = R.string.bet_history_subtitle,
emoji = R.drawable.eyes emoji = R.drawable.eyes
@ -37,7 +37,7 @@ sealed class TopLevelDestination(
) )
data object CurrentBets : TopLevelDestination( data object CurrentBets : TopLevelDestination(
route = "${Routes.BET_HISTORY}/true", route = Routes.BET_CURRENT,
title = R.string.current_bets, title = R.string.current_bets,
subtitle = R.string.current_bets_subtitle, subtitle = R.string.current_bets_subtitle,
emoji = R.drawable.money_with_wings emoji = R.drawable.money_with_wings

@ -2,7 +2,6 @@ package fr.iut.alldev.allin.ui.preview
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
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.BetFinishedStatus
import fr.iut.alldev.allin.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.data.model.bet.CustomBet import fr.iut.alldev.allin.data.model.bet.CustomBet
import fr.iut.alldev.allin.data.model.bet.MatchBet import fr.iut.alldev.allin.data.model.bet.MatchBet
@ -18,7 +17,7 @@ class BetPreviewProvider : PreviewParameterProvider<Bet> {
endRegisterDate = ZonedDateTime.now(), endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(),
isPublic = true, isPublic = true,
betStatus = BetStatus.Finished(BetFinishedStatus.WON), betStatus = BetStatus.FINISHED,
creator = "creator" creator = "creator"
), ),
MatchBet( MatchBet(
@ -28,7 +27,7 @@ class BetPreviewProvider : PreviewParameterProvider<Bet> {
endRegisterDate = ZonedDateTime.now(), endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(),
isPublic = true, isPublic = true,
betStatus = BetStatus.Finished(BetFinishedStatus.WON), betStatus = BetStatus.FINISHED,
creator = "creator", creator = "creator",
nameTeam1 = "The Monarchs", nameTeam1 = "The Monarchs",
nameTeam2 = "Climate Change" nameTeam2 = "Climate Change"
@ -40,7 +39,7 @@ class BetPreviewProvider : PreviewParameterProvider<Bet> {
endRegisterDate = ZonedDateTime.now(), endRegisterDate = ZonedDateTime.now(),
endBetDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(),
isPublic = true, isPublic = true,
betStatus = BetStatus.Finished(BetFinishedStatus.WON), betStatus = BetStatus.FINISHED,
creator = "creator", creator = "creator",
possibleAnswers = listOf( possibleAnswers = listOf(
"Answer 1", "Answer 1",

@ -4,5 +4,5 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import fr.iut.alldev.allin.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.BetStatus
class BetStatusPreviewProvider : PreviewParameterProvider<BetStatus> { class BetStatusPreviewProvider : PreviewParameterProvider<BetStatus> {
override val values = BetStatus.entries override val values = BetStatus.entries.asSequence()
} }

@ -10,7 +10,7 @@ import java.time.ZonedDateTime
class BetWithStatusPreviewProvider : PreviewParameterProvider<Bet> { class BetWithStatusPreviewProvider : PreviewParameterProvider<Bet> {
override val values = BetStatus.entries.flatMap { status -> override val values = BetStatus.entries.asSequence().flatMap { status ->
sequenceOf( sequenceOf(
YesNoBet( YesNoBet(
id = "1", id = "1",

@ -118,6 +118,8 @@
<string name="bet_status_finished">Terminé !</string> <string name="bet_status_finished">Terminé !</string>
<string name="bet_status_in_progress">En cours…</string> <string name="bet_status_in_progress">En cours…</string>
<string name="bet_status_waiting">En attente…</string> <string name="bet_status_waiting">En attente…</string>
<string name="bet_status_closing">Fermeture…</string>
<string name="bet_status_cancelled">Annulé</string>
<string name="place_your_bets">Faites vos paris</string> <string name="place_your_bets">Faites vos paris</string>
<string name="bet_status_participants_list">Liste des participants</string> <string name="bet_status_participants_list">Liste des participants</string>

@ -118,6 +118,8 @@
<string name="bet_status_finished">Finished !</string> <string name="bet_status_finished">Finished !</string>
<string name="bet_status_in_progress">In progress…</string> <string name="bet_status_in_progress">In progress…</string>
<string name="bet_status_waiting">Waiting…</string> <string name="bet_status_waiting">Waiting…</string>
<string name="bet_status_closing">Closing…</string>
<string name="bet_status_cancelled">Cancelled</string>
<string name="place_your_bets">Place your bets</string> <string name="place_your_bets">Place your bets</string>
<string name="bet_status_participants_list">Participants</string> <string name="bet_status_participants_list">Participants</string>

@ -6,6 +6,7 @@ import fr.iut.alldev.allin.data.api.model.RequestParticipation
import fr.iut.alldev.allin.data.api.model.RequestUser import fr.iut.alldev.allin.data.api.model.RequestUser
import fr.iut.alldev.allin.data.api.model.ResponseBet import fr.iut.alldev.allin.data.api.model.ResponseBet
import fr.iut.alldev.allin.data.api.model.ResponseBetDetail import fr.iut.alldev.allin.data.api.model.ResponseBetDetail
import fr.iut.alldev.allin.data.api.model.ResponseBetResultDetail
import fr.iut.alldev.allin.data.api.model.ResponseUser import fr.iut.alldev.allin.data.api.model.ResponseUser
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
@ -31,11 +32,42 @@ interface AllInApi {
suspend fun createBet(@Header("Authorization") token: String, @Body body: RequestBet) suspend fun createBet(@Header("Authorization") token: String, @Body body: RequestBet)
@GET("bets/gets") @GET("bets/gets")
suspend fun getAllBets(): List<ResponseBet> suspend fun getAllBets(@Header("Authorization") token: String): List<ResponseBet>
@GET("bets/toConfirm")
suspend fun getToConfirm(@Header("Authorization") token: String): List<ResponseBetDetail>
@POST("bets/confirm/{id}")
suspend fun confirmBet(
@Header("Authorization") token: String,
@Path("id") id: String,
@Body value: String
)
@GET("betdetail/get/{id}") @GET("betdetail/get/{id}")
suspend fun getBet(@Header("Authorization") token: String, @Path("id") id: String): ResponseBetDetail suspend fun getBet(
@Header("Authorization") token: String,
@Path("id") id: String
): ResponseBetDetail
@GET("bets/getCurrent")
suspend fun getBetCurrent(
@Header("Authorization") token: String
): List<ResponseBetDetail>
@GET("bets/history")
suspend fun getBetHistory(
@Header("Authorization") token: String
): List<ResponseBetResultDetail>
@GET("bets/getWon")
suspend fun getWon(
@Header("Authorization") token: String
): List<ResponseBetResultDetail>
@POST("participations/add") @POST("participations/add")
suspend fun participateToBet(@Header("Authorization") token: String, @Body body: RequestParticipation) suspend fun participateToBet(
@Header("Authorization") token: String,
@Body body: RequestParticipation
)
} }

@ -8,19 +8,26 @@ import fr.iut.alldev.allin.data.api.model.RequestUser
import fr.iut.alldev.allin.data.api.model.ResponseBet import fr.iut.alldev.allin.data.api.model.ResponseBet
import fr.iut.alldev.allin.data.api.model.ResponseBetAnswerDetail import fr.iut.alldev.allin.data.api.model.ResponseBetAnswerDetail
import fr.iut.alldev.allin.data.api.model.ResponseBetDetail import fr.iut.alldev.allin.data.api.model.ResponseBetDetail
import fr.iut.alldev.allin.data.api.model.ResponseBetResultDetail
import fr.iut.alldev.allin.data.api.model.ResponseParticipation import fr.iut.alldev.allin.data.api.model.ResponseParticipation
import fr.iut.alldev.allin.data.api.model.ResponseUser import fr.iut.alldev.allin.data.api.model.ResponseUser
import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.data.model.bet.BetType
import fr.iut.alldev.allin.data.model.bet.NO_VALUE import fr.iut.alldev.allin.data.model.bet.NO_VALUE
import fr.iut.alldev.allin.data.model.bet.YES_VALUE import fr.iut.alldev.allin.data.model.bet.YES_VALUE
import fr.iut.alldev.allin.data.model.bet.vo.BetResult
import java.time.ZonedDateTime import java.time.ZonedDateTime
import java.util.UUID import java.util.UUID
class MockAllInApi : AllInApi { class MockAllInApi : AllInApi {
private fun getUserFromToken(token: String) = private fun getUserFromToken(token: String) =
mockUsers.find { it.first.token == token } mockUsers.find { it.first.token == token.removePrefix("Bearer ") }
private fun getAnswerDetails(bet: ResponseBet, participations: List<ResponseParticipation>): List<ResponseBetAnswerDetail> { private fun getAnswerDetails(
bet: ResponseBet,
participations: List<ResponseParticipation>
): List<ResponseBetAnswerDetail> {
return bet.response.map { response -> return bet.response.map { response ->
val responseParticipations = participations.filter { it.answer == response } val responseParticipations = participations.filter { it.answer == response }
ResponseBetAnswerDetail( ResponseBetAnswerDetail(
@ -65,12 +72,47 @@ class MockAllInApi : AllInApi {
endBet = body.endBet, endBet = body.endBet,
isPrivate = body.isPrivate, isPrivate = body.isPrivate,
response = body.response, response = body.response,
type = BetType.BINARY,
status = BetStatus.WAITING,
createdBy = "" createdBy = ""
) )
) )
} }
override suspend fun getAllBets(): List<ResponseBet> = mockBets.toList() override suspend fun getAllBets(token: String): List<ResponseBet> {
getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.")
return mockBets
}
override suspend fun getToConfirm(token: String): List<ResponseBetDetail> {
val user = getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.")
return mockBets.filter {
it.createdBy == user.first.username && it.status == BetStatus.CLOSING
}.map { bet ->
val betParticipations = mockParticipations.filter { it.betId == bet.id }
val userParticipation = betParticipations.find { it.username == user.first.username }
ResponseBetDetail(
bet = bet,
answers = getAnswerDetails(bet, betParticipations),
participations = betParticipations,
userParticipation = userParticipation
)
}
}
override suspend fun confirmBet(token: String, id: String, value: String) {
getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.")
val bet = mockBets.find { it.id == id } ?: throw AllInAPIException("Unauthorized")
mockResults.add(
BetResult(
betId = id,
result = value
)
)
mockBets[mockBets.indexOf(bet)] = bet.copy(status = BetStatus.FINISHED)
}
override suspend fun getBet(token: String, id: String): ResponseBetDetail { override suspend fun getBet(token: String, id: String): ResponseBetDetail {
val bet = mockBets.find { it.id == id } ?: throw AllInAPIException("Bet not found") val bet = mockBets.find { it.id == id } ?: throw AllInAPIException("Bet not found")
val user = getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") val user = getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.")
@ -85,6 +127,18 @@ class MockAllInApi : AllInApi {
) )
} }
override suspend fun getBetCurrent(token: String): List<ResponseBetDetail> {
return emptyList()
}
override suspend fun getBetHistory(token: String): List<ResponseBetResultDetail> {
return emptyList()
}
override suspend fun getWon(token: String): List<ResponseBetResultDetail> {
return emptyList()
}
override suspend fun participateToBet(token: String, body: RequestParticipation) { override suspend fun participateToBet(token: String, body: RequestParticipation) {
getUserFromToken(token)?.let { getUserFromToken(token)?.let {
mockParticipations.add( mockParticipations.add(
@ -214,7 +268,9 @@ private val mockBets = mutableListOf(
endBet = ZonedDateTime.now().plusDays(4), endBet = ZonedDateTime.now().plusDays(4),
isPrivate = false, isPrivate = false,
response = listOf(YES_VALUE, NO_VALUE), response = listOf(YES_VALUE, NO_VALUE),
createdBy = "Armure" createdBy = "Armure",
type = BetType.BINARY,
status = BetStatus.WAITING,
), ),
ResponseBet( ResponseBet(
id = "UUID2", id = "UUID2",
@ -224,16 +280,22 @@ private val mockBets = mutableListOf(
endBet = ZonedDateTime.now().plusDays(4), endBet = ZonedDateTime.now().plusDays(4),
isPrivate = false, isPrivate = false,
response = listOf("Answer 1", "Answer 2", "Answer 3", "Answer 4"), response = listOf("Answer 1", "Answer 2", "Answer 3", "Answer 4"),
createdBy = "User 2" createdBy = "User 2",
type = BetType.BINARY,
status = BetStatus.WAITING,
), ),
ResponseBet( ResponseBet(
id = "UUID3", id = "UUID3",
theme = "Sport", theme = "Sport",
sentenceBet = "Nouveau record du monde ?", sentenceBet = "Nouveau record du monde ?",
endRegistration = ZonedDateTime.now().plusDays(3), endRegistration = ZonedDateTime.now().minusDays(3),
endBet = ZonedDateTime.now().plusDays(4), endBet = ZonedDateTime.now().minusDays(2),
isPrivate = false, isPrivate = false,
response = listOf(YES_VALUE, NO_VALUE), response = listOf(YES_VALUE, NO_VALUE),
createdBy = "Armure" createdBy = "User 1",
type = BetType.BINARY,
status = BetStatus.CLOSING,
) )
) )
private val mockResults by lazy { mutableListOf<BetResult>() }

@ -2,7 +2,10 @@ package fr.iut.alldev.allin.data.api.model
import androidx.annotation.Keep import androidx.annotation.Keep
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.BetResult
import fr.iut.alldev.allin.data.model.bet.BetResultDetail
import fr.iut.alldev.allin.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.data.model.bet.BetType
import fr.iut.alldev.allin.data.model.bet.CustomBet import fr.iut.alldev.allin.data.model.bet.CustomBet
import fr.iut.alldev.allin.data.model.bet.NO_VALUE import fr.iut.alldev.allin.data.model.bet.NO_VALUE
import fr.iut.alldev.allin.data.model.bet.YES_VALUE import fr.iut.alldev.allin.data.model.bet.YES_VALUE
@ -18,6 +21,8 @@ import java.time.ZonedDateTime
data class ResponseBet( data class ResponseBet(
val id: String?, val id: String?,
val theme: String, val theme: String,
val type: BetType,
val status: BetStatus,
val sentenceBet: String, val sentenceBet: String,
@Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime, @Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime,
@Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime, @Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime,
@ -34,7 +39,7 @@ data class ResponseBet(
endRegisterDate = endRegistration, endRegisterDate = endRegistration,
endBetDate = endBet, endBetDate = endBet,
isPublic = !isPrivate, isPublic = !isPrivate,
betStatus = BetStatus.Waiting, betStatus = status,
creator = createdBy creator = createdBy
) )
} else { } else {
@ -45,7 +50,7 @@ data class ResponseBet(
endRegisterDate = endRegistration, endRegisterDate = endRegistration,
endBetDate = endBet, endBetDate = endBet,
isPublic = !isPrivate, isPublic = !isPrivate,
betStatus = BetStatus.Waiting, betStatus = status,
creator = createdBy, creator = createdBy,
possibleAnswers = response possibleAnswers = response
) )
@ -58,6 +63,7 @@ data class ResponseBet(
data class RequestBet( data class RequestBet(
val id: String = "", val id: String = "",
val theme: String, val theme: String,
val type: BetType,
val sentenceBet: String, val sentenceBet: String,
@Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime, @Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime,
@Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime, @Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime,
@ -101,3 +107,33 @@ data class ResponseBetDetail(
) )
} }
@Serializable
data class ResponseBetResult(
val betId: String,
val result: String
) {
fun toBetResult() =
BetResult(
betId = betId,
result = result
)
}
@Serializable
data class ResponseBetResultDetail(
val betResult: ResponseBetResult,
val bet: ResponseBet,
val participation: ResponseParticipation,
val amount: Int,
val won: Boolean
) {
fun toBetResultDetail() =
BetResultDetail(
betResult = betResult.toBetResult(),
bet = bet.toBet(),
participation = participation.toParticipation(),
amount = amount,
won = won
)
}

@ -25,7 +25,7 @@ data class ResponseUser(
id = id, id = id,
username = username, username = username,
email = email, email = email,
coins = nbCoins.toInt() coins = nbCoins
) )
} }

@ -13,16 +13,18 @@ sealed class Bet(
open val isPublic: Boolean, open val isPublic: Boolean,
open val betStatus: BetStatus, open val betStatus: BetStatus,
) { ) {
abstract fun getBetType(): BetType
abstract fun getResponses(): List<String> abstract fun getResponses(): List<String>
fun toRequestBet(): RequestBet { fun toRequestBet(): RequestBet {
return RequestBet( return RequestBet(
id = "", id = id,
theme = theme, theme = theme,
sentenceBet = phrase, sentenceBet = phrase,
endRegistration = endRegisterDate, endRegistration = endRegisterDate,
endBet = endBetDate, endBet = endBetDate,
isPrivate = !isPublic, isPrivate = !isPublic,
response = getResponses() response = getResponses(),
type = getBetType()
) )
} }
} }

@ -19,7 +19,7 @@ class BetFactory {
): Bet = ): Bet =
when (betType) { when (betType) {
BetType.YES_NO -> { BetType.BINARY -> {
YesNoBet( YesNoBet(
id = id, id = id,
theme = theme, theme = theme,
@ -28,7 +28,7 @@ class BetFactory {
endRegisterDate = endRegisterDate, endRegisterDate = endRegisterDate,
endBetDate = endBetDate, endBetDate = endBetDate,
isPublic = isPublic, isPublic = isPublic,
betStatus = BetStatus.Waiting betStatus = BetStatus.WAITING
) )
} }
@ -41,7 +41,7 @@ class BetFactory {
endRegisterDate = endRegisterDate, endRegisterDate = endRegisterDate,
endBetDate = endBetDate, endBetDate = endBetDate,
isPublic = isPublic, isPublic = isPublic,
betStatus = BetStatus.Waiting, betStatus = BetStatus.WAITING,
nameTeam1 = nameTeam1, nameTeam1 = nameTeam1,
nameTeam2 = nameTeam2 nameTeam2 = nameTeam2
) )
@ -57,7 +57,7 @@ class BetFactory {
endRegisterDate = endRegisterDate, endRegisterDate = endRegisterDate,
endBetDate = endBetDate, endBetDate = endBetDate,
isPublic = isPublic, isPublic = isPublic,
betStatus = BetStatus.Waiting, betStatus = BetStatus.WAITING,
possibleAnswers = possibleAnswers possibleAnswers = possibleAnswers
) )
} }

@ -0,0 +1,14 @@
package fr.iut.alldev.allin.data.model.bet
data class BetResult(
val betId: String,
val result: String
)
data class BetResultDetail(
val betResult: BetResult,
val bet: Bet,
val participation: Participation,
val amount: Int,
val won: Boolean
)

@ -1,19 +1,9 @@
package fr.iut.alldev.allin.data.model.bet package fr.iut.alldev.allin.data.model.bet
sealed class BetStatus { enum class BetStatus {
data class Finished(val status: BetFinishedStatus) : BetStatus() IN_PROGRESS,
WAITING,
data object InProgress : BetStatus() CLOSING,
FINISHED,
data object Waiting : BetStatus() CANCELLED
companion object {
val entries = sequenceOf(
InProgress,
Waiting,
Finished(BetFinishedStatus.WON),
Finished(BetFinishedStatus.LOST)
)
}
} }

@ -1,7 +1,7 @@
package fr.iut.alldev.allin.data.model.bet package fr.iut.alldev.allin.data.model.bet
enum class BetType { enum class BetType {
YES_NO, BINARY,
MATCH, MATCH,
CUSTOM CUSTOM
} }

@ -22,5 +22,7 @@ data class CustomBet(
isPublic, isPublic,
betStatus betStatus
) { ) {
override fun getBetType() = BetType.CUSTOM
override fun getResponses(): List<String> = possibleAnswers override fun getResponses(): List<String> = possibleAnswers
} }

@ -23,6 +23,7 @@ data class MatchBet(
isPublic, isPublic,
betStatus betStatus
) { ) {
override fun getBetType() = BetType.MATCH
override fun getResponses(): List<String> = listOf(nameTeam1, nameTeam2) override fun getResponses(): List<String> = listOf(nameTeam1, nameTeam2)
} }

@ -24,5 +24,6 @@ data class YesNoBet(
isPublic, isPublic,
betStatus betStatus
) { ) {
override fun getBetType() = BetType.BINARY
override fun getResponses(): List<String> = listOf(YES_VALUE, NO_VALUE) override fun getResponses(): List<String> = listOf(YES_VALUE, NO_VALUE)
} }

@ -1,10 +1,6 @@
package fr.iut.alldev.allin.data.model.bet.vo package fr.iut.alldev.allin.data.model.bet.vo
import fr.iut.alldev.allin.data.model.bet.Bet
import fr.iut.alldev.allin.data.model.bet.Participation
data class BetResult( data class BetResult(
val bet: Bet, val betId: String,
val participations: List<Participation>, val result: String
val answerDetail: BetAnswerDetail
) )

@ -1,15 +1,18 @@
package fr.iut.alldev.allin.data.repository package fr.iut.alldev.allin.data.repository
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.BetResultDetail
import fr.iut.alldev.allin.data.model.bet.Participation import fr.iut.alldev.allin.data.model.bet.Participation
import fr.iut.alldev.allin.data.model.bet.vo.BetDetail import fr.iut.alldev.allin.data.model.bet.vo.BetDetail
import kotlinx.coroutines.flow.Flow
abstract class BetRepository { abstract class BetRepository {
abstract suspend fun createBet(bet: Bet, token: String) abstract suspend fun createBet(bet: Bet, token: String)
abstract suspend fun getHistory(): Flow<List<Bet>> abstract suspend fun getHistory(token: String): List<BetResultDetail>
abstract suspend fun getCurrentBets(): Flow<List<Bet>> abstract suspend fun getCurrentBets(token: String): List<BetDetail>
abstract suspend fun getBet(id: String, token: String): BetDetail abstract suspend fun getBet(id: String, token: String): BetDetail
abstract suspend fun participateToBet(participation: Participation, token: String) abstract suspend fun participateToBet(participation: Participation, token: String)
abstract suspend fun getAllBets(): List<Bet> abstract suspend fun getAllBets(token: String): List<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>
} }

@ -3,15 +3,10 @@ package fr.iut.alldev.allin.data.repository.impl
import fr.iut.alldev.allin.data.api.AllInApi import fr.iut.alldev.allin.data.api.AllInApi
import fr.iut.alldev.allin.data.api.AllInApi.Companion.formatBearerToken import fr.iut.alldev.allin.data.api.AllInApi.Companion.formatBearerToken
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.BetFinishedStatus import fr.iut.alldev.allin.data.model.bet.BetResultDetail
import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.data.model.bet.Participation import fr.iut.alldev.allin.data.model.bet.Participation
import fr.iut.alldev.allin.data.model.bet.YesNoBet
import fr.iut.alldev.allin.data.model.bet.vo.BetDetail import fr.iut.alldev.allin.data.model.bet.vo.BetDetail
import fr.iut.alldev.allin.data.repository.BetRepository import fr.iut.alldev.allin.data.repository.BetRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import java.time.ZonedDateTime
import javax.inject.Inject import javax.inject.Inject
class BetRepositoryImpl @Inject constructor( class BetRepositoryImpl @Inject constructor(
@ -24,79 +19,16 @@ class BetRepositoryImpl @Inject constructor(
) )
} }
override suspend fun getHistory(): Flow<List<Bet>> { override suspend fun getHistory(token: String): List<BetResultDetail> {
return flowOf( return api.getBetHistory(token.formatBearerToken()).map {
listOf( it.toBetResultDetail()
YesNoBet( }
id = "1",
creator = "Lucas",
theme = "Theme",
phrase = "Bet phrase 1",
endRegisterDate = ZonedDateTime.now().minusDays(4),
endBetDate = ZonedDateTime.now().minusDays(2),
isPublic = false,
betStatus = BetStatus.Finished(BetFinishedStatus.WON)
),
YesNoBet(
id = "2",
creator = "Lucas",
theme = "Theme",
phrase = "Bet phrase 2",
endRegisterDate = ZonedDateTime.now().minusDays(3),
endBetDate = ZonedDateTime.now().minusDays(1),
isPublic = true,
betStatus = BetStatus.Finished(BetFinishedStatus.LOST)
),
YesNoBet(
id = "3",
creator = "Lucas",
theme = "Theme",
phrase = "Bet phrase 3",
endRegisterDate = ZonedDateTime.now().minusDays(15),
endBetDate = ZonedDateTime.now().minusDays(7),
isPublic = false,
betStatus = BetStatus.Finished(BetFinishedStatus.LOST)
)
)
)
} }
override suspend fun getCurrentBets(): Flow<List<Bet>> { override suspend fun getCurrentBets(token: String): List<BetDetail> {
// TODO return api.getToConfirm(token.formatBearerToken()).map {
return flowOf( it.toBetDetail()
listOf( }
YesNoBet(
id = "1",
creator = "Lucas",
theme = "Theme",
phrase = "Bet phrase 1",
endRegisterDate = ZonedDateTime.now().plusDays(5),
endBetDate = ZonedDateTime.now().plusDays(7),
isPublic = false,
betStatus = BetStatus.InProgress
),
YesNoBet(
id = "2",
creator = "Lucas",
theme = "Theme",
phrase = "Bet phrase 2",
endRegisterDate = ZonedDateTime.now().plusDays(1),
endBetDate = ZonedDateTime.now().plusDays(2),
isPublic = true,
betStatus = BetStatus.InProgress
),
YesNoBet(
id = "3",
creator = "Lucas",
theme = "Theme",
phrase = "Bet phrase 3",
endRegisterDate = ZonedDateTime.now().plusDays(3),
endBetDate = ZonedDateTime.now().plusDays(4),
isPublic = false,
betStatus = BetStatus.InProgress
)
)
)
} }
override suspend fun getBet(id: String, token: String): BetDetail { override suspend fun getBet(id: String, token: String): BetDetail {
@ -107,11 +39,24 @@ class BetRepositoryImpl @Inject constructor(
} }
override suspend fun participateToBet(participation: Participation, token: String) { override suspend fun participateToBet(participation: Participation, token: String) {
api.participateToBet(token = token.formatBearerToken(), body = participation.toRequestParticipation()) api.participateToBet(
token = token.formatBearerToken(),
body = participation.toRequestParticipation()
)
} }
override suspend fun getAllBets(): List<Bet> { override suspend fun getAllBets(token: String): List<Bet> =
return api.getAllBets().map { it.toBet() } api.getAllBets(token.formatBearerToken()).map { it.toBet() }
override suspend fun getToConfirm(token: String): List<BetDetail> =
api.getToConfirm(token.formatBearerToken()).map { it.toBetDetail() }
override suspend fun getWon(token: String): List<BetResultDetail> =
api.getWon(token.formatBearerToken()).map { it.toBetResultDetail() }
override suspend fun confirmBet(token: String, id: String, response: String) {
api.confirmBet(token.formatBearerToken(), id, response)
} }
} }
Loading…
Cancel
Save