Add daily reward and fix event queue
continuous-integration/drone/push Build is passing Details

pull/5/head
avalin 1 year ago
parent fda26944d3
commit 527577677a

@ -112,7 +112,8 @@ fun BetConfirmationBottomSheetAnswer(
text = text.uppercase(), text = text.uppercase(),
color = contentColor ?: color, color = contentColor ?: color,
style = AllInTheme.typography.h1, style = AllInTheme.typography.h1,
fontSize = 40.sp, fontSize = 30.sp,
textAlign = TextAlign.Center,
modifier = Modifier.align(Alignment.Center) modifier = Modifier.align(Alignment.Center)
) )

@ -0,0 +1,219 @@
package fr.iut.alldev.allin.ui.dailyReward
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
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.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
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.sp
import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.theme.AllInColorToken
import fr.iut.alldev.allin.theme.AllInTheme
@Composable
fun DailyRewardScreen(
amount: Int,
onDismiss: () -> Unit
) {
var hasOpened by remember { mutableStateOf(false) }
DailyRewardScreenContent(
amount = amount,
hasOpened = hasOpened
) {
if (hasOpened) {
onDismiss()
} else {
hasOpened = true
}
}
}
@Composable
fun DailyRewardScreenContent(
amount: Int,
hasOpened: Boolean,
onClick: () -> Unit
) {
val interactionSource = remember { MutableInteractionSource() }
val infiniteTransition = rememberInfiniteTransition(label = "")
val rotation by infiniteTransition.animateFloat(
initialValue = 3f,
targetValue = -3f,
animationSpec = infiniteRepeatable(
animation = tween(900),
repeatMode = RepeatMode.Reverse
), label = ""
)
val scale by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = .95f,
animationSpec = infiniteRepeatable(
animation = tween(900),
repeatMode = RepeatMode.Reverse
), label = ""
)
Column(
modifier = Modifier
.fillMaxSize()
.background(
Brush.verticalGradient(
0f to AllInColorToken.black.copy(alpha = .71f),
1f to AllInColorToken.black.copy(alpha = .97f)
)
)
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = onClick
),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(id = R.string.daily_reward_title),
style = AllInTheme.typography.h1,
fontSize = 20.sp,
color = AllInColorToken.white,
textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = 48.dp)
)
Box(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
.padding(horizontal = 48.dp),
contentAlignment = Alignment.Center
) {
Spacer(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
)
androidx.compose.animation.AnimatedVisibility(
visible = !hasOpened,
enter = fadeIn() + scaleIn(),
exit = fadeOut() + scaleOut(targetScale = 2f)
) {
Image(
painter = painterResource(id = R.drawable.daily_reward_1),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
.rotate(rotation)
.scale(scale)
)
}
androidx.compose.animation.AnimatedVisibility(
visible = hasOpened,
enter = fadeIn() + scaleIn(),
exit = fadeOut() + scaleOut(targetScale = 2f)
) {
Box(
contentAlignment = Alignment.BottomCenter
) {
Image(
painter = painterResource(id = R.drawable.daily_reward_2),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.rotate(rotation)
.scale(scale)
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
.rotate(-rotation)
.scale(scale)
) {
Text(
text = "+$amount",
style = AllInTheme.typography.h1,
fontSize = 70.sp,
color = AllInColorToken.white
)
Icon(
painter = AllInTheme.icons.allCoins(),
tint = AllInColorToken.white,
contentDescription = null,
modifier = Modifier.size(48.dp)
)
}
}
}
}
Text(
text = stringResource(id = R.string.daily_reward_subtitle),
style = AllInTheme.typography.l1,
color = AllInColorToken.white,
textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = 48.dp)
)
}
}
@Preview(showBackground = true)
@Composable
private fun DailyRewardScreenPreview() {
AllInTheme {
DailyRewardScreenContent(
amount = 125,
hasOpened = false,
onClick = {}
)
}
}
@Preview(showBackground = true)
@Composable
private fun DailyRewardScreenStep2Preview() {
AllInTheme {
DailyRewardScreenContent(
amount = 125,
hasOpened = true,
onClick = {}
)
}
}

