diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ext/BetStatusExt.kt b/src/app/src/main/java/fr/iut/alldev/allin/ext/BetStatusExt.kt index 97e2b0c..917fb41 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ext/BetStatusExt.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ext/BetStatusExt.kt @@ -14,6 +14,20 @@ fun BetStatus.getTitle(): Int { } } +fun BetStatus.getDateStartLabel(): Int { + return when (this) { + BetStatus.FINISHED -> R.string.Started + else -> R.string.Starting + } +} + +fun BetStatus.getDateEndLabel(): Int { + return when (this) { + BetStatus.FINISHED -> R.string.Ended + else -> R.string.Ends + } +} + @Composable fun BetStatus.getColor(): Color { return when (this) { diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/BetScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/BetScreen.kt index 270fa65..9e36ca3 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/BetScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/BetScreen.kt @@ -23,6 +23,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import fr.iut.alldev.allin.R 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.MatchBet import fr.iut.alldev.allin.data.model.bet.YesNoBet import fr.iut.alldev.allin.ui.bet.components.BetScreenCard import fr.iut.alldev.allin.ui.bet.components.BetScreenPopularCard @@ -32,12 +33,38 @@ import java.time.ZonedDateTime private val bets = listOf( YesNoBet( - "Études", - "Emre va t'il finir son TP de MAUI?", - ZonedDateTime.now(), - ZonedDateTime.now(), - true, - BetStatus.IN_PROGRESS + theme = "Études", + phrase = "Emre va t'il finir son TP de MAUI?", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.WAITING + ), + YesNoBet( + theme = "Études", + phrase = "Emre va t'il finir son TP de MAUI?", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.IN_PROGRESS + ), + YesNoBet( + theme = "Études", + phrase = "Emre va t'il finir son TP de MAUI?", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.FINISHED + ), + MatchBet( + theme = "Études", + phrase = "Emre va t'il finir son TP de MAUI?", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.WAITING, + nameTeam1 = "Team 1", + nameTeam2 = "Team 2" ), ) @@ -45,7 +72,7 @@ private val bets = listOf( @Composable fun BetScreen( viewModel: BetViewModel = hiltViewModel(), - selectBet: (Bet)->Unit + selectBet: (Bet, Boolean)->Unit ){ val horizontalPadding = 23.dp @@ -122,7 +149,8 @@ fun BetScreen( date = "11 Sept.", time = "13:00", players = List(3){ null }, - onClickParticipate = { selectBet(it) }, + onClickParticipate = { selectBet(it, true) }, + onClickCard = { selectBet(it, false) }, modifier = Modifier.padding(horizontal = horizontalPadding) ) Spacer(modifier = Modifier.height(24.dp)) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenCard.kt index e3f0148..88e7136 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenCard.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenCard.kt @@ -1,6 +1,7 @@ package fr.iut.alldev.allin.ui.bet.components import android.content.res.Configuration +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material3.HorizontalDivider @@ -8,6 +9,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.CenterHorizontally +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.pluralStringResource @@ -15,13 +17,14 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import fr.iut.alldev.allin.R -import fr.iut.alldev.allin.ui.core.AllInCard +import fr.iut.alldev.allin.ui.core.AllInBouncyCard import fr.iut.alldev.allin.ui.core.RainbowButton import fr.iut.alldev.allin.ui.core.bet.BetDateTimeRow import fr.iut.alldev.allin.ui.core.bet.BetProfilePictureRow import fr.iut.alldev.allin.ui.core.bet.BetTitleHeader import fr.iut.alldev.allin.ui.theme.AllInTheme +@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class) @Composable fun BetScreenCard( creator: String, @@ -31,11 +34,13 @@ fun BetScreenCard( time: String, players: List, modifier: Modifier = Modifier, - onClickParticipate: ()->Unit + onClickParticipate: ()->Unit, + onClickCard: ()->Unit ) { - AllInCard( + AllInBouncyCard( modifier = modifier.fillMaxWidth(), - radius = 16.dp + radius = 16.dp, + onClick = onClickCard ){ Column( Modifier.padding(horizontal = 19.dp, vertical = 11.dp) @@ -96,7 +101,8 @@ private fun BetScreenCardPreview() { date = "12 Sept.", time = "13:00", players = List(3){ null }, - onClickParticipate = {} + onClickParticipate = {}, + onClickCard = {} ) } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/BetStatusBottomSheet.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/BetStatusBottomSheet.kt index 9bd62c7..61612ee 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/BetStatusBottomSheet.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/BetStatusBottomSheet.kt @@ -14,7 +14,6 @@ import fr.iut.alldev.allin.vo.bet.BetVO internal const val SHEET_HEIGHT = .85f -private val visitor = BetStatusBottomSheetDisplayBetVisitor() @OptIn(ExperimentalMaterial3Api::class) @@ -24,7 +23,8 @@ fun BetStatusBottomSheet( sheetVisibility: Boolean, sheetBackVisibility: Boolean, bet: BetVO?, - onDismiss: ()->Unit + onDismiss: ()->Unit, + visitor: BetStatusBottomSheetDisplayBetVisitor ) { AnimatedVisibility( visible = sheetBackVisibility, @@ -49,8 +49,7 @@ fun BetStatusBottomSheet( scrimColor = Color.Transparent ){ Column( - Modifier - .fillMaxHeight(SHEET_HEIGHT) + Modifier.fillMaxHeight(SHEET_HEIGHT) ) { bet?.accept(visitor) } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/BetStatusParticipationBottomSheet.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/BetStatusParticipationBottomSheet.kt new file mode 100644 index 0000000..276cb5f --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/BetStatusParticipationBottomSheet.kt @@ -0,0 +1,126 @@ +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.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 +import fr.iut.alldev.allin.R +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.topbar.AllInTopBarCoinCounter +import fr.iut.alldev.allin.ui.theme.AllInTheme +import kotlinx.coroutines.launch + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BetStatusParticipationBottomSheet( + sheetVisibility: Boolean, + safeBottomPadding: Dp, + betPhrase: String, + coinAmount: Int, + onDismiss: ()->Unit, + state: SheetState, + onParticipate: ()->Unit +) { + val scope = rememberCoroutineScope() + AllInBottomSheet( + sheetVisibility = sheetVisibility, + onDismiss = onDismiss, + state = state, + containerColor = AllInTheme.themeColors.background_2 + ) { + 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.on_main_surface, + fontSize = 20.sp, + modifier = Modifier.padding(start = 18.dp) + ) + AllInTopBarCoinCounter( + amount = coinAmount, + backgroundColor = AllInTheme.colors.allIn_Blue, + textColor = AllInTheme.colors.white, + iconColor = AllInTheme.colors.white, + ) + } + Spacer(modifier = Modifier.height(30.dp)) + Text( + text = betPhrase, + style = AllInTheme.typography.s, + color = AllInTheme.themeColors.on_main_surface, + modifier = Modifier.padding(horizontal = 18.dp) + ) + 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.r, + color = AllInTheme.themeColors.on_background + ) + AllInCoinCount( + amount = 121, + color = AllInTheme.themeColors.on_background + ) + } + AllInButton( + color = AllInTheme.colors.allIn_Purple, + text = stringResource(id = R.string.Participate), + textColor = AllInTheme.colors.white, + radius = 5.dp + ){ + scope.launch{ + onParticipate() + state.hide() + onDismiss() + } + } + } + } +} + + + +@OptIn(ExperimentalMaterial3Api::class) +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun BetStatusParticipationBottomSheetPreview() { + AllInTheme { + BetStatusParticipationBottomSheet( + sheetVisibility = true, + safeBottomPadding = 5.dp, + betPhrase = "Lorem Ipsum", + coinAmount = 125, + onDismiss = {}, + state = rememberModalBottomSheetState(), + onParticipate = {} + ) + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/BetStatusWinner.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/BetStatusWinner.kt new file mode 100644 index 0000000..10611cd --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/BetStatusWinner.kt @@ -0,0 +1,84 @@ +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.material.icons.Icons +import androidx.compose.material.icons.filled.EmojiEvents +import androidx.compose.material.icons.filled.People +import androidx.compose.material3.HorizontalDivider +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import fr.iut.alldev.allin.ui.core.AllInCoinCount +import fr.iut.alldev.allin.ui.core.AllInTextIcon +import fr.iut.alldev.allin.ui.core.IconPosition +import fr.iut.alldev.allin.ui.theme.AllInTheme + +@Composable +fun BetStatusWinner( + answer: String, + coinAmount: Int, + username: String, + multiplier: Float, + color: Color = AllInTheme.themeColors.on_main_surface +) { + Column { + HorizontalDivider(color = color.copy(alpha = .4f)) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .background(color.copy(alpha = .2f)) + .padding(vertical = 20.dp) + ) { + AllInTextIcon( + text = answer, + icon = Icons.Filled.EmojiEvents, + color = color, + size = 50, + iconSize = 60, + position = IconPosition.LEADING + ) + Row( + horizontalArrangement = Arrangement.spacedBy(17.dp) + ) { + AllInCoinCount( + amount = coinAmount, + color = color, + position = IconPosition.LEADING + ) + AllInTextIcon( + text = username, + icon = Icons.Filled.People, + color = color, + position = IconPosition.LEADING + ) + AllInTextIcon( + text = "x" + String.format("%.1f", multiplier), + icon = Icons.Filled.EmojiEvents, + color = color, + position = IconPosition.LEADING + ) + } + } + } + HorizontalDivider(color = color.copy(alpha = .4f)) +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun BetStatusWinnerPreview() { + AllInTheme { + BetStatusWinner( + answer = "Answer", + coinAmount = 435, + username = "Imri", + multiplier = 1.2f, + ) + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/YesNoDetailsLine.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/YesNoDetailsLine.kt new file mode 100644 index 0000000..a454c76 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/YesNoDetailsLine.kt @@ -0,0 +1,85 @@ +package fr.iut.alldev.allin.ui.betstatus.components + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.tooling.preview.Preview +import fr.iut.alldev.allin.ui.core.AllInTextIcon +import fr.iut.alldev.allin.ui.core.IconPosition +import fr.iut.alldev.allin.ui.theme.AllInTheme + +@Composable +fun YesNoDetailsLine( + icon: ImageVector, + yesText: String, + noText: String +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + AllInTextIcon( + text = yesText, + color = AllInTheme.colors.allIn_Blue, + icon = icon, + position = IconPosition.LEADING, + size = 10, + iconSize = 15 + ) + AllInTextIcon( + text = noText, + color = AllInTheme.colors.allIn_BarPink, + icon = icon, + position = IconPosition.TRAILING, + size = 10, + iconSize = 15 + ) + } +} + +@Composable +fun YesNoDetailsLine( + icon: Painter, + yesText: String, + noText: String +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + AllInTextIcon( + text = yesText, + color = AllInTheme.colors.allIn_Blue, + icon = icon, + position = IconPosition.LEADING, + size = 10, + iconSize = 15 + ) + AllInTextIcon( + text = noText, + color = AllInTheme.colors.allIn_BarPink, + icon = icon, + position = IconPosition.TRAILING, + size = 10, + iconSize = 15 + ) + } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun YesNoDetailsLinePreview() { + AllInTheme { + YesNoDetailsLine( + icon = AllInTheme.icons.allCoins(), + yesText = "550", + noText = "330" + ) + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/YesNoStarBar.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/YesNoStarBar.kt index 13ac6df..1bde716 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/YesNoStarBar.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/components/YesNoStarBar.kt @@ -9,7 +9,6 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import fr.iut.alldev.allin.R import fr.iut.alldev.allin.data.ext.toPercentageString @@ -19,11 +18,10 @@ import fr.iut.alldev.allin.ui.theme.AllInTheme @Composable fun YesNoStatBar( - yesPercentage: Float + yesPercentage: Float, + modifier: Modifier = Modifier ) { - Column( - Modifier.padding(horizontal = 9.dp) - ){ + Column(modifier){ Row{ Text( text = stringResource(id = R.string.Yes).uppercase(), diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/visitor/BetStatusBottomSheetDisplayBetVisitor.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/visitor/BetStatusBottomSheetDisplayBetVisitor.kt index cc5bfca..861f5ef 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/visitor/BetStatusBottomSheetDisplayBetVisitor.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betstatus/visitor/BetStatusBottomSheetDisplayBetVisitor.kt @@ -1,33 +1,233 @@ package fr.iut.alldev.allin.ui.betstatus.visitor -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.EmojiEvents +import androidx.compose.material.icons.filled.People +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.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +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 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.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.MatchBet import fr.iut.alldev.allin.data.model.bet.YesNoBet -import fr.iut.alldev.allin.ui.core.StatBar +import fr.iut.alldev.allin.ext.getDateEndLabel +import fr.iut.alldev.allin.ext.getDateStartLabel +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 +import fr.iut.alldev.allin.ui.core.AllInDetailsDrawer +import fr.iut.alldev.allin.ui.core.RainbowButton +import fr.iut.alldev.allin.ui.core.bet.BetDateTimeRow import fr.iut.alldev.allin.ui.core.bet.BetTitleHeader +import fr.iut.alldev.allin.ui.theme.AllInTheme +import fr.iut.alldev.allin.vo.bet.factory.toBetVO import fr.iut.alldev.allin.vo.bet.visitor.DisplayBetVisitor +import java.time.ZonedDateTime -class BetStatusBottomSheetDisplayBetVisitor : DisplayBetVisitor { +class BetStatusBottomSheetDisplayBetVisitor( + val userCoinAmount: MutableState, + val onParticipate: (Int)->Unit +) : DisplayBetVisitor { + + val participateBottomSheetVisibility = mutableStateOf(false) + val paddingValues = mutableStateOf(PaddingValues()) + + @OptIn(ExperimentalMaterial3Api::class) @Composable override fun visitYesNoBet(b: YesNoBet) { - Column { - BetTitleHeader( - title = b.phrase, - category = b.theme, - creator = "Lucas" /*TODO : Creator*/, - modifier = Modifier.padding(horizontal = 20.dp) - ) - StatBar(percentage = .86f) + + val (participateSheetVisibility, setParticipateSheetVisibility) = remember{ + this.participateBottomSheetVisibility } - } + 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 = "Lucas" /*TODO : Creator*/, + modifier = Modifier.fillMaxWidth() + ) + Spacer(modifier = Modifier.height(20.dp)) + Column( + horizontalAlignment = Alignment.End + ) { + BetDateTimeRow( + label = stringResource(id = b.betStatus.getDateStartLabel()), + date = b.endRegisterDate.formatToMediumDateNoYear(), + time = b.endRegisterDate.formatToTime(), + modifier = Modifier.width(IntrinsicSize.Max) + ) + Spacer(modifier = Modifier.height(15.dp)) + BetDateTimeRow( + label = stringResource(id = b.betStatus.getDateEndLabel()), + date = b.endBetDate.formatToMediumDateNoYear(), + time = b.endBetDate.formatToTime(), + modifier = Modifier.width(IntrinsicSize.Max) + ) + } + Spacer(modifier = Modifier.height(20.dp)) + } + if (b.betStatus == BetStatus.FINISHED) { + BetStatusWinner( + answer = stringResource(id = R.string.Yes), + color = AllInTheme.colors.allIn_Blue, + coinAmount = 442, + username = "Imri", + multiplier = 1.2f + ) + } else { + HorizontalDivider(color = AllInTheme.themeColors.border) + } + Column( + Modifier + .fillMaxHeight() + .background(AllInTheme.themeColors.background_2) + .padding(horizontal = 20.dp) + ) { + Spacer(modifier = Modifier.height(20.dp)) + YesNoStatBar(yesPercentage = .86f) + AllInDetailsDrawer { + YesNoDetailsLine( + icon = AllInTheme.icons.allCoins(), + yesText = "550", + noText = "330", + ) + YesNoDetailsLine( + icon = Icons.Filled.People, + yesText = "12", + noText = "5" + ) + YesNoDetailsLine( + icon = Icons.Filled.WorkspacePremium, + yesText = "45", + noText = "45" + ) + YesNoDetailsLine( + icon = Icons.Filled.EmojiEvents, + yesText = "x1.2", + noText = "x1.45" + ) + } + } + } + if(b.betStatus != 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) + } + ) + } + } + + BetStatusParticipationBottomSheet( + sheetVisibility = participateSheetVisibility && b.betStatus == BetStatus.WAITING, + safeBottomPadding = safeBottomPadding, + betPhrase = b.phrase, + coinAmount = userCoinAmount.value, + onDismiss = { setParticipateSheetVisibility(false) }, + state = rememberModalBottomSheetState() + ){ + onParticipate(100) + } + } @Composable override fun visitMatchBet(b: MatchBet) { Text("This is a MATCH BET") } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun YesNoBetPreview() { + AllInTheme { + YesNoBet( + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.IN_PROGRESS + ).toBetVO()?.accept( + BetStatusBottomSheetDisplayBetVisitor( + userCoinAmount = mutableStateOf(100), + onParticipate = {} + ) + ) + } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun YesNoBetFinishedPreview() { + AllInTheme { + YesNoBet( + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.FINISHED + ).toBetVO()?.accept( + BetStatusBottomSheetDisplayBetVisitor( + userCoinAmount = mutableStateOf(100), + onParticipate = {} + ) + ) + } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun MatchBetPreview() { + AllInTheme { + MatchBet( + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.IN_PROGRESS, + nameTeam1 = "Team 1", + nameTeam2 = "Team 2" + ).toBetVO()?.accept( + BetStatusBottomSheetDisplayBetVisitor( + userCoinAmount = mutableStateOf(100), + onParticipate = {} + ) + ) + } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInBottomSheet.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInBottomSheet.kt index 3005eb3..54a8a1e 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInBottomSheet.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInBottomSheet.kt @@ -7,6 +7,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.dp +import fr.iut.alldev.allin.ui.theme.AllInTheme import racra.compose.smooth_corner_rect_library.AbsoluteSmoothCornerShape @OptIn(ExperimentalMaterial3Api::class) @@ -16,6 +17,7 @@ fun AllInBottomSheet( onDismiss: ()->Unit, state: SheetState, scrimColor: Color = BottomSheetDefaults.ScrimColor, + containerColor: Color = AllInTheme.themeColors.background, content: @Composable ColumnScope.()->Unit ) { val localDensity = LocalDensity.current @@ -25,6 +27,7 @@ fun AllInBottomSheet( ModalBottomSheet( onDismissRequest = onDismiss, sheetState = state, + containerColor = containerColor, scrimColor = scrimColor, shape = sheetShape, windowInsets = BottomSheetDefaults.windowInsets.let { diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInButton.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInButton.kt index 8dcb31d..4e976e9 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInButton.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInButton.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign 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 import fr.iut.alldev.allin.ui.theme.AllInTheme @@ -17,10 +18,16 @@ fun AllInButton( color: Color, text: String, textColor: Color, + radius: Dp = 15.dp, modifier: Modifier = Modifier, onClick: ()->Unit ) { - AllInCard(onClick = onClick, modifier = modifier, radius = 50.dp, backgroundColor = color) { + AllInCard( + onClick = onClick, + modifier = modifier, + radius = radius, + backgroundColor = color + ) { Text( text = text, textAlign = TextAlign.Center, diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCard.kt index 09f2a43..5a07b51 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCard.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCard.kt @@ -1,13 +1,23 @@ package fr.iut.alldev.allin.ui.core +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.spring import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp @@ -69,3 +79,52 @@ fun AllInCard( } } } + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun AllInBouncyCard( + modifier: Modifier = Modifier, + onClick: (()->Unit)? = null, + radius: Dp = 15.dp, + enabled: Boolean = true, + backgroundColor: Color = AllInTheme.themeColors.background, + disabledBackgroundColor: Color = AllInTheme.themeColors.disabled, + backgroundBrush: Brush? = null, + borderWidth: Dp? = null, + borderColor: Color = AllInTheme.themeColors.border, + disabledBorderColor: Color = AllInTheme.themeColors.disabled_border, + borderBrush: Brush? = null, + content: @Composable ()->Unit +){ + val interactionSource = remember { MutableInteractionSource() } + val isPressed by interactionSource.collectIsPressedAsState() + + val scale by animateFloatAsState( + targetValue = if(isPressed) .95f else 1f, + animationSpec = spring( + Spring.DampingRatioHighBouncy, + Spring.StiffnessMediumLow + ) + ) + AllInCard( + modifier = modifier + .combinedClickable( + interactionSource = interactionSource, + indication = null, + onClick = { onClick?.let { it() } } + ) + .scale(scale), + onClick = null, + radius = radius, + enabled = enabled, + backgroundColor = backgroundColor, + disabledBackgroundColor = disabledBackgroundColor, + backgroundBrush = backgroundBrush, + borderWidth = borderWidth, + borderColor = borderColor, + disabledBorderColor = disabledBorderColor, + borderBrush = borderBrush, + content = content + ) + +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCoinCount.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCoinCount.kt index afbdead..557b06f 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCoinCount.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCoinCount.kt @@ -1,49 +1,26 @@ package fr.iut.alldev.allin.ui.core import android.content.res.Configuration -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.size -import androidx.compose.material3.Icon -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -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.sp -import fr.iut.alldev.allin.R import fr.iut.alldev.allin.ui.theme.AllInTheme @Composable fun AllInCoinCount( modifier: Modifier = Modifier, amount: Int, - color: Color + color: Color, + position: IconPosition = IconPosition.TRAILING ) { - Row( - modifier = modifier, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(7.dp) - ) { - Text( - text = amount.toString(), - fontWeight = FontWeight.ExtraBold, - color = color, - style = AllInTheme.typography.h1, - fontSize = 16.sp - ) - Icon( - painter = painterResource(id = R.drawable.allcoin), - contentDescription = null, - modifier = Modifier - .size(13.dp), - tint = color - ) - } + AllInTextIcon( + text = amount.toString(), + icon = AllInTheme.icons.allCoins(), + color = color, + position = position, + modifier = modifier + ) } @Preview diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDetailsDrawer.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDetailsDrawer.kt new file mode 100644 index 0000000..1c404d6 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDetailsDrawer.kt @@ -0,0 +1,81 @@ +package fr.iut.alldev.allin.ui.core + +import android.content.res.Configuration +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ExpandLess +import androidx.compose.material.icons.filled.ExpandMore +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import fr.iut.alldev.allin.R +import fr.iut.alldev.allin.ui.theme.AllInTheme + +@Composable +fun AllInDetailsDrawer( + text: String = stringResource(id = R.string.Details), + textColor: Color = AllInTheme.themeColors.on_background_2, + content: @Composable ColumnScope.()->Unit +){ + val interactionSource = remember { MutableInteractionSource() } + var isOpen by remember { mutableStateOf(false) } + + Column( + Modifier + .fillMaxWidth() + .animateContentSize() + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .align(Alignment.End) + .clickable( + interactionSource = interactionSource, + indication = null, + onClick = { + isOpen = !isOpen + } + ) + ){ + Text( + text = text, + style = AllInTheme.typography.s, + color = textColor, + fontSize = 15.sp + ) + Icon( + imageVector = with(Icons.Default){ + if(isOpen) ExpandLess else ExpandMore + }, + contentDescription = null, + tint = textColor, + modifier = Modifier.size(15.dp) + ) + } + AnimatedVisibility(visible = isOpen){ + Column { + content() + } + } + } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun AllInDetailsDrawerPreview() { + AllInTheme { + AllInDetailsDrawer{} + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInLoading.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInLoading.kt index cf6b8f2..ddbac31 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInLoading.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInLoading.kt @@ -1,7 +1,10 @@ package fr.iut.alldev.allin.ui.core import android.content.res.Configuration +import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.* +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.foundation.Canvas import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -23,9 +26,13 @@ import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalView import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import androidx.compose.ui.window.DialogWindowProvider import fr.iut.alldev.allin.ui.theme.AllInTheme import kotlin.math.PI import kotlin.math.abs @@ -34,26 +41,44 @@ import kotlin.math.max @Composable fun AllInLoading( modifier: Modifier = Modifier, + visible: Boolean, brush: Brush = AllInTheme.colors.allIn_MainGradient ) { val interactionSource = remember { MutableInteractionSource() } - Box( - modifier = modifier - .fillMaxSize() - .clickable( - interactionSource = interactionSource, - indication = null, - onClick = {} - ) - .background(AllInTheme.themeColors.main_surface.copy(alpha = .4f)) + AnimatedVisibility( + visible = visible, + enter = fadeIn(), + exit = fadeOut() ) { - AllInCircularProgressIndicator( - modifier = Modifier - .align(Alignment.Center) - .size(50.dp), - brush = brush, - strokeWidth = 7.dp - ) + Dialog( + onDismissRequest = {}, + properties = DialogProperties( + dismissOnBackPress = false, + dismissOnClickOutside = false, + decorFitsSystemWindows = false, + usePlatformDefaultWidth = false + ) + ) { + (LocalView.current.parent as DialogWindowProvider).window.setDimAmount(0f) + Box( + modifier = modifier + .fillMaxSize() + .clickable( + interactionSource = interactionSource, + indication = null, + onClick = {} + ) + .background(AllInTheme.themeColors.main_surface.copy(alpha = .4f)) + ) { + AllInCircularProgressIndicator( + modifier = Modifier + .align(Alignment.Center) + .size(50.dp), + brush = brush, + strokeWidth = 7.dp + ) + } + } } } @@ -204,6 +229,6 @@ private val CircularEasing = CubicBezierEasing(0.4f, 0f, 0.2f, 1f) @Composable private fun AllInLoadingPreview() { AllInTheme { - AllInLoading() + AllInLoading(visible = true) } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInRetractableCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInRetractableCard.kt index 5b47ae6..fe683c1 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInRetractableCard.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInRetractableCard.kt @@ -1,5 +1,6 @@ package fr.iut.alldev.allin.ui.core +import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateContentSize import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -71,9 +72,11 @@ fun AllInRetractableCard( modifier = Modifier.size(30.dp) ) } - if(isOpen){ - HorizontalDivider(color = AllInTheme.themeColors.border) - content() + AnimatedVisibility(isOpen){ + Column{ + HorizontalDivider(color = AllInTheme.themeColors.border) + content() + } } } } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSelectionBox.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSelectionBox.kt index cdb6846..d8bd07e 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSelectionBox.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSelectionBox.kt @@ -1,6 +1,7 @@ package fr.iut.alldev.allin.ui.core import android.content.res.Configuration +import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateContentSize import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -104,19 +105,20 @@ fun AllInSelectionBox( if(isOpen) ExpandLess else ExpandMore } ) - if(isOpen){ - HorizontalDivider(color = AllInTheme.themeColors.border) - elements.filter { it != selected }.forEach{ - element -> - AllInSelectionLine( - text = stringResource(id = element.textId), - iconVector = element.imageVector, - interactionSource = interactionSource, - onClick = { - setSelected(element) - setIsOpen(false) - } - ) + AnimatedVisibility(isOpen){ + Column { + HorizontalDivider(color = AllInTheme.themeColors.border) + elements.filter { it != selected }.forEach { element -> + AllInSelectionLine( + text = stringResource(id = element.textId), + iconVector = element.imageVector, + interactionSource = interactionSource, + onClick = { + setSelected(element) + setIsOpen(false) + } + ) + } } } } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextIcon.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextIcon.kt new file mode 100644 index 0000000..9948881 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextIcon.kt @@ -0,0 +1,132 @@ +package fr.iut.alldev.allin.ui.core + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Fireplace +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import fr.iut.alldev.allin.ui.theme.AllInTheme + + +enum class IconPosition{ + LEADING, + TRAILING +} + +@Composable +fun AllInTextIcon( + modifier: Modifier = Modifier, + text: String, + icon: Painter, + color: Color, + position: IconPosition = IconPosition.TRAILING, + size: Int = 15, + iconSize: Int = size +) { + val direction = + if(position==IconPosition.LEADING) LayoutDirection.Rtl + else LayoutDirection.Ltr + Box(modifier) { + CompositionLocalProvider( + LocalLayoutDirection provides direction + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(7.dp) + ) { + Text( + text = text, + color = color, + style = AllInTheme.typography.h1, + fontSize = size.sp + ) + Icon( + painter = icon, + contentDescription = null, + modifier = Modifier.size(iconSize.dp), + tint = color + ) + } + } + } +} + + +@Composable +fun AllInTextIcon( + modifier: Modifier = Modifier, + text: String, + icon: ImageVector, + color: Color, + position: IconPosition = IconPosition.TRAILING, + size: Int = 15, + iconSize: Int = size +) { + val direction = + if(position==IconPosition.LEADING) LayoutDirection.Rtl + else LayoutDirection.Ltr + Box(modifier) { + CompositionLocalProvider( + LocalLayoutDirection provides direction + ) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(7.dp) + ) { + Text( + text = text, + color = color, + style = AllInTheme.typography.h1, + fontSize = size.sp + ) + Icon( + imageVector = icon, + contentDescription = null, + modifier = Modifier.size(iconSize.dp), + tint = color + ) + } + } + } +} + +@Preview +@Composable +private fun AllInTextIconPreview() { + AllInTheme { + AllInTextIcon( + text = "value", + icon = Icons.Default.Fireplace, + color = AllInTheme.colors.allIn_Blue + ) + } +} + +@Preview +@Composable +private fun AllInTextIconReversePreview() { + AllInTheme { + AllInTextIcon( + text = "value", + icon = AllInTheme.icons.allCoins(), + color = AllInTheme.colors.allIn_Blue, + position = IconPosition.LEADING + ) + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/RainbowButton.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/RainbowButton.kt index 027343b..a376787 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/RainbowButton.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/RainbowButton.kt @@ -23,7 +23,7 @@ fun RainbowButton( ) { AllInRipple(rippleColor) { AllInCard( - borderWidth = if (enabled) 1.dp else 2.dp, + borderWidth = 1.dp, onClick = onClick, modifier = modifier.fillMaxWidth(), enabled = enabled diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/topbar/coinCounter.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/topbar/coinCounter.kt index 90b27ef..0961116 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/topbar/coinCounter.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/topbar/coinCounter.kt @@ -12,30 +12,35 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource +import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import fr.iut.alldev.allin.R import fr.iut.alldev.allin.ui.theme.AllInTheme @Composable -fun CoinCounter(amount:Int, modifier: Modifier = Modifier) { +fun AllInTopBarCoinCounter( + amount:Int, + backgroundColor: Color = AllInTheme.colors.white, + textColor: Color = AllInTheme.colors.allIn_Dark, + iconColor: Color = AllInTheme.colors.allIn_Blue, + modifier: Modifier = Modifier +) { Card(modifier = modifier.wrapContentSize(), shape = RoundedCornerShape(topStartPercent = 50, bottomStartPercent = 50)) { Row( modifier = Modifier - .background(AllInTheme.colors.white) + .background(backgroundColor) .padding(horizontal = 13.dp, vertical = 5.dp), horizontalArrangement = Arrangement.spacedBy(7.dp), verticalAlignment = Alignment.CenterVertically ) { Text(text = amount.toString(), - color = AllInTheme.colors.allIn_Dark, + color = textColor, style = AllInTheme.typography.h1, fontSize = 20.sp) Icon( - painter = painterResource(R.drawable.allcoin), - tint = AllInTheme.colors.allIn_Blue, + painter = AllInTheme.icons.allCoins(), + tint = iconColor, contentDescription = null, ) } @@ -44,8 +49,8 @@ fun CoinCounter(amount:Int, modifier: Modifier = Modifier) { @Preview @Composable -private fun CoinCounterPreview() { +private fun AllInTopBarCoinCounterPreview() { AllInTheme { - CoinCounter(547) + AllInTopBarCoinCounter(547) } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/topbar/topbar.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/topbar/topbar.kt index e4c1917..a193606 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/topbar/topbar.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/topbar/topbar.kt @@ -45,7 +45,7 @@ fun AllInTopBar( .size(40.dp) .align(Alignment.Center) ) - CoinCounter( + AllInTopBarCoinCounter( amount = coinAmount, modifier = Modifier .align(Alignment.CenterEnd) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/login/LoginScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/login/LoginScreen.kt index 4192a39..c4d7138 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/login/LoginScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/login/LoginScreen.kt @@ -1,6 +1,5 @@ package fr.iut.alldev.allin.ui.login -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.* @@ -161,9 +160,7 @@ fun LoginScreen( } } } - AnimatedVisibility(visible = loading) { - AllInLoading() - } + AllInLoading(visible = loading) AllInAlertDialog( enabled = hasLoginError, title = stringResource(id = R.string.Login_Error_Title), diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainScreen.kt index 8b57b1f..ebb4d6e 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainScreen.kt @@ -11,6 +11,8 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import fr.iut.alldev.allin.ui.betstatus.BetStatusBottomSheet +import fr.iut.alldev.allin.ui.betstatus.visitor.BetStatusBottomSheetDisplayBetVisitor +import fr.iut.alldev.allin.ui.core.AllInLoading import fr.iut.alldev.allin.ui.main.components.AllInScaffold import fr.iut.alldev.allin.ui.navigation.AllInDrawerNavHost import fr.iut.alldev.allin.ui.navigation.Routes @@ -28,8 +30,10 @@ private val topLevelDestinations = listOf( TopLevelDestination.FRIENDS, TopLevelDestination.CURRENT_BETS ) + @Composable -private fun rememberBetStatusVisibilities(): Triple, MutableState, (Boolean) -> Unit> { +private fun rememberBetStatusVisibilities() +: Triple, MutableState, (Boolean) -> Unit> { val statusVisibility = remember { mutableStateOf(false) } @@ -43,7 +47,11 @@ private fun rememberBetStatusVisibilities(): Triple, Mutab statusVisibility.value = it if(it) sheetBackVisibility.value = true } - return Triple(statusVisibility, sheetBackVisibility, setStatusVisibility) + return Triple( + statusVisibility, + sheetBackVisibility, + setStatusVisibility, + ) } @OptIn(ExperimentalMaterial3Api::class) @@ -54,15 +62,25 @@ fun MainScreen( startDestination: String = Routes.PUBLIC_BETS, mainViewModel: MainViewModel = hiltViewModel() ) { + val loading by remember{ mainViewModel.loading } val currentUser = remember{ - mainViewModel.currentUser + mainViewModel.currentUserState } val (selectedBet, setSelectedBet) = remember{ mainViewModel.selectedBet } + val betStatusDisplayVisitor = remember { + BetStatusBottomSheetDisplayBetVisitor( + userCoinAmount = currentUser.userCoins, + onParticipate = { + mainViewModel.participateToBet(it) + } + ) + } + val scope = rememberCoroutineScope() val (statusVisibility, sheetBackVisibility, setStatusVisibility) @@ -82,7 +100,7 @@ fun MainScreen( drawerState = drawerState, destinations = topLevelDestinations, scope = scope, - username = currentUser.username, + username = currentUser.user.username, nbFriends = 5, nbBets = 35, bestWin = 362, @@ -92,9 +110,12 @@ fun MainScreen( ){ AllInScaffold( onMenuClicked = { scope.launch { drawerState.open() } }, - coinAmount = currentUser.coins, + coinAmount = currentUser.userCoins.value, drawerState = drawerState ) { + LaunchedEffect(key1 = it){ + betStatusDisplayVisitor.paddingValues.value = it + } Column( modifier = Modifier .padding(top = it.calculateTopPadding()) @@ -104,8 +125,9 @@ fun MainScreen( ) { AllInDrawerNavHost( navController = navController, - selectBet = { - setSelectedBet(it) + selectBet = { bet, participate -> + setSelectedBet(bet) + betStatusDisplayVisitor.participateBottomSheetVisibility.value = participate setStatusVisibility(true) } ) @@ -120,8 +142,10 @@ fun MainScreen( onDismiss = { setStatusVisibility(false) }, - bet = selectedBet?.toBetVO() + bet = selectedBet?.toBetVO(), + visitor = betStatusDisplayVisitor ) + AllInLoading(visible = loading) BackHandler( enabled = drawerState.isOpen ) { @@ -130,13 +154,6 @@ fun MainScreen( } } - BackHandler( - enabled = statusVisibility.value - ) { - scope.launch { - setStatusVisibility(false) - } - } } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainViewModel.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainViewModel.kt index a863bc9..f1756b4 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainViewModel.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainViewModel.kt @@ -2,16 +2,41 @@ package fr.iut.alldev.allin.ui.main import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import fr.iut.alldev.allin.data.model.User import fr.iut.alldev.allin.data.model.bet.Bet import fr.iut.alldev.allin.di.AllInCurrentUser -import fr.iut.alldev.allin.data.model.User +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import javax.inject.Inject +class UserState(val user: User){ + val userCoins = mutableStateOf(user.coins) +} @HiltViewModel class MainViewModel @Inject constructor( @AllInCurrentUser val currentUser: User ) : ViewModel() { + + var loading = mutableStateOf(false) + + val currentUserState = UserState(currentUser) val selectedBet = mutableStateOf(null) + + fun participateToBet( + stake: Int + ){ + viewModelScope.launch { + withContext(Dispatchers.IO) { + loading.value = true + currentUserState.userCoins.value += 50 + Thread.sleep(1000) + loading.value = false + } + } + } + } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/NavHost.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/NavHost.kt index 22b85e9..d7fcdf1 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/NavHost.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/NavHost.kt @@ -81,7 +81,7 @@ fun AllInNavHost(modifier: Modifier = Modifier, internal fun AllInDrawerNavHost( modifier: Modifier = Modifier, navController: NavHostController, - selectBet: (Bet) -> Unit, + selectBet: (Bet, Boolean) -> Unit, startDestination: String = Routes.PUBLIC_BETS ) { NavHost( diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/register/RegisterScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/register/RegisterScreen.kt index a64efcb..3fe01cc 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/register/RegisterScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/register/RegisterScreen.kt @@ -1,6 +1,5 @@ package fr.iut.alldev.allin.ui.register -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.relocation.BringIntoViewRequester @@ -201,7 +200,5 @@ fun RegisterScreen( } } } - AnimatedVisibility(visible = loading) { - AllInLoading() - } + AllInLoading(visible = loading) } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Icons.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Icons.kt new file mode 100644 index 0000000..a1e3c4d --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Icons.kt @@ -0,0 +1,19 @@ +package fr.iut.alldev.allin.ui.theme + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.ColorPainter +import androidx.compose.ui.graphics.painter.Painter + +@Immutable +data class AllInIcons( + val allCoins: @Composable ()->Painter, +) + +internal val LocalIcons = staticCompositionLocalOf { + AllInIcons( + allCoins = { ColorPainter(Color.Unspecified) } + ) +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Theme.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Theme.kt index eb36e3a..4525dea 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Theme.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Theme.kt @@ -9,8 +9,10 @@ import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import fr.iut.alldev.allin.R @Composable @@ -134,8 +136,13 @@ fun AllInTheme( ) } + val customIcons = AllInIcons( + allCoins = { painterResource(id = R.drawable.allcoin) } + ) + CompositionLocalProvider( LocalColors provides customColors, + LocalIcons provides customIcons, LocalTypography provides customTypography, LocalThemeColors provides customTheme ){ @@ -149,6 +156,11 @@ object AllInTheme { @ReadOnlyComposable get() = LocalColors.current + val icons: AllInIcons + @Composable + @ReadOnlyComposable + get() = LocalIcons.current + val typography: AllInTypography @Composable @ReadOnlyComposable diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Type.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Type.kt index 5c73744..204346f 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Type.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/theme/Type.kt @@ -29,7 +29,7 @@ data class AllInTypography( val xs: TextStyle ) -val LocalTypography = staticCompositionLocalOf { +internal val LocalTypography = staticCompositionLocalOf { AllInTypography( h1 = TextStyle.Default, h2 = TextStyle.Default, diff --git a/src/app/src/main/java/fr/iut/alldev/allin/utils/Tuples.kt b/src/app/src/main/java/fr/iut/alldev/allin/utils/Tuples.kt new file mode 100644 index 0000000..922ca6e --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/utils/Tuples.kt @@ -0,0 +1,12 @@ +package fr.iut.alldev.allin.utils + +import java.io.Serializable + +data class Quadruple( + val first: A, + val second: B, + val third: C, + val fourth: D +) : Serializable { + override fun toString(): String = "($first, $second, $third, $fourth)" +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/ViewObject.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/ViewObject.kt index dceeeb1..ccd7e20 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/vo/ViewObject.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/vo/ViewObject.kt @@ -2,7 +2,7 @@ package fr.iut.alldev.allin.vo import androidx.compose.runtime.Composable -interface ViewObject{ +interface ViewObject{ @Composable fun accept(v: V) } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/Visitor.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/Visitor.kt new file mode 100644 index 0000000..00aa0a2 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/vo/Visitor.kt @@ -0,0 +1,3 @@ +package fr.iut.alldev.allin.vo + +interface Visitor \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/factory/BetVOFactory.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/factory/BetVOFactory.kt index 1b93d5d..90cbf02 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/factory/BetVOFactory.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/factory/BetVOFactory.kt @@ -11,7 +11,6 @@ private val betTypeToVOMap = mapOf( YesNoBet::class.java to YesNoBetVOFactory(), MatchBet::class.java to MatchBetVOFactory() ) - abstract class BetVOFactory { abstract fun create(bet: @UnsafeVariance T): BetVO<@UnsafeVariance T> } @@ -26,5 +25,6 @@ class MatchBetVOFactory : BetVOFactory() { MatchBetVO(bet) } -fun Bet.toBetVO() = - betTypeToVOMap[this.javaClass]?.create(this) +fun Bet.toBetVO() = betTypeToVOMap[this.javaClass]?.create(this) + + diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/visitor/BetVisitor.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/visitor/BetVisitor.kt index 06101ea..58a1b11 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/visitor/BetVisitor.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/visitor/BetVisitor.kt @@ -3,9 +3,10 @@ package fr.iut.alldev.allin.vo.bet.visitor import androidx.compose.runtime.Composable import fr.iut.alldev.allin.data.model.bet.MatchBet import fr.iut.alldev.allin.data.model.bet.YesNoBet +import fr.iut.alldev.allin.vo.Visitor -interface DisplayBetVisitor { +interface DisplayBetVisitor : Visitor { @Composable fun visitYesNoBet(b: YesNoBet) diff --git a/src/app/src/main/res/values-fr/strings.xml b/src/app/src/main/res/values-fr/strings.xml index 1772fd4..e6511ab 100644 --- a/src/app/src/main/res/values-fr/strings.xml +++ b/src/app/src/main/res/values-fr/strings.xml @@ -20,6 +20,9 @@ %s est déjà utilisé. Oui Non + Détails + Mise + Gains possibles Bets @@ -82,6 +85,9 @@ En cours Terminés Commence le + A commencé le + Prend fin le + A pris fin le Participer Proposé par %1$s @@ -104,5 +110,6 @@ Terminé ! En cours… En attente… + Faites vos paris \ No newline at end of file diff --git a/src/app/src/main/res/values/strings.xml b/src/app/src/main/res/values/strings.xml index 75b5482..e29d1bd 100644 --- a/src/app/src/main/res/values/strings.xml +++ b/src/app/src/main/res/values/strings.xml @@ -22,7 +22,10 @@ %s is already used. Yes No - + Details + Stake + Possible winnings + Bets Best win @@ -84,7 +87,10 @@ Invitation Current Finished - Starting + Starting on + Started on + Ends on + Ended on Participate Proposed by %1$s @@ -103,4 +109,5 @@ Finished ! In progress… Waiting… + Place your bets \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/api/AllInApi.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/api/AllInApi.kt index 9dd4a6c..be18a76 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/api/AllInApi.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/api/AllInApi.kt @@ -1,6 +1,7 @@ package fr.iut.alldev.allin.data.api import fr.iut.alldev.allin.data.api.model.CheckUser +import fr.iut.alldev.allin.data.api.model.RequestUser import fr.iut.alldev.allin.data.api.model.ResponseUser import retrofit2.http.Body import retrofit2.http.POST @@ -13,6 +14,6 @@ interface AllInApi { @POST("users/register") suspend fun register( - @Body body: ResponseUser + @Body body: RequestUser ): ResponseUser } \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ResponseUser.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ResponseUser.kt index 3cbcd6e..e29b6a1 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ResponseUser.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ResponseUser.kt @@ -6,11 +6,19 @@ import kotlinx.serialization.Serializable @Keep @Serializable -data class ResponseUser( +data class RequestUser( val username: String, val email: String, val password: String, var nbCoins: Int, +) + +@Keep +@Serializable +data class ResponseUser( + val username: String, + val email: String, + var nbCoins: Int, ){ fun toUser() = User( username = username, diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/ext/DateExt.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/ext/DateExt.kt index 130c9f7..a7e64b5 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/ext/DateExt.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/ext/DateExt.kt @@ -9,6 +9,12 @@ fun ZonedDateTime.formatToMediumDate(): String { ).replaceFirstChar { it.uppercase() } } +fun ZonedDateTime.formatToMediumDateNoYear(): String { + return this.format( + DateTimeFormatter.ofPattern("dd MMM") + ).replaceFirstChar { it.uppercase() } +} + fun ZonedDateTime.formatToTime(): String { return this.format( DateTimeFormatter.ofPattern("HH:mm") diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/UserRepositoryImpl.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/UserRepositoryImpl.kt index 8ae17e6..3380105 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/UserRepositoryImpl.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/UserRepositoryImpl.kt @@ -2,7 +2,7 @@ package fr.iut.alldev.allin.data.repository.impl import fr.iut.alldev.allin.data.api.AllInApi import fr.iut.alldev.allin.data.api.model.CheckUser -import fr.iut.alldev.allin.data.api.model.ResponseUser +import fr.iut.alldev.allin.data.api.model.RequestUser import fr.iut.alldev.allin.data.repository.UserRepository import javax.inject.Inject @@ -22,7 +22,7 @@ class UserRepositoryImpl @Inject constructor( override suspend fun register(username: String, email: String, password: String) { currentUser = api.register( - ResponseUser( + RequestUser( username = username, email = email, password = password,