Private bets and profile pictures with coil
continuous-integration/drone/push Build is passing Details

pull/5/head
avalin 11 months ago
parent 3adc0e381b
commit c53f9e8b91

@ -128,6 +128,9 @@ dependencies {
// Squircle
implementation(libs.smoothCornerRect)
// Coil
implementation(libs.coil.compose)
// Tests
testImplementation(libs.test.junit)
androidTestImplementation(libs.test.junit)

@ -75,7 +75,7 @@ fun BetScreenCard(
verticalAlignment = Alignment.CenterVertically
) {
if (players.isNotEmpty()) {
BetProfilePictureRow(pictures = players.map { it.username to null })
BetProfilePictureRow(pictures = players.map { it.username to it.image })
Spacer(modifier = Modifier.width(12.dp))
}
Text(

@ -36,7 +36,7 @@ fun BetCreationScreen(
var phrase by remember { viewModel.phrase }
val (registerDate, setRegisterDate) = remember { viewModel.registerDate }
val (betDate, setBetDate) = remember { viewModel.betDate }
var isPublic by remember { viewModel.isPublic }
var isPrivate by remember { viewModel.isPrivate }
var selectedBetType by remember { viewModel.selectedBetType }
val themeError by remember { viewModel.themeError }
@ -47,7 +47,7 @@ fun BetCreationScreen(
val friends by viewModel.friends.collectAsStateWithLifecycle()
val selectedFriends = remember { mutableListOf<String>() }
val selectedFriends by viewModel.selectedFriends.collectAsStateWithLifecycle()
var selectionElements by remember { mutableStateOf(listOf<SelectionElement>()) }
var selectedBetTypeElement by remember { mutableStateOf<SelectionElement?>(null) }
@ -81,15 +81,15 @@ fun BetCreationScreen(
betPhrase = phrase,
betPhraseError = phraseError.errorResource(),
setBetPhrase = { phrase = it },
isPublic = isPublic,
setIsPublic = { isPublic = it },
isPrivate = isPrivate,
setIsPrivate = { isPrivate = it },
registerDate = registerDate,
registerDateError = registerDateError.errorResource(),
betDate = betDate,
betDateError = betDateError.errorResource(),
typeError = typeError.errorResource(),
friends = friends,
selectedFriends = selectedFriends,
selectedFriends = selectedFriends.toList(),
setRegisterDateDialog = setRegisterDatePicker,
setEndDateDialog = setEndDatePicker,
setRegisterTimeDialog = setRegisterTimePicker,
@ -110,7 +110,8 @@ fun BetCreationScreen(
onCreation()
}
)
}
},
toggleFriend = { viewModel.toggleFriend(it) }
)
if (showRegisterDatePicker || showEndDatePicker) {

@ -4,13 +4,12 @@ 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.api.model.RequestBet
import fr.iut.alldev.allin.data.model.FriendStatus
import fr.iut.alldev.allin.data.model.User
import fr.iut.alldev.allin.data.model.bet.BetStatus
import fr.iut.alldev.allin.data.model.bet.BetType
import fr.iut.alldev.allin.data.model.bet.BinaryBet
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.repository.BetRepository
import fr.iut.alldev.allin.data.repository.FriendRepository
import fr.iut.alldev.allin.data.repository.UserRepository
@ -36,7 +35,7 @@ class BetCreationViewModel @Inject constructor(
var phrase = mutableStateOf("")
val registerDate = mutableStateOf(ZonedDateTime.now())
val betDate = mutableStateOf(ZonedDateTime.now())
var isPublic = mutableStateOf(true)
var isPrivate = mutableStateOf(false)
var selectedBetType = mutableStateOf<BetTypeState>(BetTypeState.Binary)
val themeError = mutableStateOf<FieldErrorState>(FieldErrorState.NoError)
@ -48,6 +47,9 @@ class BetCreationViewModel @Inject constructor(
private val _friends by lazy { MutableStateFlow<List<User>>(emptyList()) }
val friends get() = _friends.asStateFlow()
private val _selectedFriends by lazy { MutableStateFlow<Set<String>>(emptySet()) }
val selectedFriends get() = _selectedFriends.asStateFlow()
init {
viewModelScope.launch {
_friends.emit(
@ -102,7 +104,7 @@ class BetCreationViewModel @Inject constructor(
when (val state = selectedBetType.value) {
BetTypeState.Binary -> Unit
is BetTypeState.Custom -> if (state.possibleAnswers.size < 2) {
is BetTypeState.Custom -> if (state.answers.size < 2) {
typeError.value = FieldErrorState.NoResponse
hasError.value = true
}
@ -133,58 +135,18 @@ class BetCreationViewModel @Inject constructor(
if (!hasError.value) {
try {
userRepository.currentUserState.value?.let { currentUser ->
val bet =
userRepository.currentUserState.value?.let { _ ->
when (val type = selectedBetType.value) {
BetTypeState.Binary -> {
BinaryBet(
id = "",
val bet = RequestBet(
theme = theme.value,
creator = currentUser.username,
phrase = phrase.value,
endRegisterDate = registerDate.value,
endBetDate = betDate.value,
isPublic = isPublic.value,
betStatus = BetStatus.WAITING,
totalStakes = 0,
totalParticipants = 0
type = selectedBetType.value.type,
sentenceBet = phrase.value,
endRegistration = registerDate.value,
endBet = betDate.value,
isPrivate = isPrivate.value,
response = selectedBetType.value.getPossibleAnswers(),
userInvited = selectedFriends.value.toList()
)
}
is BetTypeState.Match -> {
MatchBet(
id = "",
theme = theme.value,
creator = currentUser.username,
phrase = phrase.value,
endRegisterDate = registerDate.value,
endBetDate = betDate.value,
isPublic = isPublic.value,
betStatus = BetStatus.WAITING,
totalStakes = 0,
totalParticipants = 0,
nameTeam1 = type.team1,
nameTeam2 = type.team2
)
}
is BetTypeState.Custom -> {
CustomBet(
id = "",
theme = theme.value,
creator = currentUser.username,
phrase = phrase.value,
endRegisterDate = registerDate.value,
endBetDate = betDate.value,
isPublic = isPublic.value,
betStatus = BetStatus.WAITING,
totalStakes = 0,
totalParticipants = 0,
possibleAnswers = type.possibleAnswers
)
}
}
betRepository.createBet(bet, keystoreManager.getTokenOrEmpty())
onSuccess()
@ -202,7 +164,7 @@ class BetCreationViewModel @Inject constructor(
viewModelScope.launch {
selectedBetType.value.let {
if (it is BetTypeState.Custom) {
selectedBetType.value = BetTypeState.Custom(possibleAnswers = it.possibleAnswers + value)
selectedBetType.value = BetTypeState.Custom(answers = it.answers + value)
}
}
}
@ -212,16 +174,40 @@ class BetCreationViewModel @Inject constructor(
viewModelScope.launch {
selectedBetType.value.let {
if (it is BetTypeState.Custom) {
selectedBetType.value = BetTypeState.Custom(possibleAnswers = it.possibleAnswers - value)
selectedBetType.value = BetTypeState.Custom(answers = it.answers - value)
}
}
}
}
fun toggleFriend(value: String) {
viewModelScope.launch {
_selectedFriends.value.let { itSelectedFriends ->
if (itSelectedFriends.contains(value)) {
_selectedFriends.emit(itSelectedFriends - value)
} else {
_selectedFriends.emit(itSelectedFriends + value)
}
}
}
}
sealed class BetTypeState(val type: BetType) {
data object Binary : BetTypeState(type = BetType.BINARY)
data class Match(val team1: String, val team2: String) : BetTypeState(type = BetType.MATCH)
data class Custom(val possibleAnswers: List<String>) : BetTypeState(type = BetType.CUSTOM)
data object Binary : BetTypeState(type = BetType.BINARY) {
override fun getPossibleAnswers(): List<String> = listOf(YES_VALUE, NO_VALUE)
}
data class Match(val team1: String, val team2: String) : BetTypeState(type = BetType.MATCH) {
override fun getPossibleAnswers(): List<String> = listOf(team1, team2)
}
data class Custom(val answers: List<String>) : BetTypeState(type = BetType.CUSTOM) {
override fun getPossibleAnswers(): List<String> = answers
}
abstract fun getPossibleAnswers(): List<String>
companion object {
fun BetType.typeState() =

@ -36,14 +36,14 @@ fun BetCreationScreenContent(
betPhrase: String,
betPhraseError: String?,
setBetPhrase: (String) -> Unit,
isPublic: Boolean,
setIsPublic: (Boolean) -> Unit,
isPrivate: Boolean,
setIsPrivate: (Boolean) -> Unit,
registerDate: ZonedDateTime,
registerDateError: String?,
betDate: ZonedDateTime,
betDateError: String?,
friends: List<User>,
selectedFriends: MutableList<String>,
selectedFriends: List<String>,
setRegisterDateDialog: (Boolean) -> Unit,
setEndDateDialog: (Boolean) -> Unit,
setRegisterTimeDialog: (Boolean) -> Unit,
@ -55,7 +55,8 @@ fun BetCreationScreenContent(
selectionBetType: List<SelectionElement>,
addAnswer: (String) -> Unit,
deleteAnswer: (String) -> Unit,
onCreateBet: () -> Unit
onCreateBet: () -> Unit,
toggleFriend: (String) -> Unit
) {
val interactionSource = remember { MutableInteractionSource() }
val focus = LocalFocusManager.current
@ -67,8 +68,8 @@ fun BetCreationScreenContent(
sections = listOf(
SectionElement(stringResource(id = R.string.bet_creation_question)) {
BetCreationScreenQuestionTab(
isPublic = isPublic,
setIsPublic = setIsPublic,
isPrivate = isPrivate,
setIsPrivate = setIsPrivate,
betPhrase = betPhrase,
setBetPhrase = setBetPhrase,
betTheme = betTheme,
@ -85,7 +86,8 @@ fun BetCreationScreenContent(
betThemeError = betThemeError,
betPhraseError = betPhraseError,
registerDateError = registerDateError,
betDateError = betDateError
betDateError = betDateError,
toggleFriend = toggleFriend
)
},
SectionElement(stringResource(id = R.string.bet_creation_answer)) {
@ -118,7 +120,8 @@ fun BetCreationScreenContent(
.padding(bottom = 14.dp)
.padding(horizontal = 20.dp)
.safeContentPadding(),
onClick = onCreateBet
onClick = onCreateBet,
enabled = !isPrivate || selectedFriends.isNotEmpty()
)
}
}
@ -137,8 +140,8 @@ private fun BetCreationScreenContentPreview() {
typeError = null,
betPhraseError = null,
setBetPhrase = { },
isPublic = false,
setIsPublic = { },
isPrivate = false,
setIsPrivate = { },
registerDate = ZonedDateTime.now(),
registerDateError = null,
betDate = ZonedDateTime.now(),
@ -154,7 +157,8 @@ private fun BetCreationScreenContentPreview() {
selectionBetType = listOf(),
onCreateBet = { },
addAnswer = { },
deleteAnswer = { }
deleteAnswer = { },
toggleFriend = { }
)
}
}

@ -25,6 +25,7 @@ import fr.iut.alldev.allin.ui.core.ProfilePicture
@Composable
fun BetCreationScreenFriendLine(
username: String,
image: String?,
allCoinsAmount: Int,
isSelected: Boolean,
onClick: () -> Unit,
@ -46,6 +47,7 @@ fun BetCreationScreenFriendLine(
modifier = Modifier.padding(end = 7.dp)
)
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
size = 25.dp
)
@ -72,6 +74,7 @@ private fun BetCreationScreenFriendLinePreview() {
AllInTheme {
BetCreationScreenFriendLine(
username = "David",
image = null,
allCoinsAmount = 542,
isSelected = false
) {
@ -87,6 +90,7 @@ private fun BetCreationScreenFriendLineSelectedPreview() {
AllInTheme {
BetCreationScreenFriendLine(
username = "David",
image = null,
allCoinsAmount = 542,
isSelected = true
) {

@ -88,14 +88,14 @@ fun BetCreationScreenAnswerTab(
value = currentAnswer,
setValue = setCurrentAnswer,
onAdd = { addAnswer(currentAnswer) },
enabled = selectedBetType.possibleAnswers.size < BET_MAX_ANSWERS,
buttonEnabled = currentAnswer.isNotBlank() && (currentAnswer !in selectedBetType.possibleAnswers),
enabled = selectedBetType.answers.size < BET_MAX_ANSWERS,
buttonEnabled = currentAnswer.isNotBlank() && (currentAnswer !in selectedBetType.answers),
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(
id = R.string.bet_creation_max_answers,
BET_MAX_ANSWERS - selectedBetType.possibleAnswers.size
BET_MAX_ANSWERS - selectedBetType.answers.size
),
color = AllInTheme.colors.onMainSurface,
style = AllInTheme.typography.sm1,
@ -107,7 +107,7 @@ fun BetCreationScreenAnswerTab(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
selectedBetType.possibleAnswers.fastForEach {
selectedBetType.answers.fastForEach {
BetCreationScreenCustomAnswer(
text = it,
onDelete = { deleteAnswer(it) }

@ -28,17 +28,18 @@ fun BetCreationScreenQuestionTab(
betPhrase: String,
betPhraseError: String?,
setBetPhrase: (String) -> Unit,
isPublic: Boolean,
setIsPublic: (Boolean) -> Unit,
isPrivate: Boolean,
setIsPrivate: (Boolean) -> Unit,
registerDate: ZonedDateTime,
registerDateError: String?,
betDate: ZonedDateTime,
betDateError: String?,
selectedFriends: MutableList<String>,
selectedFriends: List<String>,
setRegisterDateDialog: (Boolean) -> Unit,
setEndDateDialog: (Boolean) -> Unit,
setRegisterTimeDialog: (Boolean) -> Unit,
setEndTimeDialog: (Boolean) -> Unit,
toggleFriend: (String) -> Unit,
interactionSource: MutableInteractionSource
) {
LazyColumn(
@ -74,11 +75,13 @@ fun BetCreationScreenQuestionTab(
}
item {
QuestionTabPrivacySection(
isPublic = isPublic,
setIsPublic = setIsPublic,
isPrivate = isPrivate,
setIsPrivate = setIsPrivate,
friends = friends,
selectedFriends = selectedFriends,
toggleFriend = toggleFriend,
interactionSource = interactionSource
)
}
}
@ -96,8 +99,8 @@ private fun BetCreationScreenQuestionTabPreview() {
betPhrase = "Trinh",
betPhraseError = null,
setBetPhrase = { },
isPublic = true,
setIsPublic = { },
isPrivate = true,
setIsPrivate = { },
registerDate = ZonedDateTime.now(),
registerDateError = null,
betDate = ZonedDateTime.now(),
@ -107,6 +110,7 @@ private fun BetCreationScreenQuestionTabPreview() {
setEndDateDialog = { },
setRegisterTimeDialog = { },
setEndTimeDialog = { },
toggleFriend = { },
interactionSource = remember { MutableInteractionSource() }
)
}

@ -39,11 +39,12 @@ import fr.iut.alldev.allin.ui.core.bet.AllInEmptyView
@Composable
fun QuestionTabPrivacySection(
isPublic: Boolean,
setIsPublic: (Boolean) -> Unit,
isPrivate: Boolean,
setIsPrivate: (Boolean) -> Unit,
friends: List<User>,
selectedFriends: MutableList<String>,
selectedFriends: List<String>,
interactionSource: MutableInteractionSource,
toggleFriend: (String) -> Unit
) {
AllInTitleInfo(
text = stringResource(id = R.string.bet_creation_bet_privacy),
@ -59,37 +60,23 @@ fun QuestionTabPrivacySection(
AllInIconChip(
text = stringResource(id = R.string.bet_public),
leadingIcon = Icons.Default.Public,
onClick = {
setIsPublic(true)
},
isSelected = isPublic
onClick = { setIsPrivate(false) },
isSelected = !isPrivate
)
AllInIconChip(
text = stringResource(id = R.string.bet_private),
leadingIcon = Icons.Default.Lock,
onClick = {
setIsPublic(false)
},
isSelected = !isPublic
onClick = { setIsPrivate(true) },
isSelected = isPrivate
)
}
Column(
verticalArrangement = Arrangement.spacedBy(17.dp)
) {
var isOpen by remember {
mutableStateOf(false)
}
var isOpen by remember { mutableStateOf(false) }
if (isPublic) {
Column(
modifier = Modifier.padding(vertical = 20.dp),
verticalArrangement = Arrangement.spacedBy(17.dp)
) {
BetCreationScreenBottomText(text = stringResource(id = R.string.bet_creation_public_bottom_text_1))
BetCreationScreenBottomText(text = stringResource(id = R.string.bet_creation_public_bottom_text_2))
}
} else {
if (isPrivate) {
AllInRetractableCard(
text = pluralStringResource(
id = R.plurals.bet_creation_friends_available_format,
@ -118,13 +105,10 @@ fun QuestionTabPrivacySection(
BetCreationScreenFriendLine(
username = it.username,
allCoinsAmount = it.coins,
image = it.image,
isSelected = isSelected
) {
if (isSelected) {
selectedFriends.remove(it.id)
} else {
selectedFriends.add(it.id)
}
toggleFriend(it.id)
isSelected = !isSelected
}
}
@ -151,6 +135,14 @@ fun QuestionTabPrivacySection(
BetCreationScreenBottomText(text = stringResource(id = R.string.bet_creation_private_bottom_text_2))
BetCreationScreenBottomText(text = stringResource(id = R.string.bet_creation_private_bottom_text_3))
}
} else {
Column(
modifier = Modifier.padding(vertical = 20.dp),
verticalArrangement = Arrangement.spacedBy(17.dp)
) {
BetCreationScreenBottomText(text = stringResource(id = R.string.bet_creation_public_bottom_text_1))
BetCreationScreenBottomText(text = stringResource(id = R.string.bet_creation_public_bottom_text_2))
}
}
}
}

@ -153,7 +153,8 @@ class BetStatusBottomSheetBetDisplayer(
item {
BetStatusParticipant(
username = it.username,
allCoinsAmount = it.stake
allCoinsAmount = it.stake,
image = null // TODO : Image
)
HorizontalDivider(
color = AllInTheme.colors.border,
@ -165,7 +166,8 @@ class BetStatusBottomSheetBetDisplayer(
if (it.username != betDetail.userParticipation?.username) {
BetStatusParticipant(
username = it.username,
allCoinsAmount = it.stake
allCoinsAmount = it.stake,
image = null // TODO : Image
)
Spacer(modifier = Modifier.height(8.dp))
}
@ -374,6 +376,7 @@ class BetStatusBottomSheetBetDisplayer(
@Composable
fun BetStatusParticipant(
username: String,
image: String?,
allCoinsAmount: Int
) {
Row(
@ -382,6 +385,7 @@ fun BetStatusParticipant(
verticalAlignment = Alignment.CenterVertically
) {
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
size = 25.dp
)

@ -1,38 +1,46 @@
package fr.iut.alldev.allin.ui.core
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
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.clip
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
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 fr.iut.alldev.allin.R
import coil.compose.AsyncImage
import coil.request.ImageRequest
import fr.iut.alldev.allin.theme.AllInColorToken
import fr.iut.alldev.allin.theme.AllInTheme
@Composable
fun ProfilePicture(
fallback: String,
image: String?,
modifier: Modifier = Modifier,
image: Painter? = null,
borderWidth: Dp? = null,
size: Dp = 80.dp,
size: Dp = 80.dp
) {
val shape = RoundedCornerShape(100)
var hasImageloaded by remember { mutableStateOf(false) }
Card(
modifier = modifier.size(size),
shape = shape,
@ -41,14 +49,31 @@ fun ProfilePicture(
) {
Box(Modifier.fillMaxSize()) {
image?.let {
Image(
painter = it,
contentDescription = null,
AsyncImage(
modifier = Modifier
.align(Alignment.Center)
.fillMaxSize()
.clip(shape)
.width(300.dp)
.height(174.dp)
.clip(RoundedCornerShape(14.dp)),
model = ImageRequest.Builder(LocalContext.current)
.data(image)
.crossfade(true)
.build(),
contentDescription = null,
onSuccess = { hasImageloaded = true },
contentScale = ContentScale.Crop
)
if (!hasImageloaded) {
Text(
text = fallback,
style = AllInTheme.typography.p2,
textAlign = TextAlign.Center,
fontSize = with(LocalDensity.current) { (size / 2).toSp() },
color = AllInColorToken.white,
modifier = Modifier.align(Alignment.Center)
)
}
} ?: run {
Text(
text = fallback,
@ -56,9 +81,7 @@ fun ProfilePicture(
textAlign = TextAlign.Center,
fontSize = with(LocalDensity.current) { (size / 2).toSp() },
color = AllInColorToken.white,
modifier = Modifier
.align(Alignment.Center)
.clip(shape)
modifier = Modifier.align(Alignment.Center)
)
}
}
@ -70,7 +93,7 @@ fun ProfilePicture(
@Composable
private fun ProfilePictureDefaultPreview() {
AllInTheme {
ProfilePicture("LS")
ProfilePicture(image = null, fallback = "LS")
}
}
@ -80,7 +103,7 @@ private fun ProfilePicturePreview() {
AllInTheme {
ProfilePicture(
fallback = "LS",
image = painterResource(id = R.drawable.money_with_wings)
image = "https://cdn.myanimelist.net/s/common/userimages/6076ae8b-54ed-4924-bb81-4d2d51806b1a_225w?s=965262aa50355e917a7ef9579c58fffc"
)
}
}

@ -8,29 +8,26 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.ext.asFallbackProfileUsername
import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.core.ProfilePicture
@Composable
fun BetProfilePictureRow(
pictures: List<Pair<String, Painter?>>,
pictures: List<Pair<String, String?>>,
modifier: Modifier = Modifier,
maxLength: Int = 5
) {
val nRepeat = remember{ pictures.size.coerceAtMost(maxLength) }
Box(modifier.width((35 + (nRepeat - 1) * 17).dp)){
pictures.take(nRepeat).forEachIndexed { index, (username, painter) ->
pictures.take(nRepeat).forEachIndexed { index, (username, image) ->
ProfilePicture(
fallback = username.asFallbackProfileUsername(),
image = painter,
image = image,
size = 35.dp,
modifier = Modifier
.align(Alignment.CenterEnd)
@ -65,11 +62,10 @@ private fun BetProfilePictureRowMaxPreview() {
) {
BetProfilePictureRow(
pictures = listOf(
"lucas" to painterResource(id = R.drawable.money_with_wings),
"lucas" to null,
"lucas" to painterResource(id = R.drawable.money_with_wings),
"lucas" to null,
"lucas" to painterResource(id = R.drawable.money_with_wings),
"lucas" to null,
"lucas" to null,
"lucas" to null
)
)

@ -24,6 +24,7 @@ import fr.iut.alldev.allin.ui.core.ProfilePicture
@Composable
fun FriendsScreenLine(
username: String,
image: String?,
status: FriendStatus,
toggleIsFriend: () -> Unit,
modifier: Modifier = Modifier
@ -34,6 +35,7 @@ fun FriendsScreenLine(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
size = 50.dp
)
@ -83,6 +85,7 @@ fun FriendsScreenLine(
private fun FriendsScreenLinePreview() {
AllInTheme {
FriendsScreenLine(
image = null,
username = "Random",
status = FriendStatus.NOT_FRIEND,
toggleIsFriend = { }
@ -96,6 +99,7 @@ private fun FriendsScreenLinePreview() {
private fun FriendsScreenLineRequestedPreview() {
AllInTheme {
FriendsScreenLine(
image = null,
username = "Random",
status = FriendStatus.REQUESTED,
toggleIsFriend = { }
@ -109,6 +113,7 @@ private fun FriendsScreenLineRequestedPreview() {
private fun FriendsScreenLineIsFriendPreview() {
AllInTheme {
FriendsScreenLine(
image = null,
username = "Random",
status = FriendStatus.FRIEND,
toggleIsFriend = { }

@ -27,6 +27,7 @@ import fr.iut.alldev.allin.ui.core.ProfilePicture
@Composable
fun FriendsScreenRequestLine(
username: String,
image: String?,
accept: () -> Unit,
decline: () -> Unit,
modifier: Modifier = Modifier
@ -37,6 +38,7 @@ fun FriendsScreenRequestLine(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
size = 50.dp
)
@ -78,6 +80,7 @@ fun FriendsScreenRequestLine(
private fun FriendsScreenLinePreview() {
AllInTheme {
FriendsScreenRequestLine(
image = null,
username = "Xx_Bg_du_63",
accept = { },
decline = { }

@ -64,6 +64,7 @@ fun FriendsScreenAddTab(
items(friends) {
FriendsScreenLine(
username = it.username,
image = it.image,
status = it.friendStatus ?: FriendStatus.NOT_FRIEND,
toggleIsFriend = { onToggleDeleteFriend(it) }
)

@ -36,6 +36,7 @@ fun FriendsScreenRequestsTab(
items(requests) {
FriendsScreenRequestLine(
username = it.username,
image = it.image,
accept = { acceptRequest(it) },
decline = { declineRequest(it) }
)

@ -128,6 +128,7 @@ fun MainScreen(
nbFriends = currentUser?.nbFriends ?: 0,
nbBets = currentUser?.nbBets ?: 0,
bestWin = currentUser?.bestWin ?: 0,
image = currentUser?.image,
navigateTo = { route ->
mainViewModel.fetchEvents()
navController.popUpTo(route, startDestination)

@ -39,6 +39,7 @@ fun AllInDrawer(
nbBets: Int,
bestWin: Int,
nbFriends: Int,
image: String?,
navigateTo: (String) -> Unit,
logout: () -> Unit,
content: @Composable () -> Unit
@ -55,6 +56,7 @@ fun AllInDrawer(
bestWin = bestWin,
nbFriends = nbFriends,
username = username,
image = image,
modifier = Modifier.padding(top = 39.dp, bottom = 26.dp)
)
destinations.forEach { item ->

@ -28,6 +28,7 @@ fun DrawerHeader(
bestWin: Int,
nbFriends: Int,
username: String,
image: String?,
modifier: Modifier = Modifier,
) {
Column(
@ -35,6 +36,7 @@ fun DrawerHeader(
horizontalAlignment = Alignment.CenterHorizontally
) {
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
borderWidth = 1.dp
)
@ -69,7 +71,8 @@ private fun DrawerHeaderPreview() {
nbBets = 114,
bestWin = 360,
nbFriends = 5,
username = "Pseudo"
username = "Pseudo",
image = null
)
}
}

@ -17,6 +17,7 @@ fun ProfileScreen(
when (val s = state) {
is ProfileViewModel.State.Loaded -> {
ProfileScreenHeader(
image = null,
username = s.user.username,
totalBets = 333,
bestWin = 365,

@ -21,6 +21,7 @@ import fr.iut.alldev.allin.ui.core.ProfilePicture
@Composable
fun ProfileScreenHeader(
username: String,
image: String?,
totalBets: Int,
bestWin: Int,
friends: Int
@ -30,6 +31,7 @@ fun ProfileScreenHeader(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
size = 68.dp
)
@ -97,6 +99,7 @@ private fun ProfileScreenHeaderPreview() {
AllInTheme {
ProfileScreenHeader(
username = "User 1",
image = null,
totalBets = 12,
bestWin = 365,
friends = 5

@ -56,6 +56,7 @@ fun RankingScreenContent(
RankingScreenFirst(
username = first.username,
coins = first.coins,
image = first.image,
modifier = Modifier.weight(1f)
)
}
@ -64,6 +65,7 @@ fun RankingScreenContent(
RankingScreenSecond(
username = second.username,
coins = second.coins,
image = second.image,
modifier = Modifier.weight(1f)
)
}
@ -75,6 +77,7 @@ fun RankingScreenContent(
RankingScreenItem(
position = idx + 3,
username = user.username,
image = user.image,
coins = user.coins
)
}

@ -33,6 +33,7 @@ import racra.compose.smooth_corner_rect_library.AbsoluteSmoothCornerShape
@Composable
fun RankingScreenFirst(
username: String,
image: String?,
coins: Int,
modifier: Modifier = Modifier
) {
@ -88,6 +89,7 @@ fun RankingScreenFirst(
}
}
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
size = 70.dp,
modifier = Modifier
@ -123,6 +125,7 @@ private fun RankingScreenFirstPreview() {
AllInTheme {
RankingScreenFirst(
username = "Username",
image = null,
coins = 420
)
}

@ -26,6 +26,7 @@ import fr.iut.alldev.allin.ui.core.ProfilePicture
fun RankingScreenItem(
position: Int,
username: String,
image: String?,
coins: Int,
modifier: Modifier = Modifier
) {
@ -50,6 +51,7 @@ fun RankingScreenItem(
)
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
size = 38.dp
)
@ -80,6 +82,7 @@ fun RankingScreenItem(
private fun RankingScreenItemPreview() {
AllInTheme {
RankingScreenItem(
image = null,
position = 3,
username = "Username",
coins = 420
@ -93,6 +96,7 @@ private fun RankingScreenItemPreview() {
private fun RankingScreenItemTenthPreview() {
AllInTheme {
RankingScreenItem(
image = null,
position = 10,
username = "Username",
coins = 420

@ -33,6 +33,7 @@ import racra.compose.smooth_corner_rect_library.AbsoluteSmoothCornerShape
@Composable
fun RankingScreenSecond(
username: String,
image: String?,
coins: Int,
modifier: Modifier = Modifier
) {
@ -88,6 +89,7 @@ fun RankingScreenSecond(
}
}
ProfilePicture(
image = image,
fallback = username.asFallbackProfileUsername(),
size = 52.dp,
modifier = Modifier
@ -123,6 +125,7 @@ private fun RankingScreenSecondPreview() {
AllInTheme {
RankingScreenSecond(
username = "Username",
image = null,
coins = 420
)
}

@ -95,9 +95,10 @@ data class RequestBet(
val type: BetType,
val sentenceBet: String,
@Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime,
@Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime,
var isPrivate: Boolean,
var response: List<String>
@Serializable(ZonedDateTimeSerializer::class) val endBet: ZonedDateTime,
val isPrivate: Boolean,
val response: List<String>,
val userInvited: List<String>
)
@Keep

@ -24,7 +24,8 @@ data class ResponseUser(
var nbBets: Int,
var nbFriends: Int,
var bestWin: Int,
val friendStatus: FriendStatus? = null
val friendStatus: FriendStatus? = null,
val image: String? = null
) {
fun toUser() = User(
id = id,
@ -34,7 +35,8 @@ data class ResponseUser(
friendStatus = friendStatus,
nbBets = nbBets,
nbFriends = nbFriends,
bestWin = bestWin
bestWin = bestWin,
image = image
)
}

@ -8,5 +8,6 @@ data class User(
var nbBets: Int,
var nbFriends: Int,
var bestWin: Int,
val friendStatus: FriendStatus? = null
val friendStatus: FriendStatus? = null,
val image: String? = null
)

@ -1,6 +1,5 @@
package fr.iut.alldev.allin.data.model.bet
import fr.iut.alldev.allin.data.api.model.RequestBet
import java.time.ZonedDateTime
sealed class Bet(
@ -17,16 +16,4 @@ sealed class Bet(
) {
abstract fun getBetType(): BetType
abstract fun getResponses(): List<String>
fun toRequestBet(): RequestBet {
return RequestBet(
id = id,
theme = theme,
sentenceBet = phrase,
endRegistration = endRegisterDate,
endBet = endBetDate,
isPrivate = !isPublic,
response = getResponses(),
type = getBetType()
)
}
}

@ -1,5 +1,6 @@
package fr.iut.alldev.allin.data.repository
import fr.iut.alldev.allin.data.api.model.RequestBet
import fr.iut.alldev.allin.data.model.bet.Bet
import fr.iut.alldev.allin.data.model.bet.BetFilter
import fr.iut.alldev.allin.data.model.bet.BetResultDetail
@ -7,7 +8,7 @@ import fr.iut.alldev.allin.data.model.bet.Participation
import fr.iut.alldev.allin.data.model.bet.vo.BetDetail
abstract class BetRepository {
abstract suspend fun createBet(bet: Bet, token: String)
abstract suspend fun createBet(bet: RequestBet, token: String)
abstract suspend fun getHistory(token: String): List<BetResultDetail>
abstract suspend fun getCurrentBets(token: String): List<BetDetail>
abstract suspend fun getBet(id: String, token: String): BetDetail

@ -3,6 +3,7 @@ package fr.iut.alldev.allin.data.repository.impl
import fr.iut.alldev.allin.data.api.AllInApi
import fr.iut.alldev.allin.data.api.AllInApi.Companion.asRequestBody
import fr.iut.alldev.allin.data.api.AllInApi.Companion.formatBearerToken
import fr.iut.alldev.allin.data.api.model.RequestBet
import fr.iut.alldev.allin.data.api.model.RequestBetFilters
import fr.iut.alldev.allin.data.model.bet.Bet
import fr.iut.alldev.allin.data.model.bet.BetFilter
@ -15,10 +16,10 @@ import javax.inject.Inject
class BetRepositoryImpl @Inject constructor(
private val api: AllInApi
) : BetRepository() {
override suspend fun createBet(bet: Bet, token: String) {
override suspend fun createBet(bet: RequestBet, token: String) {
api.createBet(
token = token.formatBearerToken(),
body = bet.toRequestBet()
body = bet
)
}

@ -30,6 +30,8 @@ espressoCore = "3.5.1"
room = "2.6.1"
okHttp = "4.11.0"
coil = "2.4.0"
# Plugins
gradlePlugin = "8.1.4"
publishPlugin = "1.1"
@ -93,6 +95,9 @@ kotlinSerialization-retrofit = { group = "com.jakewharton.retrofit", name = "ret
# Squicle
smoothCornerRect = { module = "com.github.racra:smooth-corner-rect-android-compose", version = "v1.0.0" }
#Coil
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
# Plugins
plugin-gradle = { module = "com.android.tools.build:gradle", version.ref = "gradlePlugin" }
plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }

Loading…
Cancel
Save