@ -1,6 +1,9 @@
package fr.iut.alldev.allin.ui.main package fr.iut.alldev.allin.ui.main
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -33,12 +36,19 @@ import fr.iut.alldev.allin.ui.betStatus.vo.BetStatusBottomSheetBetDisplayer
import fr.iut.alldev.allin.ui.core.AllInLoading import fr.iut.alldev.allin.ui.core.AllInLoading
import fr.iut.alldev.allin.ui.core.snackbar.AllInSnackbarVisualsImpl import fr.iut.alldev.allin.ui.core.snackbar.AllInSnackbarVisualsImpl
import fr.iut.alldev.allin.ui.main.components.AllInScaffold import fr.iut.alldev.allin.ui.main.components.AllInScaffold
import fr.iut.alldev.allin.ui.main.event.DailyReward
import fr.iut.alldev.allin.ui.main.event.ToConfirmBet
import fr.iut.alldev.allin.ui.main.event.WonBet
import fr.iut.alldev.allin.ui.navigation.AllInDrawerNavHost import fr.iut.alldev.allin.ui.navigation.AllInDrawerNavHost
import fr.iut.alldev.allin.ui.navigation.Routes import fr.iut.alldev.allin.ui.navigation.Routes
import fr.iut.alldev.allin.ui.navigation.TopLevelDestination import fr.iut.alldev.allin.ui.navigation.TopLevelDestination
import fr.iut.alldev.allin.ui.navigation.drawer.AllInDrawer import fr.iut.alldev.allin.ui.navigation.drawer.AllInDrawer
import fr.iut.alldev.allin.ui.navigation.popUpTo import fr.iut.alldev.allin.ui.navigation.popUpTo
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
const val EVENT_DISMISS_DELAY_MS = 300L
private val topLevelDestinations = listOf( private val topLevelDestinations = listOf(
TopLevelDestination.PublicBets, TopLevelDestination.PublicBets,
@ -111,7 +121,6 @@ fun MainScreen(
} }
) )
AllInDrawer( AllInDrawer(
drawerState = drawerState, drawerState = drawerState,
destinations = topLevelDestinations, destinations = topLevelDestinations,
@ -169,13 +178,55 @@ fun MainScreen(
} }
} }
events.firstOrNull()?.let { events.firstOrNull()?.let {
it.Display(sheetState = eventBottomSheetState) { when (val event = it) {
is ToConfirmBet -> {
Timber.d("ToConfirmBet")
event.Display(sheetState = eventBottomSheetState) {
mainViewModel.dismissedEvents += it
scope.launch {
eventBottomSheetState.hide()
delay(EVENT_DISMISS_DELAY_MS)
events.removeFirstOrNull()
}
}
}
is WonBet -> {
Timber.d("WonBet")
event.Display(sheetState = eventBottomSheetState) {
mainViewModel.dismissedEvents += it
scope.launch {
eventBottomSheetState.hide()
delay(EVENT_DISMISS_DELAY_MS)
events.removeFirstOrNull()
}
}
}
is DailyReward -> {
var dailyRewardVisible by remember { mutableStateOf(true) }
AnimatedVisibility(
visible = dailyRewardVisible,
enter = fadeIn(),
exit = fadeOut()
) {
(events.firstOrNull() as? DailyReward)?.let {
it.Display(
onDismiss = {
dailyRewardVisible = false
mainViewModel.dismissedEvents += it mainViewModel.dismissedEvents += it
scope.launch {
delay(EVENT_DISMISS_DELAY_MS)
events.removeFirstOrNull() events.removeFirstOrNull()
} }
} }
)
}
}
}
}
}
BetStatusBottomSheet( BetStatusBottomSheet(
state = statusBottomSheetState, state = statusBottomSheetState,
@ -191,6 +242,7 @@ fun MainScreen(
participateSheetVisibility = participateSheetVisibility, participateSheetVisibility = participateSheetVisibility,
setParticipateSheetVisibility = setParticipateSheetVisibility setParticipateSheetVisibility = setParticipateSheetVisibility
) )
AllInLoading(visible = loading) AllInLoading(visible = loading)
} }

