Refactor and start fixing edge to edge

pull/5/head
avalin 11 months ago
parent b40788676f
commit b6c6f2c005

@ -17,6 +17,7 @@
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustPan"
android:theme="@style/Theme.Allin">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

@ -2,6 +2,7 @@ package fr.iut.alldev.allin
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
import racra.compose.smooth_corner_rect_library.BuildConfig
import timber.log.Timber
@HiltAndroidApp

@ -5,6 +5,7 @@ import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
@ -18,25 +19,11 @@ import fr.iut.alldev.allin.theme.AllInTheme
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
setContent {
AllInTheme{
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
with((view.context as Activity)) {
window.statusBarColor = Color.Transparent.toArgb()
window.navigationBarColor = Color.Transparent.toArgb()
if (Build.VERSION.SDK_INT > 30) {
window.insetsController?.hide(WindowInsetsCompat.Type.statusBars())
window.insetsController?.hide(WindowInsetsCompat.Type.navigationBars())
WindowCompat.setDecorFitsSystemWindows(window, false)
}
}
}
}
AllInNavHost()
}
}

@ -8,11 +8,14 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
@ -28,6 +31,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
@ -46,18 +50,16 @@ fun BetScreen(
viewModel: BetViewModel = hiltViewModel(),
selectBet: (Bet, Boolean) -> Unit,
) {
val haptic = LocalHapticFeedback.current
val bets by viewModel.bets.collectAsState()
val horizontalPadding = 23.dp
val refreshing by viewModel.isRefreshing.collectAsState()
val pullRefreshState = rememberPullRefreshState(refreshing, { viewModel.refresh() })
val progressAnimation by animateFloatAsState(pullRefreshState.progress * 15, label = "")
LazyColumn(
Modifier
modifier = Modifier
.pullRefresh(pullRefreshState)
.padding(top = with(LocalDensity.current) {
progressAnimation.toDp()
@ -97,7 +99,7 @@ fun BetScreen(
horizontalArrangement = Arrangement.spacedBy(9.dp)
) {
item {
Spacer(modifier = Modifier.width(horizontalPadding))
Spacer(modifier = Modifier.width(23.dp))
}
items(items) {
var isSelected by remember { mutableStateOf(false) }
@ -109,11 +111,11 @@ fun BetScreen(
})
}
item {
Spacer(modifier = Modifier.width(horizontalPadding))
Spacer(modifier = Modifier.width(23.dp))
}
}
}
items(bets) {
itemsIndexed(bets) { idx, it ->
BetScreenCard(
creator = it.creator,
category = it.theme,
@ -123,9 +125,15 @@ fun BetScreen(
players = List(3) { null },
onClickParticipate = { selectBet(it, true) },
onClickCard = { selectBet(it, false) },
modifier = Modifier.padding(horizontal = horizontalPadding)
modifier = Modifier.padding(horizontal = 23.dp)
)
Spacer(modifier = Modifier.height(24.dp))
if (idx != bets.lastIndex) {
Spacer(modifier = Modifier.height(24.dp))
}
}
item {
Spacer(modifier = Modifier.navigationBarsPadding())
}
}
}

@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@ -271,6 +272,7 @@ fun BetConfirmationBottomSheetContent(
Box(
modifier = Modifier
.fillMaxSize()
.safeContentPadding()
.padding(16.dp)
) {
IconButton(

@ -1,35 +1,22 @@
package fr.iut.alldev.allin.ui.betCreation
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.data.model.bet.BetType
import fr.iut.alldev.allin.ext.getIcon
import fr.iut.alldev.allin.ext.getTitleId
import fr.iut.alldev.allin.ui.betCreation.tabs.BetCreationScreenAnswerTab
import fr.iut.alldev.allin.ui.betCreation.tabs.BetCreationScreenQuestionTab
import fr.iut.alldev.allin.ui.betCreation.components.BetCreationScreenContent
import fr.iut.alldev.allin.ui.core.AllInAlertDialog
import fr.iut.alldev.allin.ui.core.AllInDatePicker
import fr.iut.alldev.allin.ui.core.AllInSections
import fr.iut.alldev.allin.ui.core.AllInTimePicker
import fr.iut.alldev.allin.ui.core.RainbowButton
import fr.iut.alldev.allin.ui.core.SectionElement
import fr.iut.alldev.allin.ui.core.SelectionElement
import java.time.Instant
import java.time.ZoneId
@ -41,8 +28,7 @@ fun BetCreationScreen(
setLoading: (Boolean) -> Unit,
onCreation: () -> Unit
) {
val interactionSource = remember { MutableInteractionSource() }
val betTypes = remember { BetType.values().toList() }
val betTypes = remember { BetType.entries }
var hasError by remember { mutableStateOf(false) }
var theme by remember { viewModel.theme }
@ -60,7 +46,6 @@ fun BetCreationScreen(
val selectedFriends = remember { mutableListOf<Int>() }
var selectionElements by remember { mutableStateOf(listOf<SelectionElement>()) }
var selectedBetTypeElement by remember { mutableStateOf<SelectionElement?>(null) }
val focus = LocalFocusManager.current
val themeFieldName = stringResource(id = R.string.Theme)
val phraseFieldName = stringResource(id = R.string.Bet_Phrase)
@ -85,80 +70,42 @@ fun BetCreationScreen(
val (showRegisterTimePicker, setRegisterTimePicker) = remember { mutableStateOf(false) }
val (showEndTimePicker, setEndTimePicker) = remember { mutableStateOf(false) }
Box(
Modifier
.fillMaxSize()
.padding(top = 20.dp)
) {
AllInSections(
onLoadSection = {
focus.clearFocus()
},
modifier = Modifier
.align(Alignment.TopCenter)
.fillMaxSize()
.padding(bottom = 90.dp),
sections = listOf(
SectionElement(stringResource(id = R.string.Question)) {
BetCreationScreenQuestionTab(
isPublic = isPublic,
setIsPublic = { isPublic = it },
betPhrase = phrase,
setBetPhrase = { phrase = it },
betTheme = theme,
setBetTheme = { theme = it },
nbFriends = 42,
selectedFriends = selectedFriends,
registerDate = registerDate,
betDate = betDate,
setRegisterDateDialog = { setRegisterDatePicker(it) },
setEndDateDialog = { setEndDatePicker(it) },
setRegisterTimeDialog = { setRegisterTimePicker(it) },
setEndTimeDialog = { setEndTimePicker(it) },
interactionSource = interactionSource,
betThemeError = themeError.errorResource(),
betPhraseError = phraseError.errorResource(),
registerDateError = registerDateError.errorResource(),
betDateError = betDateError.errorResource(),
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 12.dp, horizontal = 20.dp)
)
},
SectionElement(stringResource(id = R.string.Answer)) {
BetCreationScreenAnswerTab(
selectedBetType = selectedBetType,
selected = selectedBetTypeElement,
setSelected = { selectedBetTypeElement = it },
elements = selectionElements,
modifier = Modifier
.fillMaxSize()
.padding(vertical = 12.dp, horizontal = 20.dp)
)
BetCreationScreenContent(
nbFriends = 42,
betTheme = theme,
betThemeError = themeError.errorResource(),
setBetTheme = { theme = it },
betPhrase = phrase,
betPhraseError = phraseError.errorResource(),
setBetPhrase = { phrase = it },
isPublic = isPublic,
setIsPublic = { isPublic = it },
registerDate = registerDate,
registerDateError = registerDateError.errorResource(),
betDate = betDate,
betDateError = betDateError.errorResource(),
selectedFriends = selectedFriends,
setRegisterDateDialog = setRegisterDatePicker,
setEndDateDialog = setEndDatePicker,
setRegisterTimeDialog = setRegisterTimePicker,
setEndTimeDialog = setEndTimePicker,
selectedBetTypeElement = selectedBetTypeElement,
selectedBetType = selectedBetType,
setSelectedBetTypeElement = { selectedBetTypeElement = it },
selectionBetType = selectionElements,
onCreateBet = {
viewModel.createBet(
themeFieldName = themeFieldName,
phraseFieldName = phraseFieldName,
setLoading = setLoading,
onError = { hasError = true },
onSuccess = {
onCreation()
}
)
)
}
)
RainbowButton(
text = stringResource(id = R.string.Publish),
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 14.dp)
.padding(horizontal = 20.dp),
onClick = {
viewModel.createBet(
themeFieldName = themeFieldName,
phraseFieldName = phraseFieldName,
setLoading = setLoading,
onError = { hasError = true },
onSuccess = {
onCreation()
}
)
}
)
}
if (showRegisterDatePicker || showEndDatePicker) {
val dateToEdit = if (showRegisterDatePicker) registerDate else betDate
AllInDatePicker(

@ -0,0 +1,150 @@
package fr.iut.alldev.allin.ui.betCreation.components
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
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.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
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.model.bet.BetType
import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.betCreation.tabs.BetCreationScreenAnswerTab
import fr.iut.alldev.allin.ui.betCreation.tabs.BetCreationScreenQuestionTab
import fr.iut.alldev.allin.ui.core.AllInSections
import fr.iut.alldev.allin.ui.core.RainbowButton
import fr.iut.alldev.allin.ui.core.SectionElement
import fr.iut.alldev.allin.ui.core.SelectionElement
import java.time.ZonedDateTime
@Composable
fun BetCreationScreenContent(
nbFriends: Int,
betTheme: String,
betThemeError: String?,
setBetTheme: (String) -> Unit,
betPhrase: String,
betPhraseError: String?,
setBetPhrase: (String) -> Unit,
isPublic: Boolean,
setIsPublic: (Boolean) -> Unit,
registerDate: ZonedDateTime,
registerDateError: String?,
betDate: ZonedDateTime,
betDateError: String?,
selectedFriends: MutableList<Int>,
setRegisterDateDialog: (Boolean) -> Unit,
setEndDateDialog: (Boolean) -> Unit,
setRegisterTimeDialog: (Boolean) -> Unit,
setEndTimeDialog: (Boolean) -> Unit,
selectedBetTypeElement: SelectionElement?,
selectedBetType: BetType,
setSelectedBetTypeElement: (SelectionElement) -> Unit,
selectionBetType: List<SelectionElement>,
onCreateBet: () -> Unit
) {
val interactionSource = remember { MutableInteractionSource() }
val focus = LocalFocusManager.current
Box(Modifier.fillMaxSize()) {
AllInSections(
onLoadSection = { focus.clearFocus() },
modifier = Modifier.align(Alignment.TopCenter),
sections = listOf(
SectionElement(stringResource(id = R.string.Question)) {
BetCreationScreenQuestionTab(
isPublic = isPublic,
setIsPublic = setIsPublic,
betPhrase = betPhrase,
setBetPhrase = setBetPhrase,
betTheme = betTheme,
setBetTheme = setBetTheme,
nbFriends = nbFriends,
selectedFriends = selectedFriends,
registerDate = registerDate,
betDate = betDate,
setRegisterDateDialog = setRegisterDateDialog,
setEndDateDialog = setEndDateDialog,
setRegisterTimeDialog = setRegisterTimeDialog,
setEndTimeDialog = setEndTimeDialog,
interactionSource = interactionSource,
betThemeError = betThemeError,
betPhraseError = betPhraseError,
registerDateError = registerDateError,
betDateError = betDateError
)
},
SectionElement(stringResource(id = R.string.Answer)) {
BetCreationScreenAnswerTab(
selectedBetType = selectedBetType,
selected = selectedBetTypeElement,
setSelected = setSelectedBetTypeElement,
elements = selectionBetType
)
}
)
)
Box(
modifier = Modifier
.align(Alignment.BottomCenter)
.background(
Brush.verticalGradient(
0f to Color.Transparent,
0.50f to AllInTheme.themeColors.mainSurface
)
),
) {
RainbowButton(
text = stringResource(id = R.string.Publish),
modifier = Modifier
.padding(bottom = 14.dp)
.padding(horizontal = 20.dp)
.safeContentPadding(),
onClick = onCreateBet
)
}
}
}
@Preview
@Composable
private fun BetCreationScreenContentPreview() {
AllInTheme {
BetCreationScreenContent(
nbFriends = 8900,
betTheme = "Ina",
betThemeError = null,
setBetTheme = { },
betPhrase = "Bryon",
betPhraseError = null,
setBetPhrase = { },
isPublic = false,
setIsPublic = { },
registerDate = ZonedDateTime.now(),
registerDateError = null,
betDate = ZonedDateTime.now(),
betDateError = null,
selectedFriends = mutableListOf(),
setRegisterDateDialog = { },
setEndDateDialog = { },
setRegisterTimeDialog = { },
setEndTimeDialog = { },
selectedBetTypeElement = null,
selectedBetType = BetType.BINARY,
setSelectedBetTypeElement = { },
selectionBetType = listOf(),
onCreateBet = { }
)
}
}

@ -12,10 +12,12 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.model.bet.BetType
import fr.iut.alldev.allin.ext.getTitleId
import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.betCreation.components.BetCreationScreenBottomText
import fr.iut.alldev.allin.ui.core.AllInSelectionBox
import fr.iut.alldev.allin.ui.core.SelectionElement
@ -26,7 +28,7 @@ fun BetCreationScreenAnswerTab(
selected: SelectionElement?,
selectedBetType: BetType,
setSelected: (SelectionElement) -> Unit,
elements: List<SelectionElement>,
elements: List<SelectionElement>
) {
var isOpen by remember {
mutableStateOf(false)
@ -67,3 +69,16 @@ fun BetCreationScreenAnswerTab(
}
}
}
@Preview
@Composable
private fun BetCreationScreenAnswerTabPreview() {
AllInTheme {
BetCreationScreenAnswerTab(
selected = null,
selectedBetType = BetType.BINARY,
setSelected = { },
elements = listOf()
)
}
}

@ -1,14 +1,19 @@
package fr.iut.alldev.allin.ui.betCreation.tabs
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import fr.iut.alldev.allin.data.ext.formatToMediumDate
import fr.iut.alldev.allin.data.ext.formatToTime
import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.betCreation.tabs.sections.QuestionTabDateTimeSection
import fr.iut.alldev.allin.ui.betCreation.tabs.sections.QuestionTabPrivacySection
import fr.iut.alldev.allin.ui.betCreation.tabs.sections.QuestionTabThemePhraseSection
@ -37,7 +42,7 @@ fun BetCreationScreenQuestionTab(
setEndTimeDialog: (Boolean) -> Unit,
interactionSource: MutableInteractionSource
) {
Column(modifier) {
Column(modifier = modifier) {
QuestionTabThemePhraseSection(
betTheme = betTheme,
betThemeError = betThemeError,
@ -69,5 +74,34 @@ fun BetCreationScreenQuestionTab(
selectedFriends = selectedFriends,
interactionSource = interactionSource
)
Spacer(modifier = Modifier.height(120.dp))
}
}
@Preview
@Composable
private fun BetCreationScreenQuestionTabPreview() {
AllInTheme {
BetCreationScreenQuestionTab(
nbFriends = 4651,
betTheme = "Elly",
betThemeError = null,
setBetTheme = { },
betPhrase = "Trinh",
betPhraseError = null,
setBetPhrase = { },
isPublic = true,
setIsPublic = { },
registerDate = ZonedDateTime.now(),
registerDateError = null,
betDate = ZonedDateTime.now(),
betDateError = null,
selectedFriends = mutableListOf(),
setRegisterDateDialog = { },
setEndDateDialog = { },
setRegisterTimeDialog = { },
setEndTimeDialog = { },
interactionSource = remember { MutableInteractionSource() }
)
}
}

@ -2,8 +2,11 @@ package fr.iut.alldev.allin.ui.betHistory.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
@ -56,5 +59,9 @@ fun <T> GenericHistory(
won = getWon(it)
)
}
item {
Spacer(modifier = Modifier.navigationBarsPadding())
}
}
}

@ -37,7 +37,6 @@ fun BetStatusBottomSheet(
sheetVisibility: Boolean,
sheetBackVisibility: Boolean,
betDetail: BetDetail?,
paddingValues: PaddingValues,
userCoinAmount: MutableIntState,
onParticipate: (stake: Int, response: String) -> Unit,
onDismiss: () -> Unit,
@ -82,7 +81,6 @@ fun BetStatusBottomSheet(
sheetVisibility = participateSheetVisibility &&
betDetail.bet.betStatus == BetStatus.IN_PROGRESS &&
state.hasExpandedState,
safeBottomPadding = paddingValues.calculateBottomPadding(),
odds = betDetail.answers.getOrNull(selectedAnswer)?.odds ?: 1f,
betPhrase = betDetail.bet.phrase,
coinAmount = userCoinAmount.intValue,

@ -30,7 +30,6 @@ import kotlin.math.roundToInt
@Composable
fun BetStatusParticipationBottomSheet(
sheetVisibility: Boolean,
safeBottomPadding: Dp,
betPhrase: String,
coinAmount: Int,
onDismiss: () -> Unit,
@ -52,7 +51,6 @@ fun BetStatusParticipationBottomSheet(
containerColor = AllInTheme.themeColors.background2
) {
BetStatusParticipationBottomSheetContent(
safeBottomPadding = safeBottomPadding,
betPhrase = betPhrase,
coinAmount = coinAmount,
elements = elements,
@ -73,8 +71,7 @@ fun BetStatusParticipationBottomSheet(
}
@Composable
private fun ColumnScope.BetStatusParticipationBottomSheetContent(
safeBottomPadding: Dp,
private fun BetStatusParticipationBottomSheetContent(
betPhrase: String,
coinAmount: Int,
enabled: Boolean,
@ -139,8 +136,7 @@ private fun ColumnScope.BetStatusParticipationBottomSheetContent(
Column(
modifier = Modifier
.background(AllInTheme.themeColors.background)
.padding(horizontal = 7.dp)
.padding(bottom = safeBottomPadding, top = 7.dp),
.padding(7.dp),
verticalArrangement = Arrangement.spacedBy(7.dp)
) {
Row(
@ -164,7 +160,8 @@ private fun ColumnScope.BetStatusParticipationBottomSheetContent(
text = stringResource(id = R.string.Participate),
textColor = AllInTheme.colors.white,
radius = 5.dp,
onClick = onButtonClick
onClick = onButtonClick,
modifier = Modifier.navigationBarsPadding()
)
}
}
@ -176,7 +173,6 @@ private fun BetStatusParticipationBottomSheetContentPreview() {
AllInTheme {
Column {
BetStatusParticipationBottomSheetContent(
safeBottomPadding = 0.dp,
betPhrase = "Bet phrase",
coinAmount = 3620,
onButtonClick = {},

@ -5,6 +5,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@ -36,7 +37,9 @@ fun BinaryStatBar(
style = AllInTheme.typography.h1,
fontStyle = FontStyle.Italic,
fontSize = 30.sp,
color = AllInTheme.colors.allInBarPink
color = AllInTheme.colors.allInBarPink,
textAlign = TextAlign.End,
modifier = Modifier.weight(1f)
)
}
StatBar(percentage = response1Percentage)

@ -12,7 +12,9 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
@ -21,14 +23,14 @@ 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.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.stringResource
@ -67,8 +69,6 @@ import java.util.Locale
class BetStatusBottomSheetBetDisplayer(
val openParticipateSheet: () -> Unit
) : BetDisplayer {
val paddingValues = mutableStateOf(PaddingValues())
@Composable
private fun DisplayBinaryBet(
betDetail: BetDetail,
@ -77,15 +77,13 @@ class BetStatusBottomSheetBetDisplayer(
response1Display: String = response1,
response2Display: String = response2
) {
val safeBottomPadding = paddingValues.value.calculateBottomPadding()
val configuration = LocalConfiguration.current
val locale =
remember { ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault() }
val locale = remember { ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault() }
val response1Answer = remember { betDetail.getAnswerOfResponse(response1) }
val response2Answer = remember { betDetail.getAnswerOfResponse(response2) }
Box(Modifier.padding(bottom = safeBottomPadding)) {
Box(Modifier.navigationBarsPadding()) {
Column {
Column(Modifier.padding(horizontal = 20.dp)) {
BetTitleHeader(
@ -125,79 +123,82 @@ class BetStatusBottomSheetBetDisplayer(
} else {
HorizontalDivider(color = AllInTheme.themeColors.border)
}
Column(
Modifier
LazyColumn(
modifier = Modifier
.fillMaxHeight()
.background(AllInTheme.themeColors.background2)
.padding(horizontal = 20.dp)
.background(AllInTheme.themeColors.background2),
contentPadding = PaddingValues(horizontal = 20.dp)
) {
Spacer(modifier = Modifier.height(20.dp))
BinaryStatBar(
response1Percentage = remember {
val total = (response1Answer?.totalParticipants
?: 0) + (response2Answer?.totalParticipants ?: 0)
if (total == 0) .5f else (response1Answer?.totalParticipants
?: 0) / total.toFloat()
},
response1 = response1Display,
response2 = response2Display
)
AllInDetailsDrawer {
YesNoDetailsLine(
icon = AllInTheme.icons.allCoins(),
yesText = response1Answer?.totalStakes?.toString() ?: "0",
noText = response2Answer?.totalStakes?.toString() ?: "0"
item {
Spacer(modifier = Modifier.height(20.dp))
BinaryStatBar(
response1Percentage = remember {
val total = (response1Answer?.totalParticipants
?: 0) + (response2Answer?.totalParticipants ?: 0)
if (total == 0) .5f else (response1Answer?.totalParticipants
?: 0) / total.toFloat()
},
response1 = response1Display,
response2 = response2Display
)
YesNoDetailsLine(
icon = rememberVectorPainter(image = Icons.Filled.People),
yesText = response1Answer?.totalParticipants?.toString() ?: "0",
noText = response2Answer?.totalParticipants?.toString() ?: "0"
)
YesNoDetailsLine(
icon = rememberVectorPainter(image = Icons.Filled.WorkspacePremium),
yesText = response1Answer?.highestStake?.toString() ?: "0",
noText = response2Answer?.highestStake?.toString() ?: "0"
)
YesNoDetailsLine(
icon = rememberVectorPainter(image = Icons.Filled.EmojiEvents),
yesText = "x${response1Answer?.odds?.formatToSimple(locale) ?: "1.00"}",
noText = "x${response2Answer?.odds?.formatToSimple(locale) ?: "1.00"}"
AllInDetailsDrawer {
YesNoDetailsLine(
icon = AllInTheme.icons.allCoins(),
yesText = response1Answer?.totalStakes?.toString() ?: "0",
noText = response2Answer?.totalStakes?.toString() ?: "0"
)
YesNoDetailsLine(
icon = rememberVectorPainter(image = Icons.Filled.People),
yesText = response1Answer?.totalParticipants?.toString() ?: "0",
noText = response2Answer?.totalParticipants?.toString() ?: "0"
)
YesNoDetailsLine(
icon = rememberVectorPainter(image = Icons.Filled.WorkspacePremium),
yesText = response1Answer?.highestStake?.toString() ?: "0",
noText = response2Answer?.highestStake?.toString() ?: "0"
)
YesNoDetailsLine(
icon = rememberVectorPainter(image = Icons.Filled.EmojiEvents),
yesText = "x${response1Answer?.odds?.formatToSimple(locale) ?: "1.00"}",
noText = "x${response2Answer?.odds?.formatToSimple(locale) ?: "1.00"}"
)
}
Text(
text = stringResource(id = R.string.bet_status_participants_list),
fontSize = 20.sp,
color = AllInTheme.themeColors.onMainSurface,
style = AllInTheme.typography.h1,
modifier = Modifier.padding(vertical = 36.dp)
)
}
Text(
text = stringResource(id = R.string.bet_status_participants_list),
fontSize = 20.sp,
color = AllInTheme.themeColors.onMainSurface,
style = AllInTheme.typography.h1,
modifier = Modifier.padding(vertical = 36.dp)
)
LazyColumn(
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalAlignment = Alignment.CenterHorizontally,
contentPadding = PaddingValues(horizontal = 13.dp, vertical = 8.dp),
modifier = Modifier.fillMaxHeight()
) {
betDetail.userParticipation?.let {
item {
BetStatusParticipant(
username = it.username,
allCoinsAmount = it.stake
)
HorizontalDivider(
color = AllInTheme.themeColors.border,
modifier = Modifier.padding(vertical = 8.dp, horizontal = 25.dp)
)
}
betDetail.userParticipation?.let {
item {
BetStatusParticipant(
username = it.username,
allCoinsAmount = it.stake
)
HorizontalDivider(
color = AllInTheme.themeColors.border,
modifier = Modifier.padding(vertical = 8.dp, horizontal = 25.dp)
)
}
}
items(betDetail.participations) {
if (it.username != betDetail.userParticipation?.username) {
BetStatusParticipant(
username = it.username,
allCoinsAmount = it.stake
)
Spacer(modifier = Modifier.height(8.dp))
}
items(betDetail.participations) {
if (it.username != betDetail.userParticipation?.username) {
BetStatusParticipant(
username = it.username,
allCoinsAmount = it.stake
)
}
}
item {
if (betDetail.bet.betStatus != BetStatus.FINISHED && betDetail.userParticipation == null) {
Spacer(modifier = Modifier.height(48.dp))
}
Spacer(modifier = Modifier.navigationBarsPadding())
}
}
}
@ -205,7 +206,14 @@ class BetStatusBottomSheetBetDisplayer(
RainbowButton(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(horizontal = 7.dp),
.background(
Brush.verticalGradient(
.2f to Color.Transparent,
.5f to AllInTheme.themeColors.background2
)
)
.padding(7.dp)
.navigationBarsPadding(),
text = stringResource(id = R.string.Participate),
enabled = betDetail.bet.betStatus == BetStatus.IN_PROGRESS,
onClick = openParticipateSheet
@ -214,7 +222,6 @@ class BetStatusBottomSheetBetDisplayer(
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
override fun DisplayYesNoBet(betDetail: BetDetail) {
DisplayBinaryBet(

@ -35,7 +35,7 @@ fun AllInBottomSheet(
WindowInsets(
left = it.getLeft(localDensity, localLayoutDirection),
right = it.getRight(localDensity, localLayoutDirection),
top = it.getTop(localDensity),
top = 0,
bottom = 0,
)
},

@ -20,6 +20,8 @@ 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.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import fr.iut.alldev.allin.theme.AllInTheme
@ -98,6 +100,7 @@ fun AllInBouncyCard(
borderBrush: Brush? = null,
content: @Composable () -> Unit,
) {
val haptic = LocalHapticFeedback.current
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
@ -106,14 +109,17 @@ fun AllInBouncyCard(
animationSpec = spring(
Spring.DampingRatioHighBouncy,
Spring.StiffnessMediumLow
)
), label = ""
)
AllInCard(
modifier = modifier
.combinedClickable(
interactionSource = interactionSource,
indication = null,
onClick = { onClick?.let { it() } }
onClick = { onClick?.let { it() } },
onLongClick = {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}
)
.scale(scale),
onClick = null,

@ -2,16 +2,35 @@ package fr.iut.alldev.allin.ui.core
import android.content.res.Configuration
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@ -20,47 +39,65 @@ import kotlinx.coroutines.launch
class SectionElement(
val text: String,
val content: @Composable ()->Unit
val content: @Composable () -> Unit
)
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AllInSections(
sections: List<SectionElement>,
interSectionsPadding: Dp = 56.dp,
modifier: Modifier = Modifier,
onLoadSection: ()->Unit = {}
interSectionsPadding: Dp = 56.dp,
onLoadSection: ()->Unit = { }
) {
val pagerState = rememberPagerState(pageCount = {
sections.size
})
val pagerState = rememberPagerState(pageCount = { sections.size })
val scope = rememberCoroutineScope()
Column(
LazyColumn(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally
){
LazyRow(
horizontalArrangement = Arrangement.spacedBy(interSectionsPadding)
stickyHeader {
Box(
modifier = Modifier
.fillMaxWidth()
.background(
Brush.verticalGradient(
0.75f to AllInTheme.themeColors.mainSurface,
1f to Color.Transparent
)
),
contentAlignment = Alignment.Center
) {
itemsIndexed(sections) { index, section ->
AllInSectionButton(
text = section.text,
isSelected = index == pagerState.currentPage,
onClick = {
scope.launch {
pagerState.animateScrollToPage(index)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(interSectionsPadding),
modifier = Modifier.padding(vertical = 12.dp)
) {
itemsIndexed(sections) { index, section ->
AllInSectionButton(
text = section.text,
isSelected = index == pagerState.currentPage,
onClick = {
scope.launch {
pagerState.animateScrollToPage(index)
}
}
}
)
)
}
}
}
}
HorizontalPager(state = pagerState) { page ->
LaunchedEffect(key1 = page){
onLoadSection()
item {
HorizontalPager(
state = pagerState
) { page ->
LaunchedEffect(key1 = page) { onLoadSection() }
Column(
modifier = Modifier.padding(horizontal = 20.dp)
) {
sections[page].content()
}
}
sections[page].content()
}
}
}

@ -16,9 +16,9 @@ import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.SwipeToDismissBox
import androidx.compose.material3.SwipeToDismissValue
import androidx.compose.material3.SwipeToDismissBoxValue
import androidx.compose.material3.Text
import androidx.compose.material3.rememberSwipeToDismissState
import androidx.compose.material3.rememberSwipeToDismissBoxState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@ -40,9 +40,9 @@ fun AllInSnackbar(
SnackbarHost(
hostState = snackbarState
) { snackbarData ->
val dismissState = rememberSwipeToDismissState(
val dismissState = rememberSwipeToDismissBoxState(
confirmValueChange = { value ->
if (value != SwipeToDismissValue.Settled) {
if (value != SwipeToDismissBoxValue.Settled) {
snackbarState.currentSnackbarData?.dismiss()
true
} else {

@ -2,12 +2,18 @@ package fr.iut.alldev.allin.ui.core.topbar
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -23,45 +29,52 @@ fun AllInTopBar(
onMenuClicked: () -> Unit,
coinAmount: Int,
) {
Box(
modifier = Modifier
.height(86.dp)
.fillMaxWidth()
.background(brush = AllInTheme.colors.allInMainGradient)
) {
IconButton(
onClick = onMenuClicked,
modifier = Modifier
.padding(start = 19.dp)
.align(Alignment.CenterStart)
) {
Icon(
painterResource(id = R.drawable.allin_menu),
modifier = Modifier.size(30.dp),
contentDescription = null,
tint = Color.White
)
TopAppBar(
modifier = Modifier.background(AllInTheme.colors.allInMainGradient),
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent
),
title = { },
navigationIcon = {
IconButton(
onClick = onMenuClicked,
modifier = Modifier
) {
Icon(
painterResource(id = R.drawable.allin_menu),
modifier = Modifier.size(30.dp),
contentDescription = null,
tint = Color.White
)
}
},
actions = {
Box(
modifier = Modifier.fillMaxWidth()
) {
Icon(
painter = painterResource(R.drawable.allin),
contentDescription = null,
tint = AllInTheme.colors.white,
modifier = Modifier
.size(40.dp)
.align(Alignment.Center)
)
AllInTopBarCoinCounter(
amount = coinAmount,
modifier = Modifier
.align(Alignment.CenterEnd)
.offset(x = 4.dp)
)
}
}
Icon(
painter = painterResource(R.drawable.allin),
contentDescription = null,
tint = AllInTheme.colors.white,
modifier = Modifier
.size(40.dp)
.align(Alignment.Center)
)
AllInTopBarCoinCounter(
amount = coinAmount,
modifier = Modifier
.align(Alignment.CenterEnd)
)
}
)
}
@Preview
@Composable
private fun AllInTopBarPreview() {
AllInTheme {
AllInTopBar(onMenuClicked = { }, coinAmount = 541)
AllInTopBar(onMenuClicked = { }, coinAmount = 541)
}
}

@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions
@ -27,6 +28,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@ -70,6 +72,7 @@ fun LoginScreen(
.fillMaxSize()
.background(AllInTheme.themeColors.mainSurface)
.padding(horizontal = 44.dp)
.safeContentPadding()
.verticalScroll(rememberScrollState())
) {
Column(
@ -108,6 +111,7 @@ fun LoginScreen(
placeholder = stringResource(id = R.string.password),
value = password,
modifier = Modifier.fillMaxWidth(),
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Done,
keyboardActions = keyboardActions,
onValueChange = setPassword

@ -131,9 +131,6 @@ fun MainScreen(
drawerState = drawerState,
snackbarHostState = snackbarHostState
) {
LaunchedEffect(key1 = it) {
betStatusDisplayer.paddingValues.value = it
}
Column(
modifier = Modifier
.padding(top = it.calculateTopPadding())
@ -176,7 +173,6 @@ fun MainScreen(
sheetBackVisibility = sheetBackVisibility.value,
onDismiss = { setStatusVisibility(false) },
betDetail = selectedBet,
paddingValues = betStatusDisplayer.paddingValues.value,
displayBet = { betStatusDisplayer.DisplayBet(it) },
userCoinAmount = mainViewModel.currentUserState.userCoins,
onParticipate = { stake, response -> mainViewModel.participateToBet(stake, response) },

@ -1,6 +1,7 @@
package fr.iut.alldev.allin.ui.main.components
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.offset
import androidx.compose.material3.DrawerState
import androidx.compose.material3.Scaffold
@ -9,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@ -28,22 +30,23 @@ fun AllInScaffold(
content: @Composable (PaddingValues) -> Unit,
) {
var drawerWidth by remember {
mutableStateOf(drawerState.currentOffset)
}
var drawerWidth by remember { mutableFloatStateOf(drawerState.currentOffset) }
LaunchedEffect(drawerState.currentOffset.isNaN()) {
drawerWidth = drawerState.currentOffset
}
val localDensity = LocalDensity.current
val contentOffset by derivedStateOf {
if (drawerWidth.isNaN() || drawerWidth == 0f) 0.dp
else with(localDensity) {
(abs(drawerWidth) + drawerState.currentOffset).toDp()
val contentOffset by remember {
derivedStateOf {
if (drawerWidth.isNaN() || drawerWidth == 0f) 0.dp
else with(localDensity) {
(abs(drawerWidth) + drawerState.currentOffset).toDp()
}
}
}
Scaffold(
contentWindowInsets = WindowInsets(0.dp),
modifier = Modifier.offset(x = contentOffset),
snackbarHost = {
AllInSnackbar(snackbarState = snackbarHostState)

@ -47,12 +47,12 @@ class BetDetailPreviewProvider : PreviewParameterProvider<BetDetail> {
stake = 150
)
),
userParticipation = Participation(
userParticipation = null /*Participation(
betId = it.id,
username = "MyUser",
response = NO_VALUE,
stake = 150
)
)*/
)
}
}

@ -2,6 +2,7 @@ package fr.iut.alldev.allin.ui.register
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.Text
@ -25,8 +26,8 @@ import fr.iut.alldev.allin.ui.core.AllInGradientButton
import fr.iut.alldev.allin.ui.core.AllInLoading
import fr.iut.alldev.allin.ui.core.AllInPasswordField
import fr.iut.alldev.allin.ui.core.AllInTextField
import fr.iut.alldev.allin.ui.register.components.RegisterScreenContent
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun RegisterScreen(
navigateToDashboard: () -> Unit,
@ -48,8 +49,6 @@ fun RegisterScreen(
val (password, setPassword) = remember { registerViewModel.password }
val (passwordValidation, setPasswordValidation) = remember { registerViewModel.passwordValidation }
val scrollState = rememberScrollState()
val usernameFieldName = stringResource(id = R.string.username)
val emailFieldName = stringResource(id = R.string.email)
val passwordFieldName = stringResource(id = R.string.password)
@ -71,128 +70,33 @@ fun RegisterScreen(
)
}
Column(
Modifier
.fillMaxSize()
.background(AllInTheme.themeColors.mainSurface)
.padding(horizontal = 44.dp)
) {
Column(
Modifier
.weight(1f)
.verticalScroll(scrollState),
verticalArrangement = Arrangement.Center
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.Hello_x, username),
color = AllInTheme.themeColors.onMainSurface,
style = AllInTheme.typography.sm1,
textAlign = TextAlign.Center,
fontSize = 40.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.Register_title),
color = AllInTheme.themeColors.onMainSurface,
style = AllInTheme.typography.sm1,
textAlign = TextAlign.Center,
fontSize = 40.sp
RegisterScreenContent(
navigateToLogin = navigateToLogin,
onRegister = {
registerViewModel.onRegister(
usernameFieldName,
emailFieldName,
passwordFieldName,
navigateToDashboard
)
Spacer(modifier = Modifier.height(23.dp))
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.Register_subtitle),
color = AllInTheme.themeColors.onMainSurface,
style = AllInTheme.typography.p1,
textAlign = TextAlign.Center,
fontSize = 23.sp
)
Spacer(modifier = Modifier.height(83.dp))
Column(
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
AllInTextField(
placeholder = usernameFieldName,
value = username,
modifier = Modifier.fillMaxWidth(),
maxChar = 20,
onValueChange = setUsername,
errorText = usernameError.errorResource(),
imeAction = ImeAction.Next,
keyboardActions = keyboardActions
)
AllInTextField(
placeholder = emailFieldName,
value = email,
modifier = Modifier.fillMaxWidth(),
onValueChange = setEmail,
errorText = emailError.errorResource(),
keyboardType = KeyboardType.Email,
imeAction = ImeAction.Next,
keyboardActions = keyboardActions
)
AllInPasswordField(
placeholder = passwordFieldName,
value = password,
modifier = Modifier.fillMaxWidth(),
imeAction = ImeAction.Next,
keyboardActions = keyboardActions,
errorText = passwordError.errorResource(),
onValueChange = setPassword
)
AllInPasswordField(
placeholder = stringResource(id = R.string.confirm_password),
value = passwordValidation,
modifier = Modifier.fillMaxWidth(),
imeAction = ImeAction.Done,
keyboardActions = keyboardActions,
errorText = passwordValidationError.errorResource(),
onValueChange = setPasswordValidation
)
}
}
Column(
Modifier
.padding(bottom = 32.dp)
) {
AllInGradientButton(
text = stringResource(id = R.string.Register),
onClick = {
registerViewModel.onRegister(
usernameFieldName,
emailFieldName,
passwordFieldName,
navigateToDashboard
)
}
)
Spacer(modifier = Modifier.height(30.dp))
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.already_have_account),
color = AllInTheme.themeColors.onMainSurface,
fontSize = 15.sp,
style = AllInTheme.typography.p1,
modifier = Modifier.padding(end = 5.dp)
)
ClickableText(
text = AnnotatedString(stringResource(id = R.string.Login)),
style = AllInTheme.typography.p1.copy(
color = AllInTheme.colors.allInPurple,
fontSize = 15.sp,
fontWeight = FontWeight.Bold
)
) {
navigateToLogin()
}
}
}
}
AllInLoading(visible = loading)
},
keyboardActions = keyboardActions,
loading = loading,
username = username,
usernameFieldName = usernameFieldName,
setUsername = setUsername,
usernameError = usernameError.errorResource(),
email = email,
emailFieldName = emailFieldName,
setEmail = setEmail,
emailError = emailError.errorResource(),
passwordFieldName = passwordFieldName,
password = password,
passwordError = passwordError.errorResource(),
setPassword = setPassword,
passwordValidation = passwordValidation,
passwordValidationError = passwordValidationError.errorResource(),
setPasswordValidation = setPasswordValidation
)
}

@ -0,0 +1,221 @@
package fr.iut.alldev.allin.ui.register.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions
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.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
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.AllInTheme
import fr.iut.alldev.allin.ui.core.AllInGradientButton
import fr.iut.alldev.allin.ui.core.AllInLoading
import fr.iut.alldev.allin.ui.core.AllInPasswordField
import fr.iut.alldev.allin.ui.core.AllInTextField
@Composable
fun RegisterScreenContent(
navigateToLogin: () -> Unit,
onRegister: () -> Unit,
keyboardActions: KeyboardActions,
loading: Boolean,
username: String,
usernameFieldName: String,
setUsername: (String) -> Unit,
usernameError: String?,
email: String,
emailFieldName: String,
setEmail: (String) -> Unit,
emailError: String?,
passwordFieldName: String,
password: String,
passwordError: String?,
setPassword: (String) -> Unit,
passwordValidation: String,
passwordValidationError: String?,
setPasswordValidation: (String) -> Unit
) {
Box(
Modifier
.fillMaxSize()
.background(AllInTheme.themeColors.mainSurface)
) {
LazyColumn(
verticalArrangement = Arrangement.Center,
contentPadding = PaddingValues(40.dp)
) {
item {
Text(
modifier = Modifier
.padding(top = 16.dp)
.fillMaxWidth(),
text = stringResource(id = R.string.Hello_x, username),
color = AllInTheme.themeColors.onMainSurface,
style = AllInTheme.typography.sm1,
textAlign = TextAlign.Center,
fontSize = 40.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.Register_title),
color = AllInTheme.themeColors.onMainSurface,
style = AllInTheme.typography.sm1,
textAlign = TextAlign.Center,
fontSize = 40.sp
)
Spacer(modifier = Modifier.height(23.dp))
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.Register_subtitle),
color = AllInTheme.themeColors.onMainSurface,
style = AllInTheme.typography.p1,
textAlign = TextAlign.Center,
fontSize = 23.sp
)
Spacer(modifier = Modifier.height(83.dp))
Column(
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
AllInTextField(
placeholder = usernameFieldName,
value = username,
modifier = Modifier.fillMaxWidth(),
maxChar = 20,
onValueChange = setUsername,
errorText = usernameError,
imeAction = ImeAction.Next,
keyboardActions = keyboardActions
)
AllInTextField(
placeholder = emailFieldName,
value = email,
modifier = Modifier.fillMaxWidth(),
onValueChange = setEmail,
errorText = emailError,
keyboardType = KeyboardType.Email,
imeAction = ImeAction.Next,
keyboardActions = keyboardActions
)
AllInPasswordField(
placeholder = passwordFieldName,
value = password,
modifier = Modifier.fillMaxWidth(),
imeAction = ImeAction.Next,
keyboardActions = keyboardActions,
keyboardType = KeyboardType.Password,
errorText = passwordError,
onValueChange = setPassword
)
AllInPasswordField(
placeholder = stringResource(id = R.string.confirm_password),
value = passwordValidation,
modifier = Modifier.fillMaxWidth(),
imeAction = ImeAction.Done,
keyboardActions = keyboardActions,
keyboardType = KeyboardType.Password,
errorText = passwordValidationError,
onValueChange = setPasswordValidation
)
}
Spacer(modifier = Modifier.height(120.dp))
Spacer(modifier = Modifier.navigationBarsPadding())
}
}
Column(
Modifier
.align(Alignment.BottomCenter)
.background(
Brush.verticalGradient(
.2f to Color.Transparent,
.5f to AllInTheme.themeColors.background
)
)
.padding(40.dp)
.navigationBarsPadding()
) {
AllInGradientButton(
text = stringResource(id = R.string.Register),
onClick = onRegister
)
Spacer(modifier = Modifier.height(30.dp))
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.already_have_account),
color = AllInTheme.themeColors.onMainSurface,
fontSize = 15.sp,
style = AllInTheme.typography.p1,
modifier = Modifier.padding(end = 5.dp)
)
ClickableText(
text = AnnotatedString(stringResource(id = R.string.Login)),
style = AllInTheme.typography.p1.copy(
color = AllInTheme.colors.allInPurple,
fontSize = 15.sp,
fontWeight = FontWeight.Bold
)
) {
navigateToLogin()
}
}
}
}
AllInLoading(visible = loading)
}
@Preview
@Composable
private fun RegisterScreenContentPreview() {
AllInTheme {
RegisterScreenContent(
navigateToLogin = { },
onRegister = { },
keyboardActions = KeyboardActions(),
loading = false,
username = "Lekesha",
usernameFieldName = "Justen",
setUsername = { },
usernameError = "Kaitlyn",
email = "Donnell",
emailFieldName = "Camron",
setEmail = { },
emailError = "Tunisia",
passwordFieldName = "Cagney",
password = "Neha",
passwordError = "December",
setPassword = { },
passwordValidation = "Xaviera",
passwordValidationError = "Keegan",
setPasswordValidation = { }
)
}
}

@ -33,6 +33,7 @@ import fr.iut.alldev.allin.R
import fr.iut.alldev.allin.theme.AllInTheme
import fr.iut.alldev.allin.ui.core.AllInButton
import fr.iut.alldev.allin.ui.core.AllInLoading
import fr.iut.alldev.allin.ui.welcome.components.WelcomeScreenContent
@Composable
fun WelcomeScreen(
@ -47,95 +48,9 @@ fun WelcomeScreen(
viewModel.tryAutoLogin(navigateToDashboard)
}
Box(
Modifier
.fillMaxWidth()
.fillMaxHeight(.5f)
.background(AllInTheme.colors.allInLoginGradient)
WelcomeScreenContent(
navigateToRegister = navigateToRegister,
navigateToLogin = navigateToLogin,
loading = loading
)
Box(
Modifier
.fillMaxSize()
.background(
Brush.verticalGradient(
.2f to Color.Transparent,
.5f to AllInTheme.themeColors.background
)
)
) {
Column(
Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.fillMaxHeight(.5f)
.padding(horizontal = 45.dp)
) {
Text(
text = stringResource(id = R.string.welcome_title),
color = AllInTheme.themeColors.onBackground,
fontSize = 30.sp,
style = AllInTheme.typography.h1
)
Text(
text = stringResource(id = R.string.welcome_appname),
fontSize = 60.sp,
style = AllInTheme.typography.h1.copy(
brush = AllInTheme.colors.allInMainGradient
)
)
Spacer(modifier = Modifier.height(43.dp))
Text(
text = stringResource(id = R.string.welcome_subtitle),
color = AllInTheme.themeColors.onBackground,
fontSize = 15.sp,
style = AllInTheme.typography.p1
)
Spacer(modifier = Modifier.height(78.dp))
AllInButton(
color = AllInTheme.themeColors.tint1,
text = stringResource(id = R.string.join),
textColor = AllInTheme.themeColors.background,
onClick = navigateToRegister,
modifier = Modifier.padding(bottom = 13.dp)
)
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.already_have_account),
color = AllInTheme.themeColors.tint1,
fontSize = 15.sp,
style = AllInTheme.typography.p1,
modifier = Modifier.padding(end = 5.dp)
)
ClickableText(
text = AnnotatedString(stringResource(id = R.string.Login)),
style = AllInTheme.typography.p1.copy(
color = AllInTheme.themeColors.tint1,
fontSize = 15.sp,
fontWeight = FontWeight.Bold
)
) {
navigateToLogin()
}
}
}
}
AllInLoading(visible = loading)
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun WelcomeScreenPreview() {
AllInTheme {
WelcomeScreen(
navigateToRegister = {},
navigateToLogin = {},
navigateToDashboard = {}
)
}
}

@ -0,0 +1,133 @@
package fr.iut.alldev.allin.ui.welcome.components
import android.content.res.Configuration
import androidx.compose.foundation.background
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.text.ClickableText
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.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
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.theme.AllInTheme
import fr.iut.alldev.allin.ui.core.AllInButton
import fr.iut.alldev.allin.ui.core.AllInLoading
@Composable
fun WelcomeScreenContent(
navigateToRegister: () -> Unit,
navigateToLogin: () -> Unit,
loading: Boolean
) {
Box(
Modifier
.fillMaxWidth()
.fillMaxHeight(.5f)
.background(AllInTheme.colors.allInLoginGradient)
)
Box(
Modifier
.fillMaxSize()
.background(
Brush.verticalGradient(
.2f to Color.Transparent,
.5f to AllInTheme.themeColors.background
)
)
) {
Column(
Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.padding(40.dp)
.navigationBarsPadding()
) {
Text(
text = stringResource(id = R.string.welcome_title),
color = AllInTheme.themeColors.onBackground,
fontSize = 30.sp,
style = AllInTheme.typography.h1
)
Text(
text = stringResource(id = R.string.welcome_appname),
fontSize = 60.sp,
style = AllInTheme.typography.h1.copy(
brush = AllInTheme.colors.allInMainGradient
)
)
Spacer(modifier = Modifier.height(43.dp))
Text(
text = stringResource(id = R.string.welcome_subtitle),
color = AllInTheme.themeColors.onBackground,
fontSize = 15.sp,
style = AllInTheme.typography.p1
)
Spacer(modifier = Modifier.height(78.dp))
AllInButton(
color = AllInTheme.themeColors.tint1,
text = stringResource(id = R.string.join),
textColor = AllInTheme.themeColors.background,
onClick = navigateToRegister,
modifier = Modifier.padding(bottom = 13.dp)
)
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.already_have_account),
color = AllInTheme.themeColors.tint1,
fontSize = 15.sp,
style = AllInTheme.typography.p1,
modifier = Modifier.padding(end = 5.dp)
)
ClickableText(
text = AnnotatedString(stringResource(id = R.string.Login)),
style = AllInTheme.typography.p1.copy(
color = AllInTheme.themeColors.tint1,
fontSize = 15.sp,
fontWeight = FontWeight.Bold
),
onClick = { navigateToLogin() }
)
}
}
}
AllInLoading(visible = loading)
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun WelcomeScreenContentPreview() {
AllInTheme {
WelcomeScreenContent(
navigateToRegister = { },
navigateToLogin = { },
loading = false
)
}
}

@ -208,13 +208,6 @@ private val mockUsers = mutableListOf(
)
private val mockParticipations = mutableListOf(
ResponseParticipation(
id = "",
betId = "UUID1",
username = mockUsers[0].first.username,
answer = YES_VALUE,
stake = 200
),
ResponseParticipation(
id = "",
betId = "UUID1",
@ -270,7 +263,7 @@ private val mockBets = mutableListOf(
response = listOf(YES_VALUE, NO_VALUE),
createdBy = "Armure",
type = BetType.BINARY,
status = BetStatus.WAITING,
status = BetStatus.IN_PROGRESS,
),
ResponseBet(
id = "UUID2",
@ -282,7 +275,7 @@ private val mockBets = mutableListOf(
response = listOf("Answer 1", "Answer 2", "Answer 3", "Answer 4"),
createdBy = "User 2",
type = BetType.BINARY,
status = BetStatus.WAITING,
status = BetStatus.IN_PROGRESS,
),
ResponseBet(
id = "UUID3",

@ -11,19 +11,21 @@ import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import javax.inject.Singleton
const val mock = false
@Module
@InstallIn(SingletonComponent::class)
class ApiModule {
@Provides
@Singleton
fun provideAllInApi(@AllInUrl url: HttpUrl, okHttpClient: OkHttpClient): AllInApi {
return if (mock) {
return if (MOCK) {
MockAllInApi()
} else {
val retrofit = createRetrofit(url = url, okHttpClient = okHttpClient)
retrofit.create(AllInApi::class.java)
}
}
companion object {
const val MOCK = true
}
}

@ -12,10 +12,9 @@ androidxCore = "1.12.0"
androidxActivity = "1.8.2"
androidxSecurity = "1.1.0-alpha06"
composeBom = "2023.10.01"
compose = "1.5.4"
composePreview = "1.6.0-beta03"
composeBom = "2024.04.00"
composeCompiler = "1.5.5"
composePreview = "1.6.5"
composeNavigation = "2.7.6"
hilt = "2.48"
@ -55,20 +54,20 @@ test-androidx-junit = { group = "androidx.test.ext", name = "junit-ktx", version
test-espresso = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
hilt-androidTesting = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" }
hilt-androidCompiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
ui-test-junit = { group = "androidx.compose.ui", name = "ui-test-junit4", version.ref = "compose" }
ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest", version.ref = "compose" }
ui-test-junit = { group = "androidx.compose.ui", name = "ui-test-junit4" }
ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
# Compose
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
compose-ui = { module = "androidx.compose.ui:ui" }
compose-ui-graphics = { module = "androidx.compose.ui:ui-graphics" }
compose-foundation = { module = "androidx.compose.foundation:foundation", version = "1.6.0-beta03" }
compose-foundation = { module = "androidx.compose.foundation:foundation" }
compose-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "composePreview" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
compose-ui-googlefonts = { group = "androidx.compose.ui", name = "ui-text-google-fonts" }
compose-material = { module = "androidx.compose.material:material" }
compose-material3 = { group = "androidx.compose.material3", name = "material3", version = "1.2.0-beta01" }
compose-material3 = { group = "androidx.compose.material3", name = "material3", version = "1.2.1" }
compose-material-icons = { group = "androidx.compose.material", name = "material-icons-core" }
compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" }
compose-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "composeNavigation" }

Loading…
Cancel
Save