Mock API and Bet participation bottom sheet
continuous-integration/drone/push Build is passing Details

pull/3/head
Arthur VALIN 1 year ago
parent 3c5545bdb6
commit 2432599726

@ -37,7 +37,7 @@ object Bets {
isPublic = true,
betStatus = BetStatus.InProgress,
creator = "creator",
possibleAnswers = setOf(
possibleAnswers = listOf(
"Answer 1",
"Answer 2",
"Answer 3",

@ -12,17 +12,17 @@ import fr.iut.alldev.allin.vo.bet.BetDisplayer
class BetTestDisplayer : BetDisplayer {
@Composable
override fun DisplayYesNoBet(b: YesNoBet) {
override fun DisplayYesNoBet(bet: YesNoBet) {
Text("This is a YesNo Bet", Modifier.testTag(TestTags.YES_NO_BET.tag))
}
@Composable
override fun DisplayMatchBet(b: MatchBet) {
override fun DisplayMatchBet(bet: MatchBet) {
Text("This is a Match Bet", Modifier.testTag(TestTags.MATCH_BET.tag))
}
@Composable
override fun DisplayCustomBet(b: CustomBet) {
override fun DisplayCustomBet(bet: CustomBet) {
Text("This is a Custom Bet", Modifier.testTag(TestTags.CUSTOM_BET.tag))
}
}

@ -12,7 +12,7 @@ import fr.iut.alldev.allin.data.model.bet.BetType
@StringRes
fun BetType.getTitleId(): Int {
return when (this) {
BetType.YES_NO -> R.string.yes_no
BetType.YES_NO -> R.string.yes_no
BetType.MATCH -> R.string.sport_match
BetType.CUSTOM -> R.string.custom_answers
}

@ -0,0 +1,9 @@
package fr.iut.alldev.allin.ext
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Locale
fun Float.formatToSimple(locale: Locale): String {
return DecimalFormat("0.##", DecimalFormatSymbols.getInstance(locale)).format(this)
}

@ -0,0 +1,21 @@
package fr.iut.alldev.allin.ext
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Locale
fun String.verifyIsFloat(locale: Locale): String? {
val pattern = Regex("^\\d+(\\.|\\,)?\\d*\$")
val decimalSeparator = DecimalFormatSymbols.getInstance(locale).decimalSeparator.toString()
return if (this.matches(pattern)) {
this.replace(Regex("[.,]"), decimalSeparator).format()
} else if (this.isEmpty()) {
this
} else null
}
fun String.toFloatOrNull(locale: Locale): Float? {
val format = DecimalFormat("0.##", DecimalFormatSymbols.getInstance(locale))
return format.parse(this)?.toFloat()
}

@ -118,7 +118,7 @@ class BetCreationViewModel @Inject constructor(
isPublic = isPublic.value,
nameTeam1 = "",
nameTeam2 = "",
possibleAnswers = setOf(),
possibleAnswers = listOf(),
creator = currentUser.username
)
betRepository.createBet(bet, keystoreManager.getToken() ?: "")

@ -21,25 +21,25 @@ fun BetCreationScreenQuestionTab(
nbFriends: Int,
betTheme: String,
betThemeError: String?,
setBetTheme: (String)->Unit,
setBetTheme: (String) -> Unit,
betPhrase: String,
betPhraseError: String?,
setBetPhrase: (String)->Unit,
setBetPhrase: (String) -> Unit,
isPublic: Boolean,
setIsPublic: (Boolean)->Unit,
setIsPublic: (Boolean) -> Unit,
registerDate: ZonedDateTime,
registerDateError: String?,
betDate: ZonedDateTime,
betDateError: String?,
selectedFriends: MutableList<Int>,
setRegisterDateDialog: (Boolean)->Unit,
setEndDateDialog: (Boolean)->Unit,
setRegisterTimeDialog: (Boolean)->Unit,
setEndTimeDialog: (Boolean)->Unit,
setRegisterDateDialog: (Boolean) -> Unit,
setEndDateDialog: (Boolean) -> Unit,
setRegisterTimeDialog: (Boolean) -> Unit,
setEndTimeDialog: (Boolean) -> Unit,
interactionSource: MutableInteractionSource
) {
val bringIntoViewRequester = remember { BringIntoViewRequester() }
Column(modifier){
Column(modifier) {
QuestionTabThemePhraseSection(
betTheme = betTheme,
betThemeError = betThemeError,
@ -47,7 +47,6 @@ fun BetCreationScreenQuestionTab(
betPhrase = betPhrase,
betPhraseError = betPhraseError,
setBetPhrase = setBetPhrase,
bringIntoViewRequester = bringIntoViewRequester,
interactionSource = interactionSource
)
Spacer(modifier = Modifier.height(35.dp))

@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
import androidx.compose.runtime.Composable
@ -24,11 +23,10 @@ import fr.iut.alldev.allin.ui.core.AllInTitleInfo
internal fun QuestionTabThemePhraseSection(
betTheme: String,
betThemeError: String?,
setBetTheme: (String)->Unit,
setBetTheme: (String) -> Unit,
betPhrase: String,
betPhraseError: String?,
setBetPhrase: (String)->Unit,
bringIntoViewRequester: BringIntoViewRequester,
setBetPhrase: (String) -> Unit,
interactionSource: MutableInteractionSource
) {
AllInTitleInfo(
@ -41,13 +39,12 @@ internal fun QuestionTabThemePhraseSection(
AllInTextField(
placeholder = stringResource(id = R.string.Theme_placeholder),
value = betTheme,
onValueChange = setBetTheme,
bringIntoViewRequester = bringIntoViewRequester,
borderColor = AllInTheme.colors.white,
modifier = Modifier.fillMaxWidth(),
maxChar = 20,
placeholderFontSize = 13.sp,
onValueChange = setBetTheme,
errorText = betThemeError,
modifier = Modifier.fillMaxWidth()
borderColor = AllInTheme.colors.white
)
Spacer(modifier = Modifier.height(10.dp))
AllInTitleInfo(
@ -60,15 +57,14 @@ internal fun QuestionTabThemePhraseSection(
AllInTextField(
placeholder = stringResource(id = R.string.Bet_Phrase_placeholder),
value = betPhrase,
borderColor = AllInTheme.colors.white,
onValueChange = setBetPhrase,
bringIntoViewRequester = bringIntoViewRequester,
multiLine = true,
modifier = Modifier
.fillMaxWidth()
.height(100.dp),
maxChar = 100,
placeholderFontSize = 13.sp,
multiLine = true,
onValueChange = setBetPhrase,
errorText = betPhraseError,
modifier = Modifier
.fillMaxWidth()
.height(100.dp)
borderColor = AllInTheme.colors.white
)
}

@ -7,7 +7,10 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import fr.iut.alldev.allin.data.model.bet.Bet
import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.ui.betStatus.components.BetStatusBottomSheetBack
import fr.iut.alldev.allin.ui.betStatus.components.BetStatusParticipationBottomSheet
import fr.iut.alldev.allin.ui.betStatus.components.getParticipationAnswers
import fr.iut.alldev.allin.ui.core.AllInBottomSheet
@ -21,7 +24,12 @@ fun BetStatusBottomSheet(
sheetVisibility: Boolean,
sheetBackVisibility: Boolean,
bet: Bet?,
onDismiss: ()->Unit,
paddingValues: PaddingValues,
userCoinAmount: MutableIntState,
onParticipate: (Int) -> Unit,
onDismiss: () -> Unit,
participateSheetVisibility: Boolean,
setParticipateSheetVisibility: (Boolean) -> Unit,
displayBet: @Composable (Bet) -> Unit
) {
AnimatedVisibility(
@ -45,13 +53,41 @@ fun BetStatusBottomSheet(
onDismiss = onDismiss,
state = state,
scrimColor = Color.Transparent
){
) {
var selectedAnswer by remember { mutableStateOf(0) }
var stake by remember { mutableStateOf<Int?>(null) }
Column(
Modifier.fillMaxHeight(SHEET_HEIGHT)
) {
bet?.let {
val elements = bet.getParticipationAnswers()
displayBet(it)
BetStatusParticipationBottomSheet(
sheetVisibility = participateSheetVisibility && bet.betStatus == BetStatus.Waiting && state.hasExpandedState,
safeBottomPadding = paddingValues.calculateBottomPadding(),
betPhrase = bet.phrase,
coinAmount = userCoinAmount.intValue,
onDismiss = { setParticipateSheetVisibility(false) },
state = rememberModalBottomSheetState(skipPartiallyExpanded = true),
elements = elements,
selectedElement = elements.getOrNull(selectedAnswer),
stake = stake,
setStake = { stake = it },
setElement = { idx -> selectedAnswer = idx },
enabled = stake != null &&
(stake ?: 0) <= userCoinAmount.intValue
) {
stake?.let {
onParticipate(it)
}
}
}
}
}
}

@ -0,0 +1,110 @@
package fr.iut.alldev.allin.ui.betStatus.components
import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.sp
import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.data.model.bet.Bet
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.NO_VALUE
import fr.iut.alldev.allin.data.model.bet.YES_VALUE
import fr.iut.alldev.allin.data.model.bet.YesNoBet
import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.preview.BetPreviewProvider
private val participationAnswerFontSize = 25.sp
@Composable
fun Bet.getParticipationAnswers(): List<@Composable RowScope.() -> Unit> =
when (this) {
is CustomBet -> this.possibleAnswers.map {
{
Text(
text = it,
color = AllInTheme.colors.allInBlue,
style = AllInTheme.typography.h1,
fontSize = participationAnswerFontSize
)
}
}
is MatchBet -> listOf(
{
Text(
text = this@getParticipationAnswers.nameTeam1,
color = AllInTheme.colors.allInBlue,
style = AllInTheme.typography.h1,
fontSize = participationAnswerFontSize
)
},
{
Text(
text = this@getParticipationAnswers.nameTeam2,
color = AllInTheme.colors.allInBarPink,
style = AllInTheme.typography.h1,
fontSize = participationAnswerFontSize
)
}
)
is YesNoBet -> listOf(
{
Text(
text = stringResource(id = R.string.Yes).uppercase(),
color = AllInTheme.colors.allInBlue,
style = AllInTheme.typography.h1,
fontSize = participationAnswerFontSize
)
},
{
Text(
text = stringResource(id = R.string.No).uppercase(),
color = AllInTheme.colors.allInBarPink,
style = AllInTheme.typography.h1,
fontSize = participationAnswerFontSize
)
}
)
}
fun Bet.getAnswerFromParticipationIdx(idx: Int) =
when (this) {
is CustomBet -> this.possibleAnswers.getOrElse(idx) { "" }
is MatchBet -> when (idx) {
0 -> this.nameTeam1
1 -> this.nameTeam2
else -> ""
}
is YesNoBet -> when (idx) {
0 -> YES_VALUE
1 -> NO_VALUE
else -> ""
}
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun ParticipationAnswersPreview(
@PreviewParameter(BetPreviewProvider::class) bet: Bet,
) {
AllInTheme {
Column {
bet.getParticipationAnswers().forEach {
Row(Modifier.fillMaxWidth()) { it() }
}
}
}
}

@ -1,13 +1,17 @@
package fr.iut.alldev.allin.ui.betStatus.components
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@ -16,6 +20,8 @@ import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.core.AllInBottomSheet
import fr.iut.alldev.allin.ui.core.AllInButton
import fr.iut.alldev.allin.ui.core.AllInCoinCount
import fr.iut.alldev.allin.ui.core.AllInIntTextField
import fr.iut.alldev.allin.ui.core.AllInSelectionBox
import fr.iut.alldev.allin.ui.core.topbar.AllInTopBarCoinCounter
import kotlinx.coroutines.launch
@ -28,8 +34,13 @@ fun BetStatusParticipationBottomSheet(
coinAmount: Int,
onDismiss: () -> Unit,
state: SheetState,
onParticipate: () -> Unit,
content: @Composable () -> Unit
enabled: Boolean,
stake: Int?,
setStake: (Int?) -> Unit,
elements: List<@Composable RowScope.() -> Unit>,
selectedElement: (@Composable RowScope.() -> Unit)?,
setElement: (Int) -> Unit,
onParticipate: () -> Unit
) {
val scope = rememberCoroutineScope()
AllInBottomSheet(
@ -37,6 +48,96 @@ fun BetStatusParticipationBottomSheet(
onDismiss = onDismiss,
state = state,
containerColor = AllInTheme.themeColors.background2
) {
BetStatusParticipationBottomSheetContent(
safeBottomPadding = safeBottomPadding,
betPhrase = betPhrase,
coinAmount = coinAmount,
elements = elements,
selectedElement = selectedElement,
setElement = setElement,
enabled = enabled,
stake = stake,
setStake = setStake
) {
scope.launch {
onParticipate()
state.hide()
onDismiss()
}
}
}
}
@Composable
private fun ColumnScope.BetStatusParticipationBottomSheetContent(
safeBottomPadding: Dp,
betPhrase: String,
coinAmount: Int,
enabled: Boolean,
stake: Int?,
setStake: (Int?) -> Unit,
selectedElement: (@Composable RowScope.() -> Unit)?,
elements: List<@Composable RowScope.() -> Unit>,
setElement: (Int) -> Unit,
onButtonClick: () -> Unit
) {
val (answersBoxIsOpen, setAnswersBoxIsOpen) = remember { mutableStateOf(false) }
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(id = R.string.place_your_bets),
style = AllInTheme.typography.h2,
color = AllInTheme.themeColors.onMainSurface,
fontSize = 20.sp,
modifier = Modifier.padding(start = 18.dp)
)
AllInTopBarCoinCounter(
amount = coinAmount,
backgroundColor = AllInTheme.colors.allInBlue,
textColor = AllInTheme.colors.white,
iconColor = AllInTheme.colors.white,
)
}
Column(
modifier = Modifier.padding(horizontal = 18.dp)
) {
Text(
text = betPhrase,
style = AllInTheme.typography.p2,
color = AllInTheme.themeColors.onMainSurface,
modifier = Modifier.padding(vertical = 30.dp)
)
AllInSelectionBox(
isOpen = answersBoxIsOpen,
setIsOpen = setAnswersBoxIsOpen,
selected = selectedElement,
setSelected = { setElement(elements.indexOf(it)) },
elements = elements,
borderWidth = 1.dp
)
Spacer(modifier = Modifier.height(8.dp))
AllInIntTextField(
value = stake,
setValue = setStake,
placeholder = stringResource(id = R.string.bet_result_stake),
trailingIcon = AllInTheme.icons.allCoins(),
modifier = Modifier.fillMaxWidth(),
maxChar = null
)
}
Spacer(modifier = Modifier.height(100.dp))
HorizontalDivider(color = AllInTheme.themeColors.border)
Column(
modifier = Modifier
.background(AllInTheme.themeColors.background)
.padding(horizontal = 7.dp)
.padding(bottom = safeBottomPadding, top = 7.dp),
verticalArrangement = Arrangement.spacedBy(7.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
@ -44,65 +145,44 @@ fun BetStatusParticipationBottomSheet(
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(id = R.string.place_your_bets),
style = AllInTheme.typography.h2,
color = AllInTheme.themeColors.onMainSurface,
fontSize = 20.sp,
modifier = Modifier.padding(start = 18.dp)
text = stringResource(id = R.string.Possible_winnings),
style = AllInTheme.typography.p1,
color = AllInTheme.themeColors.onBackground
)
AllInTopBarCoinCounter(
amount = coinAmount,
backgroundColor = AllInTheme.colors.allInBlue,
textColor = AllInTheme.colors.white,
iconColor = AllInTheme.colors.white,
AllInCoinCount(
amount = 121,
color = AllInTheme.themeColors.onBackground
)
}
Spacer(modifier = Modifier.height(30.dp))
Text(
text = betPhrase,
style = AllInTheme.typography.p2,
color = AllInTheme.themeColors.onMainSurface,
modifier = Modifier.padding(horizontal = 18.dp)
AllInButton(
enabled = enabled,
color = AllInTheme.colors.allInPurple,
text = stringResource(id = R.string.Participate),
textColor = AllInTheme.colors.white,
radius = 5.dp,
onClick = onButtonClick
)
Spacer(modifier = Modifier.height(100.dp))
HorizontalDivider(color = AllInTheme.themeColors.border)
Column(
modifier = Modifier
.background(AllInTheme.themeColors.background)
.padding(horizontal = 7.dp)
.padding(bottom = safeBottomPadding, top = 7.dp),
verticalArrangement = Arrangement.spacedBy(7.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(id = R.string.Possible_winnings),
style = AllInTheme.typography.p1,
color = AllInTheme.themeColors.onBackground
)
AllInCoinCount(
amount = 121,
color = AllInTheme.themeColors.onBackground
)
}
Box(modifier = Modifier.fillMaxSize()) {
content()
}
AllInButton(
color = AllInTheme.colors.allInPurple,
text = stringResource(id = R.string.Participate),
textColor = AllInTheme.colors.white,
radius = 5.dp
) {
scope.launch {
onParticipate()
state.hide()
onDismiss()
}
}
}
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun BetStatusParticipationBottomSheetContentPreview() {
AllInTheme {
Column {
BetStatusParticipationBottomSheetContent(
safeBottomPadding = 0.dp,
betPhrase = "Bet phrase",
coinAmount = 3620,
onButtonClick = {},
elements = emptyList(),
setElement = {},
selectedElement = null,
enabled = true,
stake = 123,
setStake = {}
)
}
}
}

@ -10,7 +10,6 @@ import androidx.compose.material.icons.filled.WorkspacePremium
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -29,7 +28,6 @@ import fr.iut.alldev.allin.data.model.bet.YesNoBet
import fr.iut.alldev.allin.ext.getDateEndLabelId
import fr.iut.alldev.allin.ext.getDateStartLabelId
import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.betStatus.components.BetStatusParticipationBottomSheet
import fr.iut.alldev.allin.ui.betStatus.components.BetStatusWinner
import fr.iut.alldev.allin.ui.betStatus.components.YesNoDetailsLine
import fr.iut.alldev.allin.ui.betStatus.components.YesNoStatBar
@ -41,28 +39,22 @@ import fr.iut.alldev.allin.ui.preview.BetWithStatusPreviewProvider
import fr.iut.alldev.allin.vo.bet.BetDisplayer
class BetStatusBottomSheetBetDisplayer(
val userCoinAmount: MutableIntState,
val onParticipate: (Int) -> Unit,
val openParticipateSheet: () -> Unit
) : BetDisplayer {
val participateBottomSheetVisibility = mutableStateOf(false)
val paddingValues = mutableStateOf(PaddingValues())
@OptIn(ExperimentalMaterial3Api::class)
@Composable
override fun DisplayYesNoBet(b: YesNoBet) {
val (participateSheetVisibility, setParticipateSheetVisibility) = remember {
this.participateBottomSheetVisibility
}
override fun DisplayYesNoBet(bet: YesNoBet) {
val safeBottomPadding = paddingValues.value.calculateBottomPadding()
Box(Modifier.padding(bottom = safeBottomPadding)) {
Column {
Column(Modifier.padding(horizontal = 20.dp)) {
BetTitleHeader(
title = b.phrase,
category = b.theme,
creator = b.creator,
title = bet.phrase,
category = bet.theme,
creator = bet.creator,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(20.dp))
@ -70,22 +62,22 @@ class BetStatusBottomSheetBetDisplayer(
horizontalAlignment = Alignment.End
) {
BetDateTimeRow(
label = stringResource(id = b.betStatus.getDateStartLabelId()),
date = b.endRegisterDate.formatToMediumDateNoYear(),
time = b.endRegisterDate.formatToTime(),
label = stringResource(id = bet.betStatus.getDateStartLabelId()),
date = bet.endRegisterDate.formatToMediumDateNoYear(),
time = bet.endRegisterDate.formatToTime(),
modifier = Modifier.width(IntrinsicSize.Max)
)
Spacer(modifier = Modifier.height(15.dp))
BetDateTimeRow(
label = stringResource(id = b.betStatus.getDateEndLabelId()),
date = b.endBetDate.formatToMediumDateNoYear(),
time = b.endBetDate.formatToTime(),
label = stringResource(id = bet.betStatus.getDateEndLabelId()),
date = bet.endBetDate.formatToMediumDateNoYear(),
time = bet.endBetDate.formatToTime(),
modifier = Modifier.width(IntrinsicSize.Max)
)
}
Spacer(modifier = Modifier.height(20.dp))
}
if (b.betStatus is BetStatus.Finished) {
if (bet.betStatus is BetStatus.Finished) {
BetStatusWinner(
answer = stringResource(id = R.string.Yes),
color = AllInTheme.colors.allInBlue,
@ -128,42 +120,26 @@ class BetStatusBottomSheetBetDisplayer(
}
}
}
if (b.betStatus !is BetStatus.Finished) {
if (bet.betStatus !is BetStatus.Finished) {
RainbowButton(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(horizontal = 7.dp),
text = stringResource(id = R.string.Participate),
enabled = b.betStatus == BetStatus.Waiting,
onClick = {
setParticipateSheetVisibility(true)
}
enabled = bet.betStatus == BetStatus.Waiting,
onClick = openParticipateSheet
)
}
}
BetStatusParticipationBottomSheet(
sheetVisibility = participateSheetVisibility && b.betStatus == BetStatus.Waiting,
safeBottomPadding = safeBottomPadding,
betPhrase = b.phrase,
coinAmount = userCoinAmount.intValue,
onDismiss = { setParticipateSheetVisibility(false) },
state = rememberModalBottomSheetState(),
onParticipate = {
onParticipate(100)
}
) {
}
}
@Composable
override fun DisplayMatchBet(b: MatchBet) {
override fun DisplayMatchBet(bet: MatchBet) {
Text("This is a MATCH BET")
}
@Composable
override fun DisplayCustomBet(b: CustomBet) {
override fun DisplayCustomBet(bet: CustomBet) {
Text("This is a CUSTOM BET")
}
}
@ -176,9 +152,6 @@ private fun BetStatusBottomSheetPreview(
) {
AllInTheme {
val coins = remember { mutableIntStateOf(100) }
BetStatusBottomSheetBetDisplayer(
userCoinAmount = coins,
onParticipate = {}
).DisplayBet(bet)
BetStatusBottomSheetBetDisplayer {}.DisplayBet(bet)
}
}

@ -15,10 +15,11 @@ import fr.iut.alldev.allin.theme.AllInTheme
@Composable
fun AllInButton(
modifier: Modifier = Modifier,
enabled: Boolean = true,
color: Color,
text: String,
textColor: Color,
modifier: Modifier = Modifier,
radius: Dp = 15.dp,
onClick: () -> Unit,
) {
@ -26,13 +27,14 @@ fun AllInButton(
onClick = onClick,
modifier = modifier,
radius = radius,
backgroundColor = color
backgroundColor = color,
enabled = enabled
) {
Text(
text = text,
textAlign = TextAlign.Center,
style = AllInTheme.typography.h2,
color = textColor,
color = if(enabled) textColor else AllInTheme.themeColors.disabledBorder,
fontSize = 20.sp,
modifier = Modifier
.padding(vertical = 15.dp)
@ -51,6 +53,21 @@ private fun AllInButtonPreview() {
textColor = Color.White
) {
}
}
}
@Preview
@Composable
private fun AllInButtonDisabledPreview() {
AllInTheme {
AllInButton(
color = AllInTheme.colors.allInLoginPurple,
text = "Connexion",
textColor = Color.White,
enabled = false
) {
}
}
}

@ -6,8 +6,10 @@ import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@ -29,6 +31,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.theme.AllInTheme
@ -36,11 +39,11 @@ import fr.iut.alldev.allin.theme.AllInTheme
class SelectionElement(
val textId: Int,
val imageVector: ImageVector,
val imageVector: ImageVector
)
@Composable
fun AllInSelectionLine(
private fun AllInSelectionLine(
text: String,
iconVector: ImageVector?,
modifier: Modifier = Modifier,
@ -91,13 +94,19 @@ fun AllInSelectionLine(
fun AllInSelectionBox(
modifier: Modifier = Modifier,
isOpen: Boolean,
borderWidth: Dp? = null,
setIsOpen: (Boolean) -> Unit,
selected: SelectionElement?,
setSelected: (SelectionElement) -> Unit,
elements: List<SelectionElement>,
) {
val interactionSource = remember { MutableInteractionSource() }
AllInCard(modifier.fillMaxWidth()) {
AllInCard(
modifier = modifier.fillMaxWidth(),
radius = 10.dp,
borderWidth = borderWidth,
borderColor = AllInTheme.colors.allInPurple.copy(alpha = .42f)
) {
Column(
Modifier.animateContentSize()
) {
@ -154,6 +163,84 @@ private fun AllInSelectionBoxClosedPreview() {
}
}
@Composable
private fun AllInSelectionLine(
element: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
onClick: () -> Unit,
trailingIcon: ImageVector? = null,
interactionSource: MutableInteractionSource
) {
Row(
modifier = modifier
.fillMaxWidth()
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = onClick
)
.padding(horizontal = 12.dp, vertical = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
element()
trailingIcon?.let {
Icon(
imageVector = trailingIcon,
contentDescription = null,
tint = AllInTheme.colors.allInPurple,
modifier = Modifier
.size(30.dp)
)
}
}
}
@Composable
fun AllInSelectionBox(
modifier: Modifier = Modifier,
isOpen: Boolean,
setIsOpen: (Boolean) -> Unit,
borderWidth: Dp? = null,
selected: (@Composable RowScope.() -> Unit)?,
setSelected: (@Composable RowScope.() -> Unit) -> Unit,
elements: List<@Composable RowScope.() -> Unit>,
) {
val interactionSource = remember { MutableInteractionSource() }
AllInCard(
modifier = modifier.fillMaxWidth(),
radius = 10.dp,
borderWidth = borderWidth,
borderColor = AllInTheme.colors.allInPurple.copy(alpha = .42f)
) {
Column(Modifier.animateContentSize()) {
AllInSelectionLine(
element = selected ?: { Box { } },
onClick = { setIsOpen(!isOpen) },
interactionSource = interactionSource,
trailingIcon = with(Icons.Default) {
if (isOpen) ExpandLess else ExpandMore
}
)
AnimatedVisibility(isOpen) {
Column {
HorizontalDivider(color = AllInTheme.themeColors.border)
elements.filter { it != selected }.forEach { element ->
AllInSelectionLine(
element = element,
interactionSource = interactionSource,
onClick = {
setSelected(element)
setIsOpen(false)
}
)
}
}
}
}
}
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable

@ -2,7 +2,6 @@ package fr.iut.alldev.allin.ui.core
import android.content.res.Configuration
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
@ -11,35 +10,37 @@ import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.text.input.*
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.os.ConfigurationCompat
import androidx.core.text.isDigitsOnly
import fr.iut.alldev.allin.ext.formatToSimple
import fr.iut.alldev.allin.ext.toFloatOrNull
import fr.iut.alldev.allin.ext.verifyIsFloat
import fr.iut.alldev.allin.theme.AllInTheme
import kotlinx.coroutines.launch
import racra.compose.smooth_corner_rect_library.AbsoluteSmoothCornerShape
import java.util.Locale
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
@Composable
fun AllInTextField(
placeholder: String,
value: String,
modifier: Modifier = Modifier,
placeholder: String? = null,
value: String,
maxChar: Int? = null,
enabled: Boolean = true,
trailingIcon: ImageVector? = null,
trailingContent: @Composable (() -> Unit)? = null,
trailingIcon: Painter? = null,
trailingContent: @Composable() (() -> Unit)? = null,
placeholderFontSize: TextUnit = 18.sp,
multiLine: Boolean = false,
onValueChange: (String) -> Unit,
errorText: String? = null,
bringIntoViewRequester: BringIntoViewRequester,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardType: KeyboardType = KeyboardType.Text,
imeAction: ImeAction = ImeAction.Default,
@ -48,58 +49,38 @@ fun AllInTextField(
containerColor: Color = AllInTheme.themeColors.background,
textColor: Color = AllInTheme.themeColors.onMainSurface,
placeholderColor: Color = AllInTheme.themeColors.onBackground2,
onValueChange: (String) -> Unit,
) {
val scope = rememberCoroutineScope()
var hasFocus by remember { mutableStateOf(false) }
var textFieldValue by remember {
mutableStateOf(TextFieldValue(text = value, selection = TextRange(value.length)))
}
LaunchedEffect(key1 = value, block = {
textFieldValue = TextFieldValue(
text = value,
selection = textFieldValue.selection
)
})
OutlinedTextField(
value = textFieldValue,
value = value,
isError = errorText != null,
modifier = modifier
.onFocusChanged {
hasFocus = it.hasFocus
if (it.isFocused) {
scope.launch {
bringIntoViewRequester.bringIntoView()
}
}
},
modifier = modifier,
supportingText = errorText?.let {
{ AllInErrorLine(text = it) }
},
visualTransformation = visualTransformation,
singleLine = !multiLine,
onValueChange = {
if (maxChar == null || it.text.length <= maxChar) {
textFieldValue = it
onValueChange(it.text)
if (maxChar == null || it.length <= maxChar) {
onValueChange(it)
}
},
placeholder = {
Text(
text = placeholder,
fontSize = placeholderFontSize,
style = AllInTheme.typography.p1,
color = placeholderColor,
maxLines = if (multiLine) 3 else 1,
overflow = TextOverflow.Ellipsis
)
placeholder = placeholder?.let {
{
Text(
text = placeholder,
fontSize = placeholderFontSize,
style = AllInTheme.typography.p1,
color = placeholderColor,
maxLines = if (multiLine) 3 else 1,
overflow = TextOverflow.Ellipsis
)
}
},
trailingIcon = trailingContent ?: trailingIcon?.let {
@Composable {
Icon(
imageVector = it,
painter = it,
contentDescription = null,
tint = AllInTheme.colors.allInLightGrey300
)
@ -135,22 +116,13 @@ fun AllInPasswordField(
keyboardActions: KeyboardActions = KeyboardActions.Default,
errorText: String? = null,
onValueChange: (String) -> Unit,
bringIntoViewRequester: BringIntoViewRequester,
isHiddenByDefault: Boolean = true,
) {
var hidden by remember {
mutableStateOf(isHiddenByDefault)
}
var hidden by remember { mutableStateOf(isHiddenByDefault) }
AllInTextField(
modifier = modifier,
errorText = errorText,
placeholder = placeholder,
imeAction = imeAction,
keyboardActions = keyboardActions,
visualTransformation = if (hidden) PasswordVisualTransformation() else VisualTransformation.None,
value = value,
onValueChange = onValueChange,
bringIntoViewRequester = bringIntoViewRequester,
modifier = modifier,
trailingContent = {
IconButton(
onClick = { hidden = !hidden }
@ -162,10 +134,73 @@ fun AllInPasswordField(
)
}
},
keyboardType = keyboardType
onValueChange = onValueChange,
errorText = errorText,
visualTransformation = if (hidden) PasswordVisualTransformation() else VisualTransformation.None,
keyboardType = keyboardType,
imeAction = imeAction,
keyboardActions = keyboardActions
)
}
@Composable
fun AllInFloatTextfield(
modifier: Modifier = Modifier,
value: Float?,
setValue: (Float?) -> Unit
) {
val configuration = LocalConfiguration.current
val locale = remember {
ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault()
}
var stringValue by remember(value) { mutableStateOf(value?.formatToSimple(locale) ?: "") }
AllInTextField(
value = stringValue,
modifier = modifier,
maxChar = 5,
keyboardType = KeyboardType.Number
) {
it.verifyIsFloat(locale)?.let {
stringValue = it
if (it.isNotEmpty()) {
if (it.lastOrNull() !in setOf(',', '.')) {
it.toFloatOrNull(locale)?.let {
setValue(it)
}
}
} else setValue(null)
}
}
}
@Composable
fun AllInIntTextField(
modifier: Modifier = Modifier,
placeholder: String? = null,
maxChar: Int? = 3,
value: Int?,
trailingIcon: Painter? = null,
setValue: (Int?) -> Unit
) {
AllInTextField(
value = value?.toString() ?: "",
placeholder = placeholder,
modifier = modifier,
maxChar = maxChar,
trailingIcon = trailingIcon,
keyboardType = KeyboardType.NumberPassword
) {
if (it.isEmpty()) setValue(null)
else if (it.isDigitsOnly()) {
it.toIntOrNull()?.let {
setValue(it)
}
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Preview
@Composable
@ -174,8 +209,7 @@ private fun AllInTextFieldPlaceholderPreview() {
AllInTextField(
placeholder = "Email",
value = "",
onValueChange = { },
bringIntoViewRequester = BringIntoViewRequester()
onValueChange = { }
)
}
}
@ -190,8 +224,7 @@ private fun AllInTextFieldValuePreview() {
AllInTextField(
placeholder = "Email",
value = "JohnDoe@mail.com",
onValueChange = { },
bringIntoViewRequester = BringIntoViewRequester()
onValueChange = { }
)
}
}
@ -204,9 +237,8 @@ private fun AllInTextFieldErrorPreview() {
AllInTextField(
placeholder = "Email",
value = "JohnDoe@mail.com",
errorText = "This is an error.",
onValueChange = { },
bringIntoViewRequester = BringIntoViewRequester()
errorText = "This is an error."
)
}
}
@ -220,13 +252,11 @@ private fun AllInTextFieldPasswordPreview() {
AllInPasswordField(
placeholder = "Password",
value = value,
onValueChange = setValue,
bringIntoViewRequester = BringIntoViewRequester()
onValueChange = setValue
)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Preview
@Composable
private fun AllInTextFieldMultilinePreview() {
@ -234,9 +264,8 @@ private fun AllInTextFieldMultilinePreview() {
AllInTextField(
placeholder = "David sera il absent le Lundi matin en cours ?",
value = "",
onValueChange = { },
multiLine = true,
bringIntoViewRequester = BringIntoViewRequester()
onValueChange = { }
)
}
}

@ -1,6 +1,5 @@
package fr.iut.alldev.allin.ui.login
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@ -11,12 +10,10 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -42,7 +39,6 @@ import fr.iut.alldev.allin.ui.core.AllInLoading
import fr.iut.alldev.allin.ui.core.AllInPasswordField
import fr.iut.alldev.allin.ui.core.AllInTextField
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
@Composable
fun LoginScreen(
navigateToDashboard: () -> Unit,
@ -51,7 +47,6 @@ fun LoginScreen(
) {
val focusManager = LocalFocusManager.current
val bringIntoViewRequester = BringIntoViewRequester()
val loading by remember { loginViewModel.loading }
var hasLoginError by remember { loginViewModel.hasError }
@ -102,22 +97,20 @@ fun LoginScreen(
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
AllInTextField(
modifier = Modifier.fillMaxWidth(),
placeholder = stringResource(id = R.string.username),
value = username,
modifier = Modifier.fillMaxWidth(),
onValueChange = setUsername,
bringIntoViewRequester = bringIntoViewRequester,
imeAction = ImeAction.Next,
keyboardActions = keyboardActions
)
AllInPasswordField(
modifier = Modifier.fillMaxWidth(),
placeholder = stringResource(id = R.string.password),
value = password,
onValueChange = setPassword,
bringIntoViewRequester = bringIntoViewRequester,
modifier = Modifier.fillMaxWidth(),
imeAction = ImeAction.Done,
keyboardActions = keyboardActions
keyboardActions = keyboardActions,
onValueChange = setPassword
)
}
ClickableText(

@ -70,14 +70,15 @@ fun MainScreen(
val (selectedBet, setSelectedBet) = remember { mainViewModel.selectedBet }
val (wonBet, setWonBet) = remember { mainViewModel.wonBet }
val (statusVisibility, sheetBackVisibility, setStatusVisibility) = rememberBetStatusVisibilities()
val (displayResult, setDisplayResult ) = remember{ mutableStateOf(true) }
val (participateSheetVisibility, setParticipateSheetVisibility) = remember {
mutableStateOf(false)
}
val (displayResult, setDisplayResult) = remember { mutableStateOf(true) }
val betStatusDisplayer = remember {
BetStatusBottomSheetBetDisplayer(
userCoinAmount = currentUser.userCoins,
onParticipate = {
mainViewModel.participateToBet(it)
}
openParticipateSheet = { setParticipateSheetVisibility(true) }
)
}
@ -152,7 +153,7 @@ fun MainScreen(
navController = navController,
selectBet = { bet, participate ->
setSelectedBet(bet)
betStatusDisplayer.participateBottomSheetVisibility.value = participate
setParticipateSheetVisibility(participate)
setStatusVisibility(true)
},
setLoading = { loading = it },
@ -180,11 +181,14 @@ fun MainScreen(
state = statusBottomSheetState,
sheetVisibility = statusVisibility.value,
sheetBackVisibility = sheetBackVisibility.value,
onDismiss = {
setStatusVisibility(false)
},
onDismiss = { setStatusVisibility(false) },
bet = selectedBet,
displayBet = { betStatusDisplayer.DisplayBet(it) }
paddingValues = betStatusDisplayer.paddingValues.value,
displayBet = { betStatusDisplayer.DisplayBet(it) },
userCoinAmount = mainViewModel.currentUserState.userCoins,
onParticipate = { mainViewModel.participateToBet(it) },
participateSheetVisibility = participateSheetVisibility,
setParticipateSheetVisibility = setParticipateSheetVisibility
)
AllInLoading(visible = loading)
BackHandler(

@ -62,7 +62,7 @@ class MainViewModel @Inject constructor(
viewModelScope.launch {
withContext(Dispatchers.IO) {
loading.value = true
currentUserState.userCoins.intValue += 50
currentUserState.userCoins.intValue -= stake
Thread.sleep(1000)
loading.value = false
}

@ -9,7 +9,7 @@ import fr.iut.alldev.allin.data.model.bet.MatchBet
import fr.iut.alldev.allin.data.model.bet.YesNoBet
import java.time.ZonedDateTime
class BetPreviewProvider: PreviewParameterProvider<Bet> {
class BetPreviewProvider : PreviewParameterProvider<Bet> {
override val values = sequenceOf(
YesNoBet(
theme = "Theme",
@ -39,7 +39,7 @@ class BetPreviewProvider: PreviewParameterProvider<Bet> {
isPublic = true,
betStatus = BetStatus.Finished(BetFinishedStatus.WON),
creator = "creator",
possibleAnswers = setOf(
possibleAnswers = listOf(
"Answer 1",
"Answer 2",
"Answer 3",

@ -40,7 +40,7 @@ class BetWithStatusPreviewProvider : PreviewParameterProvider<Bet> {
isPublic = true,
betStatus = status,
creator = "creator",
possibleAnswers = setOf(
possibleAnswers = listOf(
"Answer 1",
"Answer 2",
"Answer 3",

@ -2,7 +2,6 @@ package fr.iut.alldev.allin.ui.register
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.Text
@ -49,7 +48,6 @@ fun RegisterScreen(
val (password, setPassword) = remember { registerViewModel.password }
val (passwordValidation, setPasswordValidation) = remember { registerViewModel.passwordValidation }
val bringIntoViewRequester = remember { BringIntoViewRequester() }
val scrollState = rememberScrollState()
val usernameFieldName = stringResource(id = R.string.username)
@ -117,46 +115,42 @@ fun RegisterScreen(
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
AllInTextField(
modifier = Modifier.fillMaxWidth(),
placeholder = usernameFieldName,
value = username,
onValueChange = setUsername,
modifier = Modifier.fillMaxWidth(),
maxChar = 20,
onValueChange = setUsername,
errorText = usernameError.errorResource(),
bringIntoViewRequester = bringIntoViewRequester,
imeAction = ImeAction.Next,
keyboardActions = keyboardActions
)
AllInTextField(
modifier = Modifier.fillMaxWidth(),
placeholder = emailFieldName,
value = email,
modifier = Modifier.fillMaxWidth(),
onValueChange = setEmail,
errorText = emailError.errorResource(),
keyboardType = KeyboardType.Email,
bringIntoViewRequester = bringIntoViewRequester,
imeAction = ImeAction.Next,
keyboardActions = keyboardActions
)
AllInPasswordField(
modifier = Modifier.fillMaxWidth(),
placeholder = passwordFieldName,
value = password,
errorText = passwordError.errorResource(),
onValueChange = setPassword,
bringIntoViewRequester = bringIntoViewRequester,
modifier = Modifier.fillMaxWidth(),
imeAction = ImeAction.Next,
keyboardActions = keyboardActions
keyboardActions = keyboardActions,
errorText = passwordError.errorResource(),
onValueChange = setPassword
)
AllInPasswordField(
modifier = Modifier.fillMaxWidth(),
placeholder = stringResource(id = R.string.confirm_password),
value = passwordValidation,
errorText = passwordValidationError.errorResource(),
onValueChange = setPasswordValidation,
bringIntoViewRequester = bringIntoViewRequester,
modifier = Modifier.fillMaxWidth(),
imeAction = ImeAction.Done,
keyboardActions = keyboardActions
keyboardActions = keyboardActions,
errorText = passwordValidationError.errorResource(),
onValueChange = setPasswordValidation
)
}
}

@ -17,11 +17,11 @@ interface BetDisplayer {
}
@Composable
fun DisplayYesNoBet(b: YesNoBet)
fun DisplayYesNoBet(bet: YesNoBet)
@Composable
fun DisplayMatchBet(b: MatchBet)
fun DisplayMatchBet(bet: MatchBet)
@Composable
fun DisplayCustomBet(b: CustomBet)
fun DisplayCustomBet(bet: CustomBet)
}

@ -0,0 +1,96 @@
package fr.iut.alldev.allin.data.api
import fr.iut.alldev.allin.data.api.interceptors.AllInAPIException
import fr.iut.alldev.allin.data.api.model.CheckUser
import fr.iut.alldev.allin.data.api.model.RequestBet
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.ResponseUser
import fr.iut.alldev.allin.data.model.bet.NO_VALUE
import fr.iut.alldev.allin.data.model.bet.YES_VALUE
import java.time.ZonedDateTime
import java.util.UUID
class MockAllInApi : AllInApi {
override suspend fun login(body: CheckUser): ResponseUser {
return users.find { it.first.username == body.login && it.second == body.password }?.first
?: throw AllInAPIException("Invalid login/password.")
}
override suspend fun login(token: String): ResponseUser {
return users.find { it.first.token == token }?.first
?: throw AllInAPIException("Invalid token")
}
override suspend fun register(body: RequestUser): ResponseUser {
val response = ResponseUser(
id = UUID.randomUUID().toString(),
username = body.username,
email = body.email,
nbCoins = body.nbCoins,
token = "${body.username} ${users.size}"
) to body.password
users.add(response)
return response.first
}
override suspend fun createBet(token: String, body: RequestBet) {
mockBets.add(
ResponseBet(
id = UUID.randomUUID().toString(),
theme = body.theme,
sentenceBet = body.sentenceBet,
endRegistration = body.endRegistration,
endBet = body.endBet,
isPrivate = body.isPrivate,
response = body.response,
createdBy = ""
)
)
}
override suspend fun getAllBets(): List<ResponseBet> = mockBets.toList()
}
private val users = mutableListOf(
ResponseUser(
id = "UUID 1",
username = "User 1",
email = "john@doe.fr",
nbCoins = 250,
token = "token 1"
) to "psswrd"
)
private val mockBets = mutableListOf(
ResponseBet(
id = "UUID1",
theme = "Études",
sentenceBet = "Dave va arriver en retard demain matin ?",
endRegistration = ZonedDateTime.now().plusDays(3),
endBet = ZonedDateTime.now().plusDays(4),
isPrivate = false,
response = listOf(YES_VALUE, NO_VALUE),
createdBy = "Armure"
),
ResponseBet(
id = "UUID2",
theme = "Études",
sentenceBet = "Dave va arriver en retard demain matin ?",
endRegistration = ZonedDateTime.now().plusDays(3),
endBet = ZonedDateTime.now().plusDays(4),
isPrivate = false,
response = listOf("Answer 1", "Answer 2", "Answer 3", "Answer 4"),
createdBy = "User 2"
),
ResponseBet(
id = "UUID3",
theme = "Sport",
sentenceBet = "Nouveau record du monde ?",
endRegistration = ZonedDateTime.now().plusDays(3),
endBet = ZonedDateTime.now().plusDays(4),
isPrivate = false,
response = listOf(YES_VALUE, NO_VALUE),
createdBy = "Armure"
)
)

@ -4,6 +4,8 @@ import androidx.annotation.Keep
import fr.iut.alldev.allin.data.model.bet.Bet
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.NO_VALUE
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.serialization.SimpleDateSerializer
import kotlinx.serialization.Serializable
@ -12,7 +14,7 @@ import java.time.ZonedDateTime
@Keep
@Serializable
data class ResponseBet(
val id: Int?,
val id: String?,
val theme: String,
val sentenceBet: String,
@Serializable(SimpleDateSerializer::class) val endRegistration: ZonedDateTime,
@ -22,7 +24,7 @@ data class ResponseBet(
val createdBy: String
) {
fun toBet(): Bet {
if (response.toSet() == setOf("Yes", "No")) {
if (response.toSet() == setOf(YES_VALUE, NO_VALUE)) {
return YesNoBet(
theme = theme,
phrase = sentenceBet,
@ -41,7 +43,7 @@ data class ResponseBet(
isPublic = !isPrivate,
betStatus = BetStatus.Waiting,
creator = createdBy,
possibleAnswers = response.toSet()
possibleAnswers = response
)
}
}

@ -16,15 +16,16 @@ data class RequestUser(
@Keep
@Serializable
data class ResponseUser(
val id: String,
val username: String,
val email: String,
var nbCoins: Int,
var token: String? = null,
) {
fun toUser() = User(
id = id,
username = username,
email = email,
id = "",
coins = nbCoins
)
}

@ -5,18 +5,25 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import fr.iut.alldev.allin.data.api.AllInApi
import fr.iut.alldev.allin.data.api.MockAllInApi
import fr.iut.alldev.allin.data.di.NetworkModule.createRetrofit
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import javax.inject.Singleton
const val mock = true
@Module
@InstallIn(SingletonComponent::class)
class ApiModule {
@Provides
@Singleton
fun provideAllInApi(@AllInUrl url: HttpUrl, okHttpClient: OkHttpClient): AllInApi {
val retrofit = createRetrofit(url = url, okHttpClient = okHttpClient)
return retrofit.create(AllInApi::class.java)
return if (mock) {
MockAllInApi()
} else {
val retrofit = createRetrofit(url = url, okHttpClient = okHttpClient)
retrofit.create(AllInApi::class.java)
}
}
}

@ -4,7 +4,7 @@ import fr.iut.alldev.allin.data.api.model.RequestBet
import java.time.ZonedDateTime
sealed class Bet(
open val id: Int? = null,
open val id: String? = null,
open val creator: String,
open val theme: String,
open val phrase: String,

@ -14,7 +14,7 @@ class BetFactory {
isPublic: Boolean,
nameTeam1: String = "",
nameTeam2: String = "",
possibleAnswers: Set<String> = emptySet(),
possibleAnswers: List<String> = emptyList(),
): Bet =
when (betType) {

@ -3,7 +3,7 @@ package fr.iut.alldev.allin.data.model.bet
import java.time.ZonedDateTime
data class CustomBet(
override val id: Int? = null,
override val id: String? = null,
override val creator: String,
override val theme: String,
override val phrase: String,
@ -11,7 +11,7 @@ data class CustomBet(
override val endBetDate: ZonedDateTime,
override val isPublic: Boolean,
override val betStatus: BetStatus,
val possibleAnswers: Set<String>,
val possibleAnswers: List<String>
) : Bet(
id,
creator,
@ -22,5 +22,5 @@ data class CustomBet(
isPublic,
betStatus
) {
override fun getResponses(): List<String> = possibleAnswers.toList()
override fun getResponses(): List<String> = possibleAnswers
}

@ -3,7 +3,7 @@ package fr.iut.alldev.allin.data.model.bet
import java.time.ZonedDateTime
data class MatchBet(
override val id: Int? = null,
override val id: String? = null,
override val creator: String,
override val theme: String,
override val phrase: String,
@ -12,7 +12,7 @@ data class MatchBet(
override val isPublic: Boolean,
override val betStatus: BetStatus,
val nameTeam1: String,
val nameTeam2: String,
val nameTeam2: String
) : Bet(
id,
creator,

@ -2,15 +2,18 @@ package fr.iut.alldev.allin.data.model.bet
import java.time.ZonedDateTime
const val YES_VALUE = "Yes"
const val NO_VALUE = "No"
data class YesNoBet(
override val id: Int? = null,
override val id: String? = null,
override val creator: String,
override val theme: String,
override val phrase: String,
override val endRegisterDate: ZonedDateTime,
override val endBetDate: ZonedDateTime,
override val isPublic: Boolean,
override val betStatus: BetStatus,
override val betStatus: BetStatus
) : Bet(
id,
creator,
@ -21,5 +24,5 @@ data class YesNoBet(
isPublic,
betStatus
) {
override fun getResponses(): List<String> = listOf("Yes", "No")
override fun getResponses(): List<String> = listOf(YES_VALUE, NO_VALUE)
}
Loading…
Cancel
Save