@ -14,6 +14,7 @@ import fr.iut.alldev.allin.data.repository.UserRepository
import fr.iut.alldev.allin.keystore.AllInKeystoreManager import fr.iut.alldev.allin.keystore.AllInKeystoreManager
import fr.iut.alldev.allin.ui.core.snackbar.SnackbarType import fr.iut.alldev.allin.ui.core.snackbar.SnackbarType
import fr.iut.alldev.allin.ui.main.event.AllInEvent import fr.iut.alldev.allin.ui.main.event.AllInEvent
import fr.iut.alldev.allin.ui.main.event.DailyReward
import fr.iut.alldev.allin.ui.main.event.ToConfirmBet import fr.iut.alldev.allin.ui.main.event.ToConfirmBet
import fr.iut.alldev.allin.ui.main.event.WonBet import fr.iut.alldev.allin.ui.main.event.WonBet
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -52,6 +53,8 @@ class MainViewModel @Inject constructor(
val token = keystoreManager.getTokenOrEmpty() val token = keystoreManager.getTokenOrEmpty()
events.addAll( events.addAll(
buildList { buildList {
add(DailyReward(125))
addAll(betRepository.getToConfirm(token).map { bet -> addAll(betRepository.getToConfirm(token).map { bet ->
ToConfirmBet( ToConfirmBet(
betDetail = bet, betDetail = bet,

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

@ -0,0 +1,15 @@
package fr.iut.alldev.allin.ui.main.event
import androidx.compose.runtime.Composable
import fr.iut.alldev.allin.ui.dailyReward.DailyRewardScreen
data class DailyReward(private val amount: Int) : AllInEvent() {
@Composable
fun Display(onDismiss: () -> Unit) {
DailyRewardScreen(
amount = amount,
onDismiss = onDismiss
)
}
}

@ -10,7 +10,7 @@ data class ToConfirmBet(
private val onConfirm: (String) -> Unit private val onConfirm: (String) -> Unit
) : AllInEvent() { ) : AllInEvent() {
@Composable @Composable
override fun Display( fun Display(
sheetState: SheetState, sheetState: SheetState,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {

@ -11,7 +11,7 @@ data class WonBet(
private val betResult: BetResultDetail, private val betResult: BetResultDetail,
) : AllInEvent() { ) : AllInEvent() {
@Composable @Composable
override fun Display( fun Display(
sheetState: SheetState, sheetState: SheetState,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

@ -143,4 +143,9 @@
<!--Ranking--> <!--Ranking-->
<string name="ranking_title">Classement</string> <string name="ranking_title">Classement</string>
<!--Daily reward-->
<string name="daily_reward_title">Récompense quotidienne</string>
<string name="daily_reward_subtitle">Votre récompense quotidienne est débloquée tous les jours à 00:00 UTC et vous permets dobtenir entre 10 et 150 Allcoins.</string>
</resources> </resources>

@ -143,4 +143,8 @@
<!--Ranking--> <!--Ranking-->
<string name="ranking_title">Ranking</string> <string name="ranking_title">Ranking</string>
<!--Daily reward-->
<string name="daily_reward_title">Daily reward</string>
<string name="daily_reward_subtitle">Your daily reward is unlocked every day at 00:00 UTC and allows you to get between 10 and 150 Allcoins.</string>
</resources> </resources>

@ -336,7 +336,7 @@ class MockAllInApi : AllInApi {
response = listOf("The Monarchs", "Climate Change"), response = listOf("The Monarchs", "Climate Change"),
createdBy = "User 1", createdBy = "User 1",
type = BetType.MATCH, type = BetType.MATCH,
status = BetStatus.IN_PROGRESS, status = BetStatus.CLOSING,
) )
) )

Loading…
Cancel
Save