diff --git a/src/app/build.gradle.kts b/src/app/build.gradle.kts index d9b3b9f..bd7d3fb 100644 --- a/src/app/build.gradle.kts +++ b/src/app/build.gradle.kts @@ -10,7 +10,7 @@ plugins { } // Keystore -val keystorePropertiesFile = rootProject.file("app/keys/keystore.properties") +val keystorePropertiesFile = rootProject.file("keys/keystore.properties") val keystoreProperties = Properties() keystoreProperties.load(FileInputStream(keystorePropertiesFile)) @@ -33,11 +33,16 @@ android { } } + signingConfigs { + named(BuildType.DEBUG.name) { + storeFile = file(keystoreProperties["debugStoreFile"].toString()) + } register(BuildType.RELEASE.name) { - storeFile = file(keystoreProperties["store"].toString()) - storePassword = keystoreProperties["password"].toString() - keyPassword = keystoreProperties["password"].toString() + storeFile = file(keystoreProperties["releaseStoreFile"].toString()) + storePassword = keystoreProperties["passwordRelease"].toString() + keyAlias = keystoreProperties["aliasRelease"].toString() + keyPassword = keystoreProperties["passwordRelease"].toString() } } @@ -102,5 +107,6 @@ dependencies { androidTestImplementation(libs.test.androidx.junit) androidTestImplementation(libs.hilt.androidTesting) kaptAndroidTest(libs.hilt.androidCompiler) - + androidTestImplementation(libs.ui.test.junit) + debugImplementation(libs.ui.test.manifest) } \ No newline at end of file diff --git a/src/app/keys/keystore.jks b/src/app/keys/keystore.jks deleted file mode 100644 index bb4e75c..0000000 Binary files a/src/app/keys/keystore.jks and /dev/null differ diff --git a/src/app/keys/keystore.properties b/src/app/keys/keystore.properties deleted file mode 100644 index fe9ab09..0000000 --- a/src/app/keys/keystore.properties +++ /dev/null @@ -1,2 +0,0 @@ -store=keys/keystore.jks -password=placeYourBets \ No newline at end of file diff --git a/src/app/keys/private_key.pepk b/src/app/keys/private_key.pepk deleted file mode 100644 index be8173b..0000000 Binary files a/src/app/keys/private_key.pepk and /dev/null differ diff --git a/src/app/proguard-rules.pro b/src/app/proguard-rules.pro index ff59496..719ab83 100644 --- a/src/app/proguard-rules.pro +++ b/src/app/proguard-rules.pro @@ -18,4 +18,19 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + + +# Android.Security.Crypto +-dontwarn com.google.api.client.http.** +-dontwarn com.google.errorprone.** +-dontwarn org.joda.time.** + +-keep,allowoptimization class com.google.crypto.tink.** { *; } +-keep,allowoptimization class com.google.errorprone.** { *; } +-keep,allowoptimization class com.google.api.client.http.** { *; } + +-keep,allowobfuscation,allowshrinking interface retrofit2.Call +-keep,allowobfuscation,allowshrinking class retrofit2.Response + +-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation \ No newline at end of file diff --git a/src/app/src/androidTest/java/fr/iut/alldev/allin/test/mock/Bets.kt b/src/app/src/androidTest/java/fr/iut/alldev/allin/test/mock/Bets.kt index 4397df3..846c540 100644 --- a/src/app/src/androidTest/java/fr/iut/alldev/allin/test/mock/Bets.kt +++ b/src/app/src/androidTest/java/fr/iut/alldev/allin/test/mock/Bets.kt @@ -1,6 +1,7 @@ package fr.iut.alldev.allin.test.mock import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.data.model.bet.CustomBet import fr.iut.alldev.allin.data.model.bet.MatchBet import fr.iut.alldev.allin.data.model.bet.YesNoBet import java.time.ZonedDateTime @@ -14,7 +15,8 @@ object Bets { endRegisterDate = ZonedDateTime.now(), endBetDate = ZonedDateTime.now(), isPublic = true, - betStatus = BetStatus.InProgress + betStatus = BetStatus.InProgress, + creator = "creator", ), MatchBet( theme = "Theme", @@ -24,7 +26,23 @@ object Bets { isPublic = true, betStatus = BetStatus.InProgress, nameTeam1 = "Team_1", - nameTeam2 = "Team_2" + nameTeam2 = "Team_2", + creator = "creator" + ), + CustomBet( + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.InProgress, + creator = "creator", + possibleAnswers = listOf( + "Answer 1", + "Answer 2", + "Answer 3", + "Answer 4" + ) ), ) } diff --git a/src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/BetVOTest.kt b/src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/BetVOTest.kt index 0f9265a..088912f 100644 --- a/src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/BetVOTest.kt +++ b/src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/BetVOTest.kt @@ -9,8 +9,7 @@ import fr.iut.alldev.allin.test.TestTags import fr.iut.alldev.allin.test.mock.Bets import fr.iut.alldev.allin.ui.MainActivity import fr.iut.alldev.allin.theme.AllInTheme -import fr.iut.alldev.allin.vo.bet.factory.toBetVO -import fr.iut.alldev.allin.vo.bet.visitor.BetTestVisitor +import fr.iut.alldev.allin.vo.bet.displayer.BetTestDisplayer import org.junit.Before import org.junit.Rule import org.junit.Test @@ -30,37 +29,55 @@ class BetVOTest { } companion object { - val visitor = BetTestVisitor() + val displayer = BetTestDisplayer() } @Test - fun testVisitor_shouldDisplayYesNoBetUI(){ + fun testDisplayer_shouldDisplayYesNoBetUI(){ //Given //When composeTestRule.activity.setContent { AllInTheme{ - Bets.bets[0].toBetVO()?.Accept(v = visitor) + displayer.DisplayBet(Bets.bets[0]) } } //Expect composeTestRule.onNodeWithTag(TestTags.YES_NO_BET.tag).assertExists() composeTestRule.onNodeWithTag(TestTags.MATCH_BET.tag).assertDoesNotExist() + composeTestRule.onNodeWithTag(TestTags.CUSTOM_BET.tag).assertDoesNotExist() } @Test - fun testVisitor_shouldDisplayMatchUI(){ + fun testDisplayer_shouldDisplayMatchUI(){ //Given //When composeTestRule.activity.setContent { AllInTheme{ - Bets.bets[1].toBetVO()?.Accept(v = visitor) + displayer.DisplayBet(Bets.bets[1]) } } //Expect composeTestRule.onNodeWithTag(TestTags.MATCH_BET.tag).assertExists() composeTestRule.onNodeWithTag(TestTags.YES_NO_BET.tag).assertDoesNotExist() + composeTestRule.onNodeWithTag(TestTags.CUSTOM_BET.tag).assertDoesNotExist() + } + + @Test + fun testDisplayer_shouldDisplayCustomBetUI(){ + //Given + + //When + composeTestRule.activity.setContent { + AllInTheme{ + displayer.DisplayBet(Bets.bets[2]) + } + } + //Expect + composeTestRule.onNodeWithTag(TestTags.MATCH_BET.tag).assertDoesNotExist() + composeTestRule.onNodeWithTag(TestTags.YES_NO_BET.tag).assertDoesNotExist() + composeTestRule.onNodeWithTag(TestTags.CUSTOM_BET.tag).assertExists() } } \ No newline at end of file diff --git a/src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/visitor/BetVOTestVisitor.kt b/src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/displayer/BetVOTestVisitor.kt similarity index 53% rename from src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/visitor/BetVOTestVisitor.kt rename to src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/displayer/BetVOTestVisitor.kt index 20858d6..b8abc92 100644 --- a/src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/visitor/BetVOTestVisitor.kt +++ b/src/app/src/androidTest/java/fr/iut/alldev/allin/vo/bet/displayer/BetVOTestVisitor.kt @@ -1,21 +1,28 @@ -package fr.iut.alldev.allin.vo.bet.visitor +package fr.iut.alldev.allin.vo.bet.displayer import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag +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.YesNoBet import fr.iut.alldev.allin.test.TestTags +import fr.iut.alldev.allin.vo.bet.BetDisplayer -class BetTestVisitor : DisplayBetVisitor { +class BetTestDisplayer : BetDisplayer { @Composable - override fun VisitYesNoBet(b: YesNoBet) { + override fun DisplayYesNoBet(bet: YesNoBet) { Text("This is a YesNo Bet", Modifier.testTag(TestTags.YES_NO_BET.tag)) } @Composable - override fun VisitMatchBet(b: MatchBet) { + override fun DisplayMatchBet(bet: MatchBet) { Text("This is a Match Bet", Modifier.testTag(TestTags.MATCH_BET.tag)) } + + @Composable + override fun DisplayCustomBet(bet: CustomBet) { + Text("This is a Custom Bet", Modifier.testTag(TestTags.CUSTOM_BET.tag)) + } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/di/CurrentUserModule.kt b/src/app/src/main/java/fr/iut/alldev/allin/di/CurrentUserModule.kt index 2010974..fee0dc8 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/di/CurrentUserModule.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/di/CurrentUserModule.kt @@ -16,7 +16,5 @@ annotation class AllInCurrentUser internal object CurrentUserModule { @AllInCurrentUser @Provides - fun provideUser( - userRepository: UserRepository - ) = userRepository.currentUser + fun provideUser(userRepository: UserRepository) = userRepository.currentUser } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ext/BetTypeExt.kt b/src/app/src/main/java/fr/iut/alldev/allin/ext/BetTypeExt.kt index b91ac51..43c66a0 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ext/BetTypeExt.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ext/BetTypeExt.kt @@ -12,7 +12,7 @@ import fr.iut.alldev.allin.data.model.bet.BetType @StringRes fun BetType.getTitleId(): Int { return when (this) { - BetType.YES_NO -> R.string.yes_no + BetType.YES_NO -> R.string.yes_no BetType.MATCH -> R.string.sport_match BetType.CUSTOM -> R.string.custom_answers } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ext/FloatExt.kt b/src/app/src/main/java/fr/iut/alldev/allin/ext/FloatExt.kt new file mode 100644 index 0000000..542eec9 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ext/FloatExt.kt @@ -0,0 +1,9 @@ +package fr.iut.alldev.allin.ext + +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.util.Locale + +fun Float.formatToSimple(locale: Locale): String { + return DecimalFormat("0.##", DecimalFormatSymbols.getInstance(locale)).format(this) +} diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ext/StringExt.kt b/src/app/src/main/java/fr/iut/alldev/allin/ext/StringExt.kt new file mode 100644 index 0000000..4d0bab2 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ext/StringExt.kt @@ -0,0 +1,21 @@ +package fr.iut.alldev.allin.ext + +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.util.Locale + +fun String.verifyIsFloat(locale: Locale): String? { + val pattern = Regex("^\\d+(\\.|\\,)?\\d*\$") + val decimalSeparator = DecimalFormatSymbols.getInstance(locale).decimalSeparator.toString() + + return if (this.matches(pattern)) { + this.replace(Regex("[.,]"), decimalSeparator).format() + } else if (this.isEmpty()) { + this + } else null +} + +fun String.toFloatOrNull(locale: Locale): Float? { + val format = DecimalFormat("0.##", DecimalFormatSymbols.getInstance(locale)) + return format.parse(this)?.toFloat() +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/keystore/AllInKeystoreManager.kt b/src/app/src/main/java/fr/iut/alldev/allin/keystore/AllInKeystoreManager.kt index 5d26ecf..79aab93 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/keystore/AllInKeystoreManager.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/keystore/AllInKeystoreManager.kt @@ -1,10 +1,9 @@ package fr.iut.alldev.allin.keystore -import androidx.security.crypto.MasterKeys +import androidx.security.crypto.MasterKey abstract class AllInKeystoreManager { - val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) - + protected abstract val masterKey: MasterKey abstract fun createKeystore() abstract fun putToken(token: String) abstract fun getToken(): String? diff --git a/src/app/src/main/java/fr/iut/alldev/allin/keystore/impl/AllInKeystoreManagerImpl.kt b/src/app/src/main/java/fr/iut/alldev/allin/keystore/impl/AllInKeystoreManagerImpl.kt index 899fd7e..a1baba5 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/keystore/impl/AllInKeystoreManagerImpl.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/keystore/impl/AllInKeystoreManagerImpl.kt @@ -3,10 +3,12 @@ package fr.iut.alldev.allin.keystore.impl import android.content.Context import android.content.SharedPreferences import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey import dagger.hilt.android.qualifiers.ApplicationContext import fr.iut.alldev.allin.keystore.AllInKeystoreManager import javax.inject.Inject + private const val AUTH_TOKEN_KEY = "auth_token" private const val PREFS_FILE_NAME = "secured_shared_prefs" @@ -14,13 +16,18 @@ class AllInKeystoreManagerImpl @Inject constructor( @ApplicationContext private val context: Context, ) : AllInKeystoreManager() { + override val masterKey = MasterKey + .Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + private var sharedPreferences: SharedPreferences? = null override fun createKeystore() { if (sharedPreferences == null) { sharedPreferences = EncryptedSharedPreferences.create( - PREFS_FILE_NAME, - masterKeyAlias, context, + PREFS_FILE_NAME, + masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/test/TestTags.kt b/src/app/src/main/java/fr/iut/alldev/allin/test/TestTags.kt index fe01326..4c4d2ac 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/test/TestTags.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/test/TestTags.kt @@ -2,5 +2,6 @@ package fr.iut.alldev.allin.test enum class TestTags(val tag: String) { YES_NO_BET("YES_NO"), - MATCH_BET("MATCH_BET") + MATCH_BET("MATCH_BET"), + CUSTOM_BET("CUSTOM_BET") } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/theme/Color.kt b/src/app/src/main/java/fr/iut/alldev/allin/theme/Color.kt index 2edb267..7fd16ff 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/theme/Color.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/theme/Color.kt @@ -36,6 +36,7 @@ data class AllInColors( val allInBetInProgressText: Color, val allInBetWaitingText: Color, val allInMainGradient: Brush, + val allInMainGradientReverse: Brush, val allInBar1stGradient: Brush, val allInBar2ndGradient: Brush, val allInTextGradient: Brush, @@ -73,6 +74,7 @@ internal val LocalColors = staticCompositionLocalOf { allInBetInProgressText = Color.Unspecified, allInBetWaitingText = Color.Unspecified, allInMainGradient = SolidColor(Color.Unspecified), + allInMainGradientReverse = SolidColor(Color.Unspecified), allInBar1stGradient = SolidColor(Color.Unspecified), allInBar2ndGradient = SolidColor(Color.Unspecified), allInTextGradient = SolidColor(Color.Unspecified), diff --git a/src/app/src/main/java/fr/iut/alldev/allin/theme/Icons.kt b/src/app/src/main/java/fr/iut/alldev/allin/theme/Icons.kt index 819c5b5..8382348 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/theme/Icons.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/theme/Icons.kt @@ -9,7 +9,7 @@ import androidx.compose.ui.graphics.painter.Painter @Immutable data class AllInIcons( - val allCoins: @Composable ()->Painter, + val allCoins: @Composable () -> Painter, ) internal val LocalIcons = staticCompositionLocalOf { diff --git a/src/app/src/main/java/fr/iut/alldev/allin/theme/Theme.kt b/src/app/src/main/java/fr/iut/alldev/allin/theme/Theme.kt index db4e631..04e6e42 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/theme/Theme.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/theme/Theme.kt @@ -55,6 +55,13 @@ fun AllInTheme( start = Offset(0f, Float.POSITIVE_INFINITY), end = Offset(Float.POSITIVE_INFINITY, 0f) ), + allInMainGradientReverse = Brush.linearGradient( + 0.0f to Color(0xFF199fee), + 0.5f to Color(0xFFaa7ef3), + 1.0f to Color(0xFFf951a8), + start = Offset(0f, Float.POSITIVE_INFINITY), + end = Offset(Float.POSITIVE_INFINITY, 0f) + ), allInBar1stGradient = Brush.horizontalGradient( 0.0f to Color(0xFF2599F8), 1.0f to Color(0xFF846AC9) @@ -82,32 +89,32 @@ fun AllInTheme( val customTypography = AllInTypography( h1 = TextStyle( - fontFamily = PlusJakartaSans, - fontWeight = FontWeight.ExtraBold, + fontFamily = fontFamilyPlusJakartaSans, + fontWeight = FontWeight.ExtraBold ), h2 = TextStyle( - fontFamily = PlusJakartaSans, - fontWeight = FontWeight.Bold, + fontFamily = fontFamilyPlusJakartaSans, + fontWeight = FontWeight.Bold ), - h3 = TextStyle( - fontFamily = PlusJakartaSans, - fontWeight = FontWeight.SemiBold, + sm1 = TextStyle( + fontFamily = fontFamilyPlusJakartaSans, + fontWeight = FontWeight.SemiBold ), - m = TextStyle( - fontFamily = PlusJakartaSans, - fontWeight = FontWeight.Medium, + sm2 = TextStyle( + fontFamily = fontFamilyPlusJakartaSans, + fontWeight = FontWeight.Medium ), - r = TextStyle( - fontFamily = PlusJakartaSans, - fontWeight = FontWeight.Normal, + p1 = TextStyle( + fontFamily = fontFamilyPlusJakartaSans, + fontWeight = FontWeight.Normal ), - s = TextStyle( - fontFamily = PlusJakartaSans, - fontWeight = FontWeight.Light, + p2 = TextStyle( + fontFamily = fontFamilyPlusJakartaSans, + fontWeight = FontWeight.Light ), - xs = TextStyle( - fontFamily = PlusJakartaSans, - fontWeight = FontWeight.ExtraLight, + l1 = TextStyle( + fontFamily = fontFamilyPlusJakartaSans, + fontWeight = FontWeight.ExtraLight ) ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/theme/Type.kt b/src/app/src/main/java/fr/iut/alldev/allin/theme/Type.kt index 1bc5b6c..e8bc176 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/theme/Type.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/theme/Type.kt @@ -3,40 +3,50 @@ package fr.iut.alldev.allin.theme import androidx.compose.runtime.Immutable import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.googlefonts.Font +import androidx.compose.ui.text.googlefonts.GoogleFont import fr.iut.alldev.allin.R -val PlusJakartaSans = FontFamily( - Font(R.font.plusjakartasans_extralight, weight = FontWeight.ExtraLight), - Font(R.font.plusjakartasans_light, weight = FontWeight.Light), - Font(R.font.plusjakartasans_regular, weight = FontWeight.Normal), - Font(R.font.plusjakartasans_medium, weight = FontWeight.Medium), - Font(R.font.plusjakartasans_semibold, weight = FontWeight.SemiBold), - Font(R.font.plusjakartasans_bold, weight = FontWeight.Bold), - Font(R.font.plusjakartasans_extrabold, weight = FontWeight.ExtraBold) - ) +private val provider = GoogleFont.Provider( + providerAuthority = "com.google.android.gms.fonts", + providerPackage = "com.google.android.gms", + certificates = R.array.com_google_android_gms_fonts_certs +) + +private val fontNamePlusJakartaSans = GoogleFont(name = "Plus Jakarta Sans") + +val fontFamilyPlusJakartaSans = FontFamily( + Font(googleFont = fontNamePlusJakartaSans, fontProvider = provider, weight = FontWeight.ExtraLight), + Font(googleFont = fontNamePlusJakartaSans, fontProvider = provider, weight = FontWeight.Light), + Font(googleFont = fontNamePlusJakartaSans, fontProvider = provider, weight = FontWeight.Normal), + Font(googleFont = fontNamePlusJakartaSans, fontProvider = provider, weight = FontWeight.Medium), + Font(googleFont = fontNamePlusJakartaSans, fontProvider = provider, weight = FontWeight.SemiBold), + Font(googleFont = fontNamePlusJakartaSans, fontProvider = provider, weight = FontWeight.Bold), + Font(googleFont = fontNamePlusJakartaSans, fontProvider = provider, weight = FontWeight.ExtraBold), +) + @Immutable data class AllInTypography( val h1: TextStyle, val h2: TextStyle, - val h3: TextStyle, - val m: TextStyle, - val r: TextStyle, - val s: TextStyle, - val xs: TextStyle + val sm1: TextStyle, + val sm2: TextStyle, + val p1: TextStyle, + val p2: TextStyle, + val l1: TextStyle ) internal val LocalTypography = staticCompositionLocalOf { AllInTypography( h1 = TextStyle.Default, h2 = TextStyle.Default, - h3 = TextStyle.Default, - m = TextStyle.Default, - r = TextStyle.Default, - s = TextStyle.Default, - xs = TextStyle.Default + sm1 = TextStyle.Default, + sm2 = TextStyle.Default, + p1 = TextStyle.Default, + p2 = TextStyle.Default, + l1 = TextStyle.Default ) } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/BetScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/BetScreen.kt index 2b2a8f0..cecb36f 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/BetScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/BetScreen.kt @@ -118,8 +118,8 @@ fun BetScreen( creator = it.creator, category = it.theme, title = it.phrase, - date = it.endBetDate.formatToMediumDateNoYear(), - time = it.endBetDate.formatToTime(), + date = it.endRegisterDate.formatToMediumDateNoYear(), + time = it.endRegisterDate.formatToTime(), players = List(3) { null }, onClickParticipate = { selectBet(it, true) }, onClickCard = { selectBet(it, false) }, diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenCard.kt index 2375aef..4d0e899 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenCard.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenCard.kt @@ -79,7 +79,7 @@ fun BetScreenCard( players.size, players.size ), - style = AllInTheme.typography.m, + style = AllInTheme.typography.sm2, color = AllInTheme.themeColors.onBackground2 ) } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenPopularCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenPopularCard.kt index 7d36a48..7dbb6a9 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenPopularCard.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/bet/components/BetScreenPopularCard.kt @@ -100,13 +100,13 @@ fun BetScreenPopularCard( color = AllInTheme.colors.allInPink ), color = AllInTheme.colors.white, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, fontSize = 15.sp ) Text( text = " - ", color = AllInTheme.colors.white, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, fontSize = 15.sp ) val pointsText = if (points % 1 == 0f) { @@ -126,7 +126,7 @@ fun BetScreenPopularCard( color = AllInTheme.colors.allInPink ), color = AllInTheme.colors.white, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, fontSize = 15.sp ) } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/BetCreationViewModel.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/BetCreationViewModel.kt index 620bd63..5e420ea 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/BetCreationViewModel.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/BetCreationViewModel.kt @@ -110,6 +110,7 @@ class BetCreationViewModel @Inject constructor( if (!hasError.value) { try { val bet = BetFactory.createBet( + id = "", betType = selectedBetType.value, theme = theme.value, phrase = phrase.value, @@ -118,7 +119,7 @@ class BetCreationViewModel @Inject constructor( isPublic = isPublic.value, nameTeam1 = "", nameTeam2 = "", - possibleAnswers = setOf(), + possibleAnswers = listOf(), creator = currentUser.username ) betRepository.createBet(bet, keystoreManager.getToken() ?: "") diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/tabs/BetCreationScreenQuestionTab.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/tabs/BetCreationScreenQuestionTab.kt index b893b5d..1065e7e 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/tabs/BetCreationScreenQuestionTab.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/tabs/BetCreationScreenQuestionTab.kt @@ -1,10 +1,10 @@ package fr.iut.alldev.allin.ui.betCreation.tabs -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.relocation.BringIntoViewRequester -import androidx.compose.runtime.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import fr.iut.alldev.allin.data.ext.formatToMediumDate @@ -14,32 +14,30 @@ import fr.iut.alldev.allin.ui.betCreation.tabs.sections.QuestionTabPrivacySectio import fr.iut.alldev.allin.ui.betCreation.tabs.sections.QuestionTabThemePhraseSection import java.time.ZonedDateTime -@OptIn(ExperimentalFoundationApi::class) @Composable fun BetCreationScreenQuestionTab( modifier: Modifier = Modifier, nbFriends: Int, betTheme: String, betThemeError: String?, - setBetTheme: (String)->Unit, + setBetTheme: (String) -> Unit, betPhrase: String, betPhraseError: String?, - setBetPhrase: (String)->Unit, + setBetPhrase: (String) -> Unit, isPublic: Boolean, - setIsPublic: (Boolean)->Unit, + setIsPublic: (Boolean) -> Unit, registerDate: ZonedDateTime, registerDateError: String?, betDate: ZonedDateTime, betDateError: String?, selectedFriends: MutableList, - setRegisterDateDialog: (Boolean)->Unit, - setEndDateDialog: (Boolean)->Unit, - setRegisterTimeDialog: (Boolean)->Unit, - setEndTimeDialog: (Boolean)->Unit, + setRegisterDateDialog: (Boolean) -> Unit, + setEndDateDialog: (Boolean) -> Unit, + setRegisterTimeDialog: (Boolean) -> Unit, + setEndTimeDialog: (Boolean) -> Unit, interactionSource: MutableInteractionSource ) { - val bringIntoViewRequester = remember { BringIntoViewRequester() } - Column(modifier){ + Column(modifier) { QuestionTabThemePhraseSection( betTheme = betTheme, betThemeError = betThemeError, @@ -47,7 +45,6 @@ fun BetCreationScreenQuestionTab( betPhrase = betPhrase, betPhraseError = betPhraseError, setBetPhrase = setBetPhrase, - bringIntoViewRequester = bringIntoViewRequester, interactionSource = interactionSource ) Spacer(modifier = Modifier.height(35.dp)) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/tabs/sections/QuestionTabThemePhraseSection.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/tabs/sections/QuestionTabThemePhraseSection.kt index 809da0d..3eddd1f 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/tabs/sections/QuestionTabThemePhraseSection.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betCreation/tabs/sections/QuestionTabThemePhraseSection.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.relocation.BringIntoViewRequester import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.runtime.Composable @@ -24,11 +23,10 @@ import fr.iut.alldev.allin.ui.core.AllInTitleInfo internal fun QuestionTabThemePhraseSection( betTheme: String, betThemeError: String?, - setBetTheme: (String)->Unit, + setBetTheme: (String) -> Unit, betPhrase: String, betPhraseError: String?, - setBetPhrase: (String)->Unit, - bringIntoViewRequester: BringIntoViewRequester, + setBetPhrase: (String) -> Unit, interactionSource: MutableInteractionSource ) { AllInTitleInfo( @@ -41,13 +39,12 @@ internal fun QuestionTabThemePhraseSection( AllInTextField( placeholder = stringResource(id = R.string.Theme_placeholder), value = betTheme, - onValueChange = setBetTheme, - bringIntoViewRequester = bringIntoViewRequester, - borderColor = AllInTheme.colors.white, + modifier = Modifier.fillMaxWidth(), maxChar = 20, placeholderFontSize = 13.sp, + onValueChange = setBetTheme, errorText = betThemeError, - modifier = Modifier.fillMaxWidth() + borderColor = AllInTheme.colors.white ) Spacer(modifier = Modifier.height(10.dp)) AllInTitleInfo( @@ -60,15 +57,14 @@ internal fun QuestionTabThemePhraseSection( AllInTextField( placeholder = stringResource(id = R.string.Bet_Phrase_placeholder), value = betPhrase, - borderColor = AllInTheme.colors.white, - onValueChange = setBetPhrase, - bringIntoViewRequester = bringIntoViewRequester, - multiLine = true, + modifier = Modifier + .fillMaxWidth() + .height(100.dp), maxChar = 100, placeholderFontSize = 13.sp, + multiLine = true, + onValueChange = setBetPhrase, errorText = betPhraseError, - modifier = Modifier - .fillMaxWidth() - .height(100.dp) + borderColor = AllInTheme.colors.white ) } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betHistory/BetHistoryScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betHistory/BetHistoryScreen.kt index 82d73f5..60ee7ed 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betHistory/BetHistoryScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betHistory/BetHistoryScreen.kt @@ -54,8 +54,8 @@ fun BetHistoryScreen( title = it.phrase, creator = it.creator, category = it.theme, - date = it.endBetDate.formatToMediumDateNoYear(), - time = it.endBetDate.formatToTime(), + date = it.endRegisterDate.formatToMediumDateNoYear(), + time = it.endRegisterDate.formatToTime(), status = it.betStatus, nbCoins = 230 ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betHistory/components/BetHistoryScreenCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betHistory/components/BetHistoryScreenCard.kt index 4a8fa93..6375306 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betHistory/components/BetHistoryScreenCard.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betHistory/components/BetHistoryScreenCard.kt @@ -1,24 +1,13 @@ package fr.iut.alldev.allin.ui.betHistory.components import android.content.res.Configuration -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.dp import fr.iut.alldev.allin.data.model.bet.BetStatus -import fr.iut.alldev.allin.ext.getDateStartLabelId import fr.iut.alldev.allin.theme.AllInTheme -import fr.iut.alldev.allin.ui.core.AllInCard -import fr.iut.alldev.allin.ui.core.bet.BetDateTimeRow -import fr.iut.alldev.allin.ui.core.bet.BetTitleHeader +import fr.iut.alldev.allin.ui.core.bet.BetCard import fr.iut.alldev.allin.ui.preview.BetStatusPreviewProvider @Composable @@ -32,30 +21,15 @@ fun BetHistoryScreenCard( status: BetStatus, nbCoins: Int, ) { - AllInCard( - modifier = modifier.fillMaxWidth(), - radius = 16.dp + BetCard( + title = title, + creator = creator, + category = category, + date = date, + time = time, + status = status, + modifier = modifier ) { - Column( - Modifier.padding(horizontal = 19.dp, vertical = 11.dp) - ) { - BetTitleHeader( - title = title, - category = category, - creator = creator, - modifier = Modifier.fillMaxWidth() - ) - Spacer(modifier = Modifier.height(11.dp)) - BetDateTimeRow( - label = stringResource(id = status.getDateStartLabelId()), - date = date, - time = time - ) - } - HorizontalDivider( - thickness = 1.dp, - color = AllInTheme.themeColors.border - ) BetHistoryBetStatus( status = status, nbCoins = nbCoins diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/BetResultBottomSheet.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/BetResultBottomSheet.kt new file mode 100644 index 0000000..7fd4eeb --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/BetResultBottomSheet.kt @@ -0,0 +1,173 @@ +package fr.iut.alldev.allin.ui.betResult + +import androidx.compose.foundation.MarqueeSpacing +import androidx.compose.foundation.background +import androidx.compose.foundation.basicMarquee +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.SheetState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.draw.scale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import fr.iut.alldev.allin.R +import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear +import fr.iut.alldev.allin.data.ext.formatToTime +import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.data.model.bet.YesNoBet +import fr.iut.alldev.allin.theme.AllInTheme +import fr.iut.alldev.allin.ui.betResult.components.BetResultBottomSheetBetCard +import fr.iut.alldev.allin.ui.betResult.components.BetResultBottomSheetContentCoinAmount +import fr.iut.alldev.allin.ui.betResult.components.BetResultBottomSheetContentCongratulations +import fr.iut.alldev.allin.ui.core.AllInBottomSheet +import java.time.ZonedDateTime + +@Composable +fun BetResultBottomSheet( + state: SheetState, + sheetVisibility: Boolean, + username: String, + coinAmount: Int, + bet: Bet, + stake: Int, + winnings: Int, + odds: Float, + onDismiss: () -> Unit +) { + AllInBottomSheet( + sheetVisibility = sheetVisibility, + onDismiss = onDismiss, + state = state, + dragHandle = null + ) { + BetResultBottomSheetContent( + username = username, + coinAmount = coinAmount, + bet = bet, + stake = stake, + winnings = winnings, + odds = odds, + onClose = onDismiss + ) + } +} + +@Composable +fun BetResultBottomSheetContent( + username: String, + coinAmount: Int, + bet: Bet, + stake: Int, + winnings: Int, + odds: Float, + onClose: () -> Unit +) { + Box( + modifier = Modifier + .fillMaxSize() + .background(AllInTheme.colors.allInMainGradientReverse), + ) { + Icon( + painter = painterResource(id = R.drawable.allin_marquee), + contentDescription = null, + modifier = Modifier + .fillMaxSize() + .rotate(11f) + .scale(1.2f) + .offset(x = (-24).dp) + .basicMarquee(spacing = MarqueeSpacing(0.dp)), + tint = AllInTheme.colors.white.copy(alpha = .05f) + ) + Box( + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + ) { + IconButton( + onClick = onClose, + modifier = Modifier + .size(24.dp) + .align(Alignment.TopStart) + ) { + Icon( + imageVector = Icons.Default.Close, + tint = AllInTheme.colors.white, + contentDescription = null, + modifier = Modifier.size(24.dp) + ) + } + + Icon( + painter = painterResource(R.drawable.allin), + contentDescription = null, + tint = AllInTheme.colors.white, + modifier = Modifier + .size(40.dp) + .align(Alignment.TopCenter) + ) + + Column( + modifier = Modifier.align(Alignment.Center), + verticalArrangement = Arrangement.spacedBy(48.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + + BetResultBottomSheetContentCongratulations(username = username) + BetResultBottomSheetContentCoinAmount(amount = coinAmount) + BetResultBottomSheetBetCard( + title = bet.phrase, + creator = bet.creator, + category = bet.theme, + date = bet.endBetDate.formatToMediumDateNoYear(), + time = bet.endBetDate.formatToTime(), + status = bet.betStatus, + stake = stake, + winnings = winnings, + odds = odds + + ) + } + } + } +} + +@Preview +@Preview(widthDp = 800, heightDp = 1280) +@Composable +private fun BetResultBottomSheetContentPreview() { + AllInTheme { + BetResultBottomSheetContent( + username = "Pseudo", + coinAmount = 3976, + bet = YesNoBet( + id = "1", + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.InProgress, + creator = "creator", + ), + stake = 4175, + winnings = 2600, + odds = 6.7f + ) { + + } + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetCard.kt new file mode 100644 index 0000000..d0050dc --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetCard.kt @@ -0,0 +1,60 @@ +package fr.iut.alldev.allin.ui.betResult.components + +import android.content.res.Configuration +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus +import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.theme.AllInTheme +import fr.iut.alldev.allin.ui.core.bet.BetCard + +@Composable +fun BetResultBottomSheetBetCard( + modifier: Modifier = Modifier, + title: String, + creator: String, + category: String, + date: String, + time: String, + status: BetStatus, + stake: Int, + winnings: Int, + odds: Float +) { + BetCard( + title = title, + creator = creator, + category = category, + date = date, + time = time, + status = status, + modifier = modifier + ) { + BetResultBottomSheetBetCardStats( + stake = stake, + winnings = winnings, + odds = odds + ) + } +} + + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun BetResultBottomSheetBetCardPreview() { + AllInTheme { + BetResultBottomSheetBetCard( + creator = "Creator", + category = "Category", + title = "Title", + date = "Date", + time = "Time", + status = BetStatus.Finished(BetFinishedStatus.WON), + stake = 2446, + winnings = 6930, + odds = 2.3f + ) + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetCardStats.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetCardStats.kt new file mode 100644 index 0000000..4a5aae6 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetCardStats.kt @@ -0,0 +1,111 @@ +package fr.iut.alldev.allin.ui.betResult.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.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.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.theme.AllInTheme +import fr.iut.alldev.allin.ui.core.AllInCard +import fr.iut.alldev.allin.ui.core.AllInCoinCount +import fr.iut.alldev.allin.ui.core.IconPosition + +@Composable +fun BetResultBottomSheetBetCardStats( + stake: Int, + winnings: Int, + odds: Float +) { + Column( + Modifier + .fillMaxWidth() + .background(AllInTheme.themeColors.background2) + .padding(horizontal = 19.dp, vertical = 11.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = stringResource(id = R.string.bet_result_stake), + style = AllInTheme.typography.sm2, + color = AllInTheme.themeColors.onMainSurface + ) + + AllInCoinCount( + amount = stake, + color = AllInTheme.colors.allInPurple, + textStyle = AllInTheme.typography.sm1, + position = IconPosition.TRAILING + ) + } + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = stringResource(id = R.string.bet_result_winnings), + style = AllInTheme.typography.sm2, + color = AllInTheme.colors.allInPurple + ) + AllInCoinCount( + amount = winnings, + textStyle = AllInTheme.typography.sm1, + brush = AllInTheme.colors.allInMainGradient, + position = IconPosition.TRAILING + ) + } + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = stringResource(id = R.string.bet_result_odds), + style = AllInTheme.typography.sm2, + color = AllInTheme.themeColors.onBackground2 + ) + AllInCard( + radius = 8.dp, + backgroundBrush = AllInTheme.colors.allInMainGradient + ) { + Box(Modifier.padding(vertical = 4.dp, horizontal = 8.dp)) { + Text( + text = "$odds", + style = AllInTheme.typography.sm1, + color = AllInTheme.colors.white + ) + } + } + } + } +} + + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun BetResultBottomSheetBetCardStatsPreview() { + AllInTheme { + BetResultBottomSheetBetCardStats( + stake = 2446, + winnings = 6930, + odds = 2.3f + ) + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetContentCongratulations.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetContentCongratulations.kt new file mode 100644 index 0000000..4af87f9 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetBetContentCongratulations.kt @@ -0,0 +1,71 @@ +package fr.iut.alldev.allin.ui.betResult.components + +import androidx.compose.animation.core.RepeatMode +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.draw.scale +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontStyle +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 + +@Composable +fun BetResultBottomSheetContentCongratulations( + modifier: Modifier = Modifier, + username: String +) { + val infiniteTransition = rememberInfiniteTransition(label = "") + + val rotation by infiniteTransition.animateFloat( + initialValue = -11f, + targetValue = -5f, + animationSpec = infiniteRepeatable( + animation = tween(900), + repeatMode = RepeatMode.Reverse + ), label = "" + ) + + val scale by infiniteTransition.animateFloat( + initialValue = 1f, + targetValue = .9f, + animationSpec = infiniteRepeatable( + animation = tween(900), + repeatMode = RepeatMode.Reverse + ), label = "" + ) + + Row( + modifier = modifier + .rotate(rotation) + .scale(scale), + verticalAlignment = Alignment.Top, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text= stringResource(id = R.string.bet_result_congratulations), + style = AllInTheme.typography.h1, + fontSize = 25.sp, + fontStyle = FontStyle.Italic, + color = AllInTheme.colors.white + ) + Text( + text = "${username.uppercase()} !", + style = AllInTheme.typography.h1, + fontSize = 30.sp, + fontStyle = FontStyle.Italic, + color = AllInTheme.colors.white + ) + } +} diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetContentCoinAmount.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetContentCoinAmount.kt new file mode 100644 index 0000000..bb9ed23 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betResult/components/BetResultBottomSheetContentCoinAmount.kt @@ -0,0 +1,79 @@ +package fr.iut.alldev.allin.ui.betResult.components + +import android.content.res.Configuration +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import fr.iut.alldev.allin.R +import fr.iut.alldev.allin.theme.AllInTheme +import fr.iut.alldev.allin.ui.core.AllInCoinCount +import fr.iut.alldev.allin.ui.core.IconPosition + +@Composable +fun BetResultBottomSheetContentCoinAmount( + modifier: Modifier = Modifier, + amount: Int +) { + Column( + verticalArrangement = Arrangement.spacedBy(14.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = stringResource(id = R.string.bet_result_you_win), + style = AllInTheme.typography.sm2, + color = AllInTheme.colors.white, + fontSize = 20.sp + ) + + Box( + modifier + .border( + width = 2.dp, + shape = RoundedCornerShape(100.dp), + color = AllInTheme.colors.white + ) + .padding(vertical = 22.dp, horizontal = 33.dp) + + ) { + AllInCoinCount( + amount = amount, + textStyle = AllInTheme.typography.h1, + position = IconPosition.TRAILING, + color = AllInTheme.colors.white, + size = 60, + modifier = Modifier + .align(Alignment.Center) + .offset(y = (-6).dp) + ) + AllInCoinCount( + amount = amount, + textStyle = AllInTheme.typography.h1, + position = IconPosition.TRAILING, + color = AllInTheme.colors.white.copy(alpha = .32f), + size = 60, + modifier = Modifier.align(Alignment.Center) + ) + } + } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun BetResultBottomSheetContentCoinAmountPreview() { + AllInTheme { + BetResultBottomSheetContentCoinAmount(amount = 1572) + } +} diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/BetStatusBottomSheet.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/BetStatusBottomSheet.kt index 2c37b47..7e193fc 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/BetStatusBottomSheet.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/BetStatusBottomSheet.kt @@ -6,11 +6,13 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail import fr.iut.alldev.allin.ui.betStatus.components.BetStatusBottomSheetBack -import fr.iut.alldev.allin.ui.betStatus.visitor.BetStatusBottomSheetDisplayBetVisitor +import fr.iut.alldev.allin.ui.betStatus.components.BetStatusParticipationBottomSheet +import fr.iut.alldev.allin.ui.betStatus.components.getAnswerFromParticipationIdx +import fr.iut.alldev.allin.ui.betStatus.components.getParticipationAnswers import fr.iut.alldev.allin.ui.core.AllInBottomSheet -import fr.iut.alldev.allin.vo.bet.BetVO internal const val SHEET_HEIGHT = .85f @@ -22,9 +24,14 @@ fun BetStatusBottomSheet( state: SheetState, sheetVisibility: Boolean, sheetBackVisibility: Boolean, - bet: BetVO?, - onDismiss: ()->Unit, - visitor: BetStatusBottomSheetDisplayBetVisitor + betDetail: BetDetail?, + paddingValues: PaddingValues, + userCoinAmount: MutableIntState, + onParticipate: (stake: Int, response: String) -> Unit, + onDismiss: () -> Unit, + participateSheetVisibility: Boolean, + setParticipateSheetVisibility: (Boolean) -> Unit, + displayBet: @Composable (BetDetail) -> Unit ) { AnimatedVisibility( visible = sheetBackVisibility, @@ -35,7 +42,7 @@ fun BetStatusBottomSheet( targetOffsetY = { it } ) ) { - bet?.let { + betDetail?.let { BetStatusBottomSheetBack( status = it.bet.betStatus ) @@ -47,11 +54,45 @@ fun BetStatusBottomSheet( onDismiss = onDismiss, state = state, scrimColor = Color.Transparent - ){ + ) { + + var selectedAnswer by remember { mutableStateOf(0) } + var stake by remember { mutableStateOf(null) } + Column( Modifier.fillMaxHeight(SHEET_HEIGHT) ) { - bet?.Accept(visitor) + betDetail?.let { + val elements = betDetail.getParticipationAnswers() + + displayBet(it) + BetStatusParticipationBottomSheet( + sheetVisibility = participateSheetVisibility && betDetail.bet.betStatus == BetStatus.Waiting && state.hasExpandedState, + safeBottomPadding = paddingValues.calculateBottomPadding(), + odds = betDetail.answers.getOrNull(selectedAnswer)?.odds ?: 1f, + betPhrase = betDetail.bet.phrase, + coinAmount = userCoinAmount.intValue, + onDismiss = { setParticipateSheetVisibility(false) }, + state = rememberModalBottomSheetState(skipPartiallyExpanded = true), + elements = elements, + selectedElement = elements.getOrNull(selectedAnswer), + stake = stake, + setStake = { stake = it }, + setElement = { idx -> selectedAnswer = idx }, + enabled = stake != null && + (stake ?: 0) <= userCoinAmount.intValue + ) { + stake?.let { stake -> + onParticipate( + stake, + betDetail.bet.getAnswerFromParticipationIdx(selectedAnswer) + ) + } + } + + } } + } + } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusParticipationAnswers.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusParticipationAnswers.kt new file mode 100644 index 0000000..735ad70 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusParticipationAnswers.kt @@ -0,0 +1,166 @@ +package fr.iut.alldev.allin.ui.betStatus.components + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +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.Color +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.os.ConfigurationCompat +import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.CustomBet +import fr.iut.alldev.allin.data.model.bet.MatchBet +import fr.iut.alldev.allin.data.model.bet.NO_VALUE +import fr.iut.alldev.allin.data.model.bet.YES_VALUE +import fr.iut.alldev.allin.data.model.bet.YesNoBet +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail +import fr.iut.alldev.allin.ext.formatToSimple +import fr.iut.alldev.allin.theme.AllInTheme +import fr.iut.alldev.allin.ui.core.AllInCard +import fr.iut.alldev.allin.ui.preview.BetDetailPreviewProvider +import java.util.Locale + +private val participationAnswerFontSize = 25.sp + +@Composable +fun BetDetail.getParticipationAnswers(): List<@Composable RowScope.() -> Unit> { + val configuration = LocalConfiguration.current + val locale = remember { ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault() } + + return when (this.bet) { + is CustomBet -> (this.bet as CustomBet).possibleAnswers.map { + { + this@getParticipationAnswers.getAnswerOfResponse(it)?.let { + ParticipationAnswerLine( + text = it.response, + odds = it.odds, + locale = locale + ) + } + } + } + + is MatchBet -> buildList { + val bet = (this@getParticipationAnswers.bet as MatchBet) + add { + this@getParticipationAnswers.getAnswerOfResponse(bet.nameTeam1)?.let { + ParticipationAnswerLine( + text = it.response, + odds = it.odds, + locale = locale + ) + } + } + add { + this@getParticipationAnswers.getAnswerOfResponse(bet.nameTeam2)?.let { + ParticipationAnswerLine( + text = it.response, + color = AllInTheme.colors.allInBarPink, + odds = it.odds, + locale = locale + ) + } + } + } + + is YesNoBet -> buildList { + add { + this@getParticipationAnswers.getAnswerOfResponse(YES_VALUE)?.let { + ParticipationAnswerLine( + text = it.response, + odds = it.odds, + locale = locale + ) + } + } + add { + this@getParticipationAnswers.getAnswerOfResponse(NO_VALUE)?.let { + ParticipationAnswerLine( + text = it.response, + color = AllInTheme.colors.allInBarPink, + odds = it.odds, + locale = locale + ) + } + } + } + } +} + +@Composable +private fun ParticipationAnswerLine( + text: String, + color: Color = AllInTheme.colors.allInBlue, + locale: Locale, + odds: Float +) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = text.uppercase(), + color = color, + style = AllInTheme.typography.h1, + fontSize = participationAnswerFontSize + ) + + AllInCard( + radius = 50.dp, + backgroundColor = AllInTheme.colors.allInPurple + ) { + Box(Modifier.padding(vertical = 4.dp, horizontal = 8.dp)) { + Text( + text = "x${odds.formatToSimple(locale)}", + color = AllInTheme.colors.white, + style = AllInTheme.typography.h2 + ) + } + } + } +} + +fun Bet.getAnswerFromParticipationIdx(idx: Int) = + when (this) { + is CustomBet -> this.possibleAnswers.getOrElse(idx) { "" } + is MatchBet -> when (idx) { + 0 -> this.nameTeam1 + 1 -> this.nameTeam2 + else -> "" + } + + is YesNoBet -> when (idx) { + 0 -> YES_VALUE + 1 -> NO_VALUE + else -> "" + } + } + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ParticipationAnswersPreview( + @PreviewParameter(BetDetailPreviewProvider::class) bet: BetDetail, +) { + AllInTheme { + Column { + bet.getParticipationAnswers().forEach { + Row(Modifier.fillMaxWidth()) { it() } + } + } + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusParticipationBottomSheet.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusParticipationBottomSheet.kt index 8c88061..7892162 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusParticipationBottomSheet.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusParticipationBottomSheet.kt @@ -5,6 +5,8 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material3.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -18,8 +20,11 @@ import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.ui.core.AllInBottomSheet import fr.iut.alldev.allin.ui.core.AllInButton import fr.iut.alldev.allin.ui.core.AllInCoinCount +import fr.iut.alldev.allin.ui.core.AllInIntTextField +import fr.iut.alldev.allin.ui.core.AllInSelectionBox import fr.iut.alldev.allin.ui.core.topbar.AllInTopBarCoinCounter import kotlinx.coroutines.launch +import kotlin.math.roundToInt @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -30,7 +35,14 @@ fun BetStatusParticipationBottomSheet( coinAmount: Int, onDismiss: () -> Unit, state: SheetState, - onParticipate: () -> Unit, + enabled: Boolean, + odds: Float, + stake: Int?, + setStake: (Int?) -> Unit, + elements: List<@Composable RowScope.() -> Unit>, + selectedElement: (@Composable RowScope.() -> Unit)?, + setElement: (Int) -> Unit, + onParticipate: () -> Unit ) { val scope = rememberCoroutineScope() AllInBottomSheet( @@ -38,6 +50,98 @@ fun BetStatusParticipationBottomSheet( onDismiss = onDismiss, state = state, containerColor = AllInTheme.themeColors.background2 + ) { + BetStatusParticipationBottomSheetContent( + safeBottomPadding = safeBottomPadding, + betPhrase = betPhrase, + coinAmount = coinAmount, + elements = elements, + selectedElement = selectedElement, + setElement = setElement, + enabled = enabled, + stake = stake, + odds = odds, + setStake = setStake + ) { + scope.launch { + onParticipate() + state.hide() + onDismiss() + } + } + } +} + +@Composable +private fun ColumnScope.BetStatusParticipationBottomSheetContent( + safeBottomPadding: Dp, + betPhrase: String, + coinAmount: Int, + enabled: Boolean, + stake: Int?, + odds: Float, + setStake: (Int?) -> Unit, + selectedElement: (@Composable RowScope.() -> Unit)?, + elements: List<@Composable RowScope.() -> Unit>, + setElement: (Int) -> Unit, + onButtonClick: () -> Unit +) { + val (answersBoxIsOpen, setAnswersBoxIsOpen) = remember { mutableStateOf(false) } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(id = R.string.place_your_bets), + style = AllInTheme.typography.h2, + color = AllInTheme.themeColors.onMainSurface, + fontSize = 20.sp, + modifier = Modifier.padding(start = 18.dp) + ) + AllInTopBarCoinCounter( + amount = coinAmount, + backgroundColor = AllInTheme.colors.allInBlue, + textColor = AllInTheme.colors.white, + iconColor = AllInTheme.colors.white, + ) + } + Column( + modifier = Modifier.padding(horizontal = 18.dp) + ) { + Text( + text = betPhrase, + style = AllInTheme.typography.p2, + color = AllInTheme.themeColors.onMainSurface, + modifier = Modifier.padding(vertical = 30.dp) + ) + AllInSelectionBox( + isOpen = answersBoxIsOpen, + setIsOpen = setAnswersBoxIsOpen, + selected = selectedElement, + setSelected = { setElement(elements.indexOf(it)) }, + elements = elements, + borderWidth = 1.dp + ) + Spacer(modifier = Modifier.height(8.dp)) + AllInIntTextField( + value = stake, + setValue = setStake, + placeholder = stringResource(id = R.string.bet_result_stake), + trailingIcon = AllInTheme.icons.allCoins(), + modifier = Modifier.fillMaxWidth(), + maxChar = null + ) + } + Spacer(modifier = Modifier.height(100.dp)) + HorizontalDivider(color = AllInTheme.themeColors.border) + Column( + modifier = Modifier + .background(AllInTheme.themeColors.background) + .padding(horizontal = 7.dp) + .padding(bottom = safeBottomPadding, top = 7.dp), + verticalArrangement = Arrangement.spacedBy(7.dp) ) { Row( modifier = Modifier.fillMaxWidth(), @@ -45,81 +149,45 @@ fun BetStatusParticipationBottomSheet( verticalAlignment = Alignment.CenterVertically ) { Text( - text = stringResource(id = R.string.place_your_bets), - style = AllInTheme.typography.h2, - color = AllInTheme.themeColors.onMainSurface, - fontSize = 20.sp, - modifier = Modifier.padding(start = 18.dp) + text = stringResource(id = R.string.Possible_winnings), + style = AllInTheme.typography.p1, + color = AllInTheme.themeColors.onBackground ) - AllInTopBarCoinCounter( - amount = coinAmount, - backgroundColor = AllInTheme.colors.allInBlue, - textColor = AllInTheme.colors.white, - iconColor = AllInTheme.colors.white, + AllInCoinCount( + amount = stake?.let { (it + (it * odds)).roundToInt() } ?: 0, + color = AllInTheme.themeColors.onBackground ) } - Spacer(modifier = Modifier.height(30.dp)) - Text( - text = betPhrase, - style = AllInTheme.typography.s, - color = AllInTheme.themeColors.onMainSurface, - modifier = Modifier.padding(horizontal = 18.dp) + AllInButton( + enabled = enabled, + color = AllInTheme.colors.allInPurple, + text = stringResource(id = R.string.Participate), + textColor = AllInTheme.colors.white, + radius = 5.dp, + onClick = onButtonClick ) - Spacer(modifier = Modifier.height(100.dp)) - HorizontalDivider(color = AllInTheme.themeColors.border) - Column( - modifier = Modifier - .background(AllInTheme.themeColors.background) - .padding(horizontal = 7.dp) - .padding(bottom = safeBottomPadding, top = 7.dp), - verticalArrangement = Arrangement.spacedBy(7.dp) - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = stringResource(id = R.string.Possible_winnings), - style = AllInTheme.typography.r, - color = AllInTheme.themeColors.onBackground - ) - AllInCoinCount( - amount = 121, - color = AllInTheme.themeColors.onBackground - ) - } - AllInButton( - color = AllInTheme.colors.allInPurple, - text = stringResource(id = R.string.Participate), - textColor = AllInTheme.colors.white, - radius = 5.dp - ) { - scope.launch { - onParticipate() - state.hide() - onDismiss() - } - } - } } } - -@OptIn(ExperimentalMaterial3Api::class) @Preview @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable -private fun BetStatusParticipationBottomSheetPreview() { +private fun BetStatusParticipationBottomSheetContentPreview() { AllInTheme { - BetStatusParticipationBottomSheet( - sheetVisibility = true, - safeBottomPadding = 5.dp, - betPhrase = "Lorem Ipsum", - coinAmount = 125, - onDismiss = {}, - state = rememberModalBottomSheetState(), - onParticipate = {} - ) + Column { + BetStatusParticipationBottomSheetContent( + safeBottomPadding = 0.dp, + betPhrase = "Bet phrase", + coinAmount = 3620, + onButtonClick = {}, + elements = emptyList(), + setElement = {}, + selectedElement = null, + enabled = true, + stake = 123, + odds = 0.42f, + setStake = {} + ) + } } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusWinner.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusWinner.kt index 92da99d..e8292b7 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusWinner.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/BetStatusWinner.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import fr.iut.alldev.allin.theme.AllInTheme @@ -41,7 +42,7 @@ fun BetStatusWinner( ) { AllInTextIcon( text = answer, - icon = Icons.Filled.EmojiEvents, + icon = rememberVectorPainter(image = Icons.Filled.EmojiEvents), color = color, size = 50, iconSize = 60, @@ -57,13 +58,13 @@ fun BetStatusWinner( ) AllInTextIcon( text = username, - icon = Icons.Filled.People, + icon = rememberVectorPainter(image = Icons.Filled.People), color = color, position = IconPosition.LEADING ) AllInTextIcon( text = "x" + String.format("%.1f", multiplier), - icon = Icons.Filled.EmojiEvents, + icon = rememberVectorPainter(image = Icons.Filled.EmojiEvents), color = color, position = IconPosition.LEADING ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/YesNoDetailsLine.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/YesNoDetailsLine.kt index acf8245..784b368 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/YesNoDetailsLine.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/YesNoDetailsLine.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.tooling.preview.Preview import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.ui.core.AllInTextIcon @@ -26,7 +27,7 @@ fun YesNoDetailsLine( AllInTextIcon( text = yesText, color = AllInTheme.colors.allInBlue, - icon = icon, + icon = rememberVectorPainter(image = icon), position = IconPosition.LEADING, size = 10, iconSize = 15 @@ -34,7 +35,7 @@ fun YesNoDetailsLine( AllInTextIcon( text = noText, color = AllInTheme.colors.allInBarPink, - icon = icon, + icon = rememberVectorPainter(image = icon), position = IconPosition.TRAILING, size = 10, iconSize = 15 diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/YesNoStarBar.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/YesNoStarBar.kt index 5366b1a..1aad42e 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/YesNoStarBar.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/components/YesNoStarBar.kt @@ -4,27 +4,27 @@ import androidx.compose.foundation.layout.* import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.sp -import fr.iut.alldev.allin.R import fr.iut.alldev.allin.data.ext.toPercentageString import fr.iut.alldev.allin.theme.AllInTheme import fr.iut.alldev.allin.ui.core.PercentagePositionnedElement import fr.iut.alldev.allin.ui.core.StatBar @Composable -fun YesNoStatBar( - yesPercentage: Float, +fun BinaryStatBar( + response1Percentage: Float, + response1: String, + response2: String, modifier: Modifier = Modifier, ) { Column(modifier) { Row { Text( - text = stringResource(id = R.string.Yes).uppercase(), + text = response1, color = AllInTheme.colors.allInBlue, style = AllInTheme.typography.h1, fontStyle = FontStyle.Italic, @@ -32,20 +32,20 @@ fun YesNoStatBar( modifier = Modifier.weight(1f) ) Text( - text = stringResource(id = R.string.No).uppercase(), + text = response2, style = AllInTheme.typography.h1, fontStyle = FontStyle.Italic, fontSize = 30.sp, color = AllInTheme.colors.allInBarPink ) } - StatBar(percentage = yesPercentage) + StatBar(percentage = response1Percentage) PercentagePositionnedElement( - percentage = yesPercentage + percentage = response1Percentage ) { Text( - text = yesPercentage.toPercentageString(), - style = AllInTheme.typography.h3, + text = response1Percentage.toPercentageString(), + style = AllInTheme.typography.sm1, color = AllInTheme.colors.allInBarPurple ) } @@ -64,6 +64,10 @@ private fun YesNoStatBarPreview( @PreviewParameter(YesNoStatBarPreviewProvider::class) percentage: Float, ) { AllInTheme { - YesNoStatBar(percentage) + BinaryStatBar( + percentage, + "Answer 1", + "Answer 2" + ) } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/visitor/BetStatusBottomSheetDisplayBetVisitor.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/visitor/BetStatusBottomSheetDisplayBetVisitor.kt deleted file mode 100644 index 62c1fd0..0000000 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/visitor/BetStatusBottomSheetDisplayBetVisitor.kt +++ /dev/null @@ -1,236 +0,0 @@ -package fr.iut.alldev.allin.ui.betStatus.visitor - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.EmojiEvents -import androidx.compose.material.icons.filled.People -import androidx.compose.material.icons.filled.WorkspacePremium -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import fr.iut.alldev.allin.R -import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear -import fr.iut.alldev.allin.data.ext.formatToTime -import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus -import fr.iut.alldev.allin.data.model.bet.BetStatus -import fr.iut.alldev.allin.data.model.bet.MatchBet -import fr.iut.alldev.allin.data.model.bet.YesNoBet -import fr.iut.alldev.allin.ext.getDateEndLabelId -import fr.iut.alldev.allin.ext.getDateStartLabelId -import fr.iut.alldev.allin.theme.AllInTheme -import fr.iut.alldev.allin.ui.betStatus.components.BetStatusParticipationBottomSheet -import fr.iut.alldev.allin.ui.betStatus.components.BetStatusWinner -import fr.iut.alldev.allin.ui.betStatus.components.YesNoDetailsLine -import fr.iut.alldev.allin.ui.betStatus.components.YesNoStatBar -import fr.iut.alldev.allin.ui.core.AllInDetailsDrawer -import fr.iut.alldev.allin.ui.core.RainbowButton -import fr.iut.alldev.allin.ui.core.bet.BetDateTimeRow -import fr.iut.alldev.allin.ui.core.bet.BetTitleHeader -import fr.iut.alldev.allin.vo.bet.factory.toBetVO -import fr.iut.alldev.allin.vo.bet.visitor.DisplayBetVisitor -import java.time.ZonedDateTime - -class BetStatusBottomSheetDisplayBetVisitor( - val userCoinAmount: MutableIntState, - val onParticipate: (Int) -> Unit, -) : DisplayBetVisitor { - - val participateBottomSheetVisibility = mutableStateOf(false) - val paddingValues = mutableStateOf(PaddingValues()) - - @OptIn(ExperimentalMaterial3Api::class) - @Composable - override fun VisitYesNoBet(b: YesNoBet) { - - val (participateSheetVisibility, setParticipateSheetVisibility) = remember { - this.participateBottomSheetVisibility - } - - val safeBottomPadding = paddingValues.value.calculateBottomPadding() - - Box( - Modifier - .padding(bottom = safeBottomPadding) - ) { - Column { - Column(Modifier.padding(horizontal = 20.dp)) { - BetTitleHeader( - title = b.phrase, - category = b.theme, - creator = "Lucas" /*TODO : Creator*/, - modifier = Modifier.fillMaxWidth() - ) - Spacer(modifier = Modifier.height(20.dp)) - Column( - horizontalAlignment = Alignment.End - ) { - BetDateTimeRow( - label = stringResource(id = b.betStatus.getDateStartLabelId()), - date = b.endRegisterDate.formatToMediumDateNoYear(), - time = b.endRegisterDate.formatToTime(), - modifier = Modifier.width(IntrinsicSize.Max) - ) - Spacer(modifier = Modifier.height(15.dp)) - BetDateTimeRow( - label = stringResource(id = b.betStatus.getDateEndLabelId()), - date = b.endBetDate.formatToMediumDateNoYear(), - time = b.endBetDate.formatToTime(), - modifier = Modifier.width(IntrinsicSize.Max) - ) - } - Spacer(modifier = Modifier.height(20.dp)) - } - if (b.betStatus is BetStatus.Finished) { - BetStatusWinner( - answer = stringResource(id = R.string.Yes), - color = AllInTheme.colors.allInBlue, - coinAmount = 442, - username = "Imri", - multiplier = 1.2f - ) - } else { - HorizontalDivider(color = AllInTheme.themeColors.border) - } - Column( - Modifier - .fillMaxHeight() - .background(AllInTheme.themeColors.background2) - .padding(horizontal = 20.dp) - ) { - Spacer(modifier = Modifier.height(20.dp)) - YesNoStatBar(yesPercentage = .86f) - AllInDetailsDrawer { - YesNoDetailsLine( - icon = AllInTheme.icons.allCoins(), - yesText = "550", - noText = "330", - ) - YesNoDetailsLine( - icon = Icons.Filled.People, - yesText = "12", - noText = "5" - ) - YesNoDetailsLine( - icon = Icons.Filled.WorkspacePremium, - yesText = "45", - noText = "45" - ) - YesNoDetailsLine( - icon = Icons.Filled.EmojiEvents, - yesText = "x1.2", - noText = "x1.45" - ) - } - } - } - if (b.betStatus !is BetStatus.Finished) { - RainbowButton( - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(horizontal = 7.dp), - text = stringResource(id = R.string.Participate), - enabled = b.betStatus == BetStatus.Waiting, - onClick = { - setParticipateSheetVisibility(true) - } - ) - } - } - - BetStatusParticipationBottomSheet( - sheetVisibility = participateSheetVisibility && b.betStatus == BetStatus.Waiting, - safeBottomPadding = safeBottomPadding, - betPhrase = b.phrase, - coinAmount = userCoinAmount.intValue, - onDismiss = { setParticipateSheetVisibility(false) }, - state = rememberModalBottomSheetState() - ) { - onParticipate(100) - } - } - - @Composable - override fun VisitMatchBet(b: MatchBet) { - Text("This is a MATCH BET") - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun YesNoBetPreview() { - AllInTheme { - val coins = remember { mutableIntStateOf(100) } - YesNoBet( - theme = "Theme", - phrase = "Phrase", - endRegisterDate = ZonedDateTime.now(), - endBetDate = ZonedDateTime.now(), - isPublic = true, - betStatus = BetStatus.InProgress, - creator = "creator" - ).toBetVO()?.Accept( - BetStatusBottomSheetDisplayBetVisitor( - userCoinAmount = coins, - onParticipate = {} - ) - ) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun YesNoBetFinishedPreview() { - AllInTheme { - val coins = remember { mutableIntStateOf(100) } - YesNoBet( - theme = "Theme", - phrase = "Phrase", - endRegisterDate = ZonedDateTime.now(), - endBetDate = ZonedDateTime.now(), - isPublic = true, - betStatus = BetStatus.Finished(BetFinishedStatus.WON), - creator = "creator" - ).toBetVO()?.Accept( - BetStatusBottomSheetDisplayBetVisitor( - userCoinAmount = coins, - onParticipate = {} - ) - ) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun MatchBetPreview() { - AllInTheme { - val coins = remember { mutableIntStateOf(100) } - MatchBet( - theme = "Theme", - phrase = "Phrase", - endRegisterDate = ZonedDateTime.now(), - endBetDate = ZonedDateTime.now(), - isPublic = true, - betStatus = BetStatus.InProgress, - nameTeam1 = "Team 1", - nameTeam2 = "Team 2", - creator = "creator" - ).toBetVO()?.Accept( - BetStatusBottomSheetDisplayBetVisitor( - userCoinAmount = coins, - onParticipate = {} - ) - ) - } -} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/vo/BetStatusBottomSheetBetDisplayer.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/vo/BetStatusBottomSheetBetDisplayer.kt new file mode 100644 index 0000000..e316c59 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/betStatus/vo/BetStatusBottomSheetBetDisplayer.kt @@ -0,0 +1,265 @@ +package fr.iut.alldev.allin.ui.betStatus.vo + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +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.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.os.ConfigurationCompat +import fr.iut.alldev.allin.R +import fr.iut.alldev.allin.data.ext.formatToMediumDateNoYear +import fr.iut.alldev.allin.data.ext.formatToTime +import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.data.model.bet.MatchBet +import fr.iut.alldev.allin.data.model.bet.NO_VALUE +import fr.iut.alldev.allin.data.model.bet.YES_VALUE +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail +import fr.iut.alldev.allin.ext.formatToSimple +import fr.iut.alldev.allin.ext.getDateEndLabelId +import fr.iut.alldev.allin.ext.getDateStartLabelId +import fr.iut.alldev.allin.theme.AllInTheme +import fr.iut.alldev.allin.ui.betStatus.components.BetStatusWinner +import fr.iut.alldev.allin.ui.betStatus.components.BinaryStatBar +import fr.iut.alldev.allin.ui.betStatus.components.YesNoDetailsLine +import fr.iut.alldev.allin.ui.core.AllInCoinCount +import fr.iut.alldev.allin.ui.core.AllInDetailsDrawer +import fr.iut.alldev.allin.ui.core.ProfilePicture +import fr.iut.alldev.allin.ui.core.RainbowButton +import fr.iut.alldev.allin.ui.core.bet.BetDateTimeRow +import fr.iut.alldev.allin.ui.core.bet.BetTitleHeader +import fr.iut.alldev.allin.ui.preview.BetDetailPreviewProvider +import fr.iut.alldev.allin.vo.bet.BetDisplayer +import java.util.Locale + +class BetStatusBottomSheetBetDisplayer( + val openParticipateSheet: () -> Unit +) : BetDisplayer { + val paddingValues = mutableStateOf(PaddingValues()) + + @Composable + private fun DisplayBinaryBet( + betDetail: BetDetail, + response1: String, + response2: String, + 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 response1Answer = remember { betDetail.getAnswerOfResponse(response1) } + val response2Answer = remember { betDetail.getAnswerOfResponse(response2) } + + Box(Modifier.padding(bottom = safeBottomPadding)) { + Column { + Column(Modifier.padding(horizontal = 20.dp)) { + BetTitleHeader( + title = betDetail.bet.phrase, + category = betDetail.bet.theme, + creator = betDetail.bet.creator, + modifier = Modifier.fillMaxWidth() + ) + Spacer(modifier = Modifier.height(20.dp)) + Column( + horizontalAlignment = Alignment.End + ) { + BetDateTimeRow( + label = stringResource(id = betDetail.bet.betStatus.getDateStartLabelId()), + date = betDetail.bet.endRegisterDate.formatToMediumDateNoYear(), + time = betDetail.bet.endRegisterDate.formatToTime(), + modifier = Modifier.width(IntrinsicSize.Max) + ) + Spacer(modifier = Modifier.height(15.dp)) + BetDateTimeRow( + label = stringResource(id = betDetail.bet.betStatus.getDateEndLabelId()), + date = betDetail.bet.endBetDate.formatToMediumDateNoYear(), + time = betDetail.bet.endBetDate.formatToTime(), + modifier = Modifier.width(IntrinsicSize.Max) + ) + } + Spacer(modifier = Modifier.height(20.dp)) + } + if (betDetail.bet.betStatus is BetStatus.Finished) { + BetStatusWinner( + answer = response1Display, + color = AllInTheme.colors.allInBlue, + coinAmount = 442, + username = "Imri", + multiplier = 1.2f + ) + } else { + HorizontalDivider(color = AllInTheme.themeColors.border) + } + Column( + Modifier + .fillMaxHeight() + .background(AllInTheme.themeColors.background2) + .padding(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" + ) + YesNoDetailsLine( + icon = Icons.Filled.People, + yesText = response1Answer?.totalParticipants?.toString() ?: "0", + noText = response2Answer?.totalParticipants?.toString() ?: "0" + ) + YesNoDetailsLine( + icon = Icons.Filled.WorkspacePremium, + yesText = response1Answer?.highestStake?.toString() ?: "0", + noText = response2Answer?.highestStake?.toString() ?: "0" + ) + YesNoDetailsLine( + icon = 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) + ) + 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) + ) + } + } + items(betDetail.participations) { + if (it.username != betDetail.userParticipation?.username) { + BetStatusParticipant( + username = it.username, + allCoinsAmount = it.stake + ) + } + } + } + } + } + if (betDetail.bet.betStatus !is BetStatus.Finished && betDetail.userParticipation == null) { + RainbowButton( + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(horizontal = 7.dp), + text = stringResource(id = R.string.Participate), + enabled = betDetail.bet.betStatus == BetStatus.Waiting, + onClick = openParticipateSheet + ) + } + } + } + + @OptIn(ExperimentalMaterial3Api::class) + @Composable + override fun DisplayYesNoBet(betDetail: BetDetail) { + DisplayBinaryBet( + betDetail = betDetail, + response1 = YES_VALUE, + response2 = NO_VALUE, + response1Display = stringResource(id = R.string.Yes).uppercase(), + response2Display = stringResource(id = R.string.No).uppercase() + ) + } + + @Composable + override fun DisplayMatchBet(betDetail: BetDetail) { + val bet = remember { betDetail.bet as MatchBet } + DisplayBinaryBet( + betDetail = betDetail, + response1 = bet.nameTeam1, + response2 = bet.nameTeam2 + ) + } + + @Composable + override fun DisplayCustomBet(betDetail: BetDetail) { + Text("This is a CUSTOM BET") + } +} + +@Composable +fun BetStatusParticipant( + username: String, + allCoinsAmount: Int +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(7.dp), + verticalAlignment = Alignment.CenterVertically + ) { + ProfilePicture(modifier = Modifier.size(25.dp)) + Text( + text = username, + fontWeight = FontWeight.Bold, + style = AllInTheme.typography.h2, + color = AllInTheme.themeColors.onMainSurface, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f) + ) + AllInCoinCount( + amount = allCoinsAmount, + color = AllInTheme.colors.allInPurple + ) + } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun BetStatusBottomSheetPreview( + @PreviewParameter(BetDetailPreviewProvider::class) bet: BetDetail +) { + AllInTheme { + BetStatusBottomSheetBetDisplayer { + + }.DisplayBet(bet) + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInAlertDialog.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInAlertDialog.kt index 8bae7c6..f2ffd39 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInAlertDialog.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInAlertDialog.kt @@ -32,7 +32,7 @@ fun AllInAlertDialog( text = { Text( text = text, - style = AllInTheme.typography.r + style = AllInTheme.typography.p1 ) }, confirmButton = { diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInBottomSheet.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInBottomSheet.kt index 43f29ef..07954b7 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInBottomSheet.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInBottomSheet.kt @@ -18,6 +18,7 @@ fun AllInBottomSheet( state: SheetState, scrimColor: Color = BottomSheetDefaults.ScrimColor, containerColor: Color = AllInTheme.themeColors.background, + dragHandle: (@Composable ()->Unit)? = { BottomSheetDefaults.DragHandle() }, content: @Composable ColumnScope.()->Unit ) { val localDensity = LocalDensity.current @@ -38,6 +39,7 @@ fun AllInBottomSheet( bottom = 0, ) }, + dragHandle = dragHandle, content = content ) } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInButton.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInButton.kt index 7917058..f6ad5d8 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInButton.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInButton.kt @@ -15,10 +15,11 @@ import fr.iut.alldev.allin.theme.AllInTheme @Composable fun AllInButton( + modifier: Modifier = Modifier, + enabled: Boolean = true, color: Color, text: String, textColor: Color, - modifier: Modifier = Modifier, radius: Dp = 15.dp, onClick: () -> Unit, ) { @@ -26,13 +27,14 @@ fun AllInButton( onClick = onClick, modifier = modifier, radius = radius, - backgroundColor = color + backgroundColor = color, + enabled = enabled ) { Text( text = text, textAlign = TextAlign.Center, style = AllInTheme.typography.h2, - color = textColor, + color = if(enabled) textColor else AllInTheme.themeColors.disabledBorder, fontSize = 20.sp, modifier = Modifier .padding(vertical = 15.dp) @@ -51,6 +53,21 @@ private fun AllInButtonPreview() { textColor = Color.White ) { + } + } +} + +@Preview +@Composable +private fun AllInButtonDisabledPreview() { + AllInTheme { + AllInButton( + color = AllInTheme.colors.allInLoginPurple, + text = "Connexion", + textColor = Color.White, + enabled = false + ) { + } } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInChip.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInChip.kt index 63846f7..fb5dbdf 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInChip.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInChip.kt @@ -44,7 +44,7 @@ fun AllInChip( .padding(vertical = 8.dp, horizontal = 22.dp) .alpha(if (isSelected) 0f else 1f), textAlign = TextAlign.Center, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, color = AllInTheme.themeColors.onBackground2 ) if (isSelected) { diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCoinCount.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCoinCount.kt index 1613a6a..99c10a0 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCoinCount.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInCoinCount.kt @@ -3,7 +3,9 @@ package fr.iut.alldev.allin.ui.core import android.content.res.Configuration import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import fr.iut.alldev.allin.theme.AllInTheme @@ -11,14 +13,20 @@ import fr.iut.alldev.allin.theme.AllInTheme fun AllInCoinCount( modifier: Modifier = Modifier, amount: Int, - color: Color, - position: IconPosition = IconPosition.TRAILING, + color: Color? = null, + brush: Brush?= null, + size: Int = 15, + textStyle: TextStyle = AllInTheme.typography.h1, + position: IconPosition = IconPosition.TRAILING ) { AllInTextIcon( text = amount.toString(), icon = AllInTheme.icons.allCoins(), - color = color, + color = color ?: Color.Black, + brush = brush, position = position, + textStyle = textStyle, + size = size, modifier = modifier ) } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDatePicker.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDatePicker.kt index 9ac4a4e..6b5a41d 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDatePicker.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDatePicker.kt @@ -51,7 +51,7 @@ fun AllInDatePicker( Text( text = stringResource(id = R.string.Cancel), color = AllInTheme.themeColors.onBackground2, - style = AllInTheme.typography.h3 + style = AllInTheme.typography.sm1 ) } }, diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDetailsDrawer.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDetailsDrawer.kt index 4a38160..22def8f 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDetailsDrawer.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInDetailsDrawer.kt @@ -58,7 +58,7 @@ fun AllInDetailsDrawer( ) { Text( text = text, - style = AllInTheme.typography.s, + style = AllInTheme.typography.p2, color = textColor, fontSize = 15.sp ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInErrorLine.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInErrorLine.kt index 4565cff..611c4b2 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInErrorLine.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInErrorLine.kt @@ -12,7 +12,7 @@ import fr.iut.alldev.allin.theme.AllInTheme fun AllInErrorLine(text: String) { Text( text = text, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, color = Color.Red, fontSize = 10.sp, overflow = TextOverflow.Ellipsis diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInRetractableCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInRetractableCard.kt index e023a85..8b552e6 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInRetractableCard.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInRetractableCard.kt @@ -64,7 +64,7 @@ fun AllInRetractableCard( fontStyle = AllInTheme.typography.h2.fontStyle ), color = AllInTheme.themeColors.onBackground2, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, fontSize = 16.sp, modifier = Modifier.weight(1f) ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSectionButton.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSectionButton.kt index 01113fc..8f8ef77 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSectionButton.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSectionButton.kt @@ -20,14 +20,14 @@ fun AllInSectionButton( onClick: (Int) -> Unit, ) { val style = if (isSelected) { - AllInTheme.typography.h3.copy( + AllInTheme.typography.sm1.copy( color = AllInTheme.themeColors.onMainSurface, fontSize = 15.sp, textAlign = TextAlign.Center, fontWeight = FontWeight.ExtraBold ) } else { - AllInTheme.typography.h3.copy( + AllInTheme.typography.sm1.copy( color = AllInTheme.themeColors.onBackground2, fontSize = 15.sp, textAlign = TextAlign.Center, diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSelectionBox.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSelectionBox.kt index c5be688..d88fd23 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSelectionBox.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInSelectionBox.kt @@ -6,8 +6,10 @@ import androidx.compose.animation.animateContentSize import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -29,6 +31,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import fr.iut.alldev.allin.R import fr.iut.alldev.allin.theme.AllInTheme @@ -36,11 +39,11 @@ import fr.iut.alldev.allin.theme.AllInTheme class SelectionElement( val textId: Int, - val imageVector: ImageVector, + val imageVector: ImageVector ) @Composable -fun AllInSelectionLine( +private fun AllInSelectionLine( text: String, iconVector: ImageVector?, modifier: Modifier = Modifier, @@ -91,13 +94,19 @@ fun AllInSelectionLine( fun AllInSelectionBox( modifier: Modifier = Modifier, isOpen: Boolean, + borderWidth: Dp? = null, setIsOpen: (Boolean) -> Unit, selected: SelectionElement?, setSelected: (SelectionElement) -> Unit, elements: List, ) { val interactionSource = remember { MutableInteractionSource() } - AllInCard(modifier.fillMaxWidth()) { + AllInCard( + modifier = modifier.fillMaxWidth(), + radius = 10.dp, + borderWidth = borderWidth, + borderColor = AllInTheme.colors.allInPurple.copy(alpha = .42f) + ) { Column( Modifier.animateContentSize() ) { @@ -154,6 +163,84 @@ private fun AllInSelectionBoxClosedPreview() { } } +@Composable +private fun AllInSelectionLine( + element: @Composable RowScope.() -> Unit, + modifier: Modifier = Modifier, + onClick: () -> Unit, + trailingIcon: ImageVector? = null, + interactionSource: MutableInteractionSource +) { + Row( + modifier = modifier + .fillMaxWidth() + .clickable( + interactionSource = interactionSource, + indication = null, + onClick = onClick + ) + .padding(horizontal = 12.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + element() + trailingIcon?.let { + Icon( + imageVector = trailingIcon, + contentDescription = null, + tint = AllInTheme.colors.allInPurple, + modifier = Modifier + .size(30.dp) + ) + } + } +} + +@Composable +fun AllInSelectionBox( + modifier: Modifier = Modifier, + isOpen: Boolean, + setIsOpen: (Boolean) -> Unit, + borderWidth: Dp? = null, + selected: (@Composable RowScope.() -> Unit)?, + setSelected: (@Composable RowScope.() -> Unit) -> Unit, + elements: List<@Composable RowScope.() -> Unit>, +) { + val interactionSource = remember { MutableInteractionSource() } + AllInCard( + modifier = modifier.fillMaxWidth(), + radius = 10.dp, + borderWidth = borderWidth, + borderColor = AllInTheme.colors.allInPurple.copy(alpha = .42f) + ) { + Column(Modifier.animateContentSize()) { + AllInSelectionLine( + element = selected ?: { Box { } }, + onClick = { setIsOpen(!isOpen) }, + interactionSource = interactionSource, + trailingIcon = with(Icons.Default) { + if (isOpen) ExpandLess else ExpandMore + } + ) + AnimatedVisibility(isOpen) { + Column { + HorizontalDivider(color = AllInTheme.themeColors.border) + elements.filter { it != selected }.forEach { element -> + AllInSelectionLine( + element = element, + interactionSource = interactionSource, + onClick = { + setSelected(element) + setIsOpen(false) + } + ) + } + } + } + } + } +} + @Preview @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextField.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextField.kt index a528297..c46d777 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextField.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextField.kt @@ -2,7 +2,6 @@ package fr.iut.alldev.allin.ui.core import android.content.res.Configuration import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.relocation.BringIntoViewRequester import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons @@ -11,35 +10,37 @@ import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.text.TextRange +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.text.input.* import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.core.os.ConfigurationCompat +import androidx.core.text.isDigitsOnly +import fr.iut.alldev.allin.ext.formatToSimple +import fr.iut.alldev.allin.ext.toFloatOrNull +import fr.iut.alldev.allin.ext.verifyIsFloat import fr.iut.alldev.allin.theme.AllInTheme -import kotlinx.coroutines.launch import racra.compose.smooth_corner_rect_library.AbsoluteSmoothCornerShape +import java.util.Locale @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable fun AllInTextField( - placeholder: String, - value: String, modifier: Modifier = Modifier, + placeholder: String? = null, + value: String, maxChar: Int? = null, enabled: Boolean = true, - trailingIcon: ImageVector? = null, - trailingContent: @Composable (() -> Unit)? = null, + trailingIcon: Painter? = null, + trailingContent: @Composable() (() -> Unit)? = null, placeholderFontSize: TextUnit = 18.sp, multiLine: Boolean = false, - onValueChange: (String) -> Unit, errorText: String? = null, - bringIntoViewRequester: BringIntoViewRequester, visualTransformation: VisualTransformation = VisualTransformation.None, keyboardType: KeyboardType = KeyboardType.Text, imeAction: ImeAction = ImeAction.Default, @@ -48,64 +49,44 @@ fun AllInTextField( containerColor: Color = AllInTheme.themeColors.background, textColor: Color = AllInTheme.themeColors.onMainSurface, placeholderColor: Color = AllInTheme.themeColors.onBackground2, + onValueChange: (String) -> Unit, ) { - val scope = rememberCoroutineScope() - var hasFocus by remember { mutableStateOf(false) } - - var textFieldValue by remember { - mutableStateOf(TextFieldValue(text = value, selection = TextRange(value.length))) - } - - LaunchedEffect(key1 = value, block = { - textFieldValue = TextFieldValue( - text = value, - selection = textFieldValue.selection - ) - }) - OutlinedTextField( - value = textFieldValue, + value = value, isError = errorText != null, - modifier = modifier - .onFocusChanged { - hasFocus = it.hasFocus - if (it.isFocused) { - scope.launch { - bringIntoViewRequester.bringIntoView() - } - } - }, + modifier = modifier, supportingText = errorText?.let { { AllInErrorLine(text = it) } }, visualTransformation = visualTransformation, singleLine = !multiLine, onValueChange = { - if (maxChar == null || it.text.length <= maxChar) { - textFieldValue = it - onValueChange(it.text) + if (maxChar == null || it.length <= maxChar) { + onValueChange(it) } }, - placeholder = { - Text( - text = placeholder, - fontSize = placeholderFontSize, - style = AllInTheme.typography.r, - color = placeholderColor, - maxLines = if (multiLine) 3 else 1, - overflow = TextOverflow.Ellipsis - ) + placeholder = placeholder?.let { + { + Text( + text = placeholder, + fontSize = placeholderFontSize, + style = AllInTheme.typography.p1, + color = placeholderColor, + maxLines = if (multiLine) 3 else 1, + overflow = TextOverflow.Ellipsis + ) + } }, trailingIcon = trailingContent ?: trailingIcon?.let { @Composable { Icon( - imageVector = it, + painter = it, contentDescription = null, tint = AllInTheme.colors.allInLightGrey300 ) } }, - textStyle = AllInTheme.typography.r, + textStyle = AllInTheme.typography.p1, enabled = enabled, keyboardOptions = KeyboardOptions(keyboardType = keyboardType, imeAction = imeAction), keyboardActions = keyboardActions, @@ -135,22 +116,13 @@ fun AllInPasswordField( keyboardActions: KeyboardActions = KeyboardActions.Default, errorText: String? = null, onValueChange: (String) -> Unit, - bringIntoViewRequester: BringIntoViewRequester, isHiddenByDefault: Boolean = true, ) { - var hidden by remember { - mutableStateOf(isHiddenByDefault) - } + var hidden by remember { mutableStateOf(isHiddenByDefault) } AllInTextField( - modifier = modifier, - errorText = errorText, placeholder = placeholder, - imeAction = imeAction, - keyboardActions = keyboardActions, - visualTransformation = if (hidden) PasswordVisualTransformation() else VisualTransformation.None, value = value, - onValueChange = onValueChange, - bringIntoViewRequester = bringIntoViewRequester, + modifier = modifier, trailingContent = { IconButton( onClick = { hidden = !hidden } @@ -162,10 +134,73 @@ fun AllInPasswordField( ) } }, - keyboardType = keyboardType + onValueChange = onValueChange, + errorText = errorText, + visualTransformation = if (hidden) PasswordVisualTransformation() else VisualTransformation.None, + keyboardType = keyboardType, + imeAction = imeAction, + keyboardActions = keyboardActions ) } +@Composable +fun AllInFloatTextfield( + modifier: Modifier = Modifier, + value: Float?, + setValue: (Float?) -> Unit +) { + val configuration = LocalConfiguration.current + val locale = remember { + ConfigurationCompat.getLocales(configuration).get(0) ?: Locale.getDefault() + } + var stringValue by remember(value) { mutableStateOf(value?.formatToSimple(locale) ?: "") } + + AllInTextField( + value = stringValue, + modifier = modifier, + maxChar = 5, + keyboardType = KeyboardType.Number + ) { + it.verifyIsFloat(locale)?.let { + stringValue = it + if (it.isNotEmpty()) { + if (it.lastOrNull() !in setOf(',', '.')) { + it.toFloatOrNull(locale)?.let { + setValue(it) + } + } + } else setValue(null) + } + } +} + +@Composable +fun AllInIntTextField( + modifier: Modifier = Modifier, + placeholder: String? = null, + maxChar: Int? = 3, + value: Int?, + trailingIcon: Painter? = null, + setValue: (Int?) -> Unit +) { + AllInTextField( + value = value?.toString() ?: "", + placeholder = placeholder, + modifier = modifier, + maxChar = maxChar, + trailingIcon = trailingIcon, + keyboardType = KeyboardType.NumberPassword + ) { + if (it.isEmpty()) setValue(null) + else if (it.isDigitsOnly()) { + it.toIntOrNull()?.let { + setValue(it) + } + } + } +} + + @OptIn(ExperimentalFoundationApi::class) @Preview @Composable @@ -174,8 +209,7 @@ private fun AllInTextFieldPlaceholderPreview() { AllInTextField( placeholder = "Email", value = "", - onValueChange = { }, - bringIntoViewRequester = BringIntoViewRequester() + onValueChange = { } ) } } @@ -190,8 +224,7 @@ private fun AllInTextFieldValuePreview() { AllInTextField( placeholder = "Email", value = "JohnDoe@mail.com", - onValueChange = { }, - bringIntoViewRequester = BringIntoViewRequester() + onValueChange = { } ) } } @@ -204,9 +237,8 @@ private fun AllInTextFieldErrorPreview() { AllInTextField( placeholder = "Email", value = "JohnDoe@mail.com", - errorText = "This is an error.", onValueChange = { }, - bringIntoViewRequester = BringIntoViewRequester() + errorText = "This is an error." ) } } @@ -220,13 +252,11 @@ private fun AllInTextFieldPasswordPreview() { AllInPasswordField( placeholder = "Password", value = value, - onValueChange = setValue, - bringIntoViewRequester = BringIntoViewRequester() + onValueChange = setValue ) } } -@OptIn(ExperimentalFoundationApi::class) @Preview @Composable private fun AllInTextFieldMultilinePreview() { @@ -234,9 +264,8 @@ private fun AllInTextFieldMultilinePreview() { AllInTextField( placeholder = "David sera il absent le Lundi matin en cours ?", value = "", - onValueChange = { }, multiLine = true, - bringIntoViewRequester = BringIntoViewRequester() + onValueChange = { } ) } } \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextIcon.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextIcon.kt index b12004e..3827926 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextIcon.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTextIcon.kt @@ -6,16 +6,17 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Fireplace -import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp @@ -34,6 +35,8 @@ fun AllInTextIcon( text: String, icon: Painter, color: Color, + brush: Brush? = null, + textStyle: TextStyle = AllInTheme.typography.h1, position: IconPosition = IconPosition.TRAILING, size: Int = 15, iconSize: Int = size, @@ -52,54 +55,15 @@ fun AllInTextIcon( Text( text = text, color = color, - style = AllInTheme.typography.h1, + style = brush?.let { textStyle.copy(brush = it) } ?: textStyle, fontSize = size.sp ) Icon( painter = icon, contentDescription = null, modifier = Modifier.size(iconSize.dp), - tint = color - ) - } - } - } -} - - -@Composable -fun AllInTextIcon( - modifier: Modifier = Modifier, - text: String, - icon: ImageVector, - color: Color, - position: IconPosition = IconPosition.TRAILING, - size: Int = 15, - iconSize: Int = size, -) { - val direction = - if (position == IconPosition.LEADING) LayoutDirection.Rtl - else LayoutDirection.Ltr - Box(modifier) { - CompositionLocalProvider( - LocalLayoutDirection provides direction - ) { - Row( - modifier = modifier, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(7.dp) - ) { - Text( - text = text, - color = color, - style = AllInTheme.typography.h1, - fontSize = size.sp - ) - Icon( - imageVector = icon, - contentDescription = null, - modifier = Modifier.size(iconSize.dp), - tint = color + tint = color, + brush = brush ) } } @@ -112,7 +76,7 @@ private fun AllInTextIconPreview() { AllInTheme { AllInTextIcon( text = "value", - icon = Icons.Default.Fireplace, + icon = rememberVectorPainter(image = Icons.Default.Fireplace), color = AllInTheme.colors.allInBlue ) } @@ -126,6 +90,7 @@ private fun AllInTextIconReversePreview() { text = "value", icon = AllInTheme.icons.allCoins(), color = AllInTheme.colors.allInBlue, + brush = AllInTheme.colors.allInMainGradient, position = IconPosition.LEADING ) } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTimePicker.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTimePicker.kt index 5ddcdc5..b78e0d2 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTimePicker.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTimePicker.kt @@ -46,7 +46,7 @@ fun AllInTimePicker( Text( text = stringResource(id = R.string.Cancel), color = AllInTheme.themeColors.onBackground2, - style = AllInTheme.typography.h3 + style = AllInTheme.typography.sm1 ) } }, diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTooltip.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTooltip.kt index bf5123a..5254aa6 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTooltip.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/AllInTooltip.kt @@ -31,7 +31,7 @@ fun AllInTooltip( Text( text = text, color = AllInTheme.colors.allInLightGrey200, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, fontSize = 12.sp ) } @@ -121,7 +121,7 @@ private fun AllInTooltipPreview() { Text( text = "Généralement une question qui sera répondu par les utilisateurs.", color = AllInTheme.colors.allInLightGrey200, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, fontSize = 10.sp ) }) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/Icon.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/Icon.kt new file mode 100644 index 0000000..6ccb149 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/Icon.kt @@ -0,0 +1,38 @@ +package fr.iut.alldev.allin.ui.core + +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.graphics.BlendMode +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.CompositingStrategy +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.graphics.painter.Painter + +@Composable +fun Icon( + painter: Painter, + contentDescription: String?, + modifier: Modifier = Modifier, + tint: Color = LocalContentColor.current, + brush: Brush? = null, +) { + Icon( + painter = painter, + contentDescription = contentDescription, + modifier = brush?.let { + modifier + .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } + .drawWithCache { + onDrawWithContent { + drawContent() + drawRect(brush, blendMode = BlendMode.SrcAtop) + } + } + } ?: modifier, + tint = tint + ) +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetCard.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetCard.kt new file mode 100644 index 0000000..a7e6613 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetCard.kt @@ -0,0 +1,76 @@ +package fr.iut.alldev.allin.ui.core.bet + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.ext.getDateStartLabelId +import fr.iut.alldev.allin.theme.AllInTheme +import fr.iut.alldev.allin.ui.core.AllInCard + +@Composable +fun BetCard( + modifier: Modifier = Modifier, + title: String, + creator: String, + category: String, + date: String, + time: String, + status: BetStatus, + content: @Composable () -> Unit +) { + AllInCard( + modifier = modifier.fillMaxWidth(), + radius = 16.dp + ) { + Column( + Modifier.padding(horizontal = 19.dp, vertical = 11.dp) + ) { + BetTitleHeader( + title = title, + category = category, + creator = creator, + modifier = Modifier.fillMaxWidth() + ) + Spacer(modifier = Modifier.height(11.dp)) + BetDateTimeRow( + label = stringResource(id = status.getDateStartLabelId()), + date = date, + time = time + ) + } + HorizontalDivider( + thickness = 1.dp, + color = AllInTheme.themeColors.border + ) + content() + } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun BetCardPreview() { + AllInTheme { + BetCard( + creator = "Creator", + category = "Category", + title = "Title", + date = "Date", + time = "Time", + status = BetStatus.Waiting + ){ + Text("Content") + } + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetDateTimeChip.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetDateTimeChip.kt index b6e9bea..256d170 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetDateTimeChip.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetDateTimeChip.kt @@ -29,7 +29,7 @@ fun BetDateTimeChip( Text( text = text, modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp), - style = AllInTheme.typography.h3, + style = AllInTheme.typography.sm1, textAlign = TextAlign.Center, color = AllInTheme.colors.allInPurple ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetDateTimeRow.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetDateTimeRow.kt index e8d99d5..1dccea0 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetDateTimeRow.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetDateTimeRow.kt @@ -27,7 +27,7 @@ fun BetDateTimeRow( Text( text = label, fontSize = 15.sp, - style = AllInTheme.typography.m, + style = AllInTheme.typography.sm2, color = AllInTheme.themeColors.onBackground2 ) BetDateTimeChip(date) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetTitleHeader.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetTitleHeader.kt index a732e02..41a7743 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetTitleHeader.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/bet/BetTitleHeader.kt @@ -38,7 +38,7 @@ fun BetTitleHeader( color = AllInTheme.themeColors.onMainSurface ), fontSize = 12.sp, - style = AllInTheme.typography.s, + style = AllInTheme.typography.p2, color = AllInTheme.themeColors.onBackground2 ) } @@ -47,7 +47,7 @@ fun BetTitleHeader( text = category, fontSize = 15.sp, color = AllInTheme.themeColors.onBackground2, - style = AllInTheme.typography.m + style = AllInTheme.typography.sm2 ) Text( text = title, diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/snackbar/AllInSnackBar.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/snackbar/AllInSnackBar.kt index d9b2129..5e69ace 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/core/snackbar/AllInSnackBar.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/core/snackbar/AllInSnackBar.kt @@ -105,7 +105,7 @@ fun AllInSnackbarContent( Text( text = text, color = contentColor, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, overflow = TextOverflow.Ellipsis, maxLines = 5, modifier = Modifier.weight(1f) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/login/LoginScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/login/LoginScreen.kt index dea639f..87c04bb 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/login/LoginScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/login/LoginScreen.kt @@ -1,6 +1,5 @@ package fr.iut.alldev.allin.ui.login -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -11,12 +10,10 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.relocation.BringIntoViewRequester import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.ClickableText import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -42,7 +39,6 @@ import fr.iut.alldev.allin.ui.core.AllInLoading import fr.iut.alldev.allin.ui.core.AllInPasswordField import fr.iut.alldev.allin.ui.core.AllInTextField -@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable fun LoginScreen( navigateToDashboard: () -> Unit, @@ -51,7 +47,6 @@ fun LoginScreen( ) { val focusManager = LocalFocusManager.current - val bringIntoViewRequester = BringIntoViewRequester() val loading by remember { loginViewModel.loading } var hasLoginError by remember { loginViewModel.hasError } @@ -84,7 +79,7 @@ fun LoginScreen( modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.Login_title), color = AllInTheme.themeColors.onMainSurface, - style = AllInTheme.typography.h3, + style = AllInTheme.typography.sm1, textAlign = TextAlign.Center, fontSize = 40.sp ) @@ -93,7 +88,7 @@ fun LoginScreen( modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.Login_subtitle), color = AllInTheme.themeColors.onMainSurface, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, textAlign = TextAlign.Center, fontSize = 23.sp ) @@ -102,27 +97,25 @@ fun LoginScreen( verticalArrangement = Arrangement.spacedBy(20.dp) ) { AllInTextField( - modifier = Modifier.fillMaxWidth(), placeholder = stringResource(id = R.string.username), value = username, + modifier = Modifier.fillMaxWidth(), onValueChange = setUsername, - bringIntoViewRequester = bringIntoViewRequester, imeAction = ImeAction.Next, keyboardActions = keyboardActions ) AllInPasswordField( - modifier = Modifier.fillMaxWidth(), placeholder = stringResource(id = R.string.password), value = password, - onValueChange = setPassword, - bringIntoViewRequester = bringIntoViewRequester, + modifier = Modifier.fillMaxWidth(), imeAction = ImeAction.Done, - keyboardActions = keyboardActions + keyboardActions = keyboardActions, + onValueChange = setPassword ) } ClickableText( text = AnnotatedString(stringResource(id = R.string.forgot_password)), - style = AllInTheme.typography.m.copy( + style = AllInTheme.typography.sm2.copy( color = AllInTheme.themeColors.onMainSurface, fontSize = 15.sp, ), @@ -156,12 +149,12 @@ fun LoginScreen( text = stringResource(id = R.string.no_account), color = AllInTheme.themeColors.onMainSurface, fontSize = 15.sp, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, modifier = Modifier.padding(end = 5.dp) ) ClickableText( text = AnnotatedString(stringResource(id = R.string.Register)), - style = AllInTheme.typography.r.copy( + style = AllInTheme.typography.p1.copy( color = AllInTheme.colors.allInPurple, fontSize = 15.sp, fontWeight = FontWeight.Bold diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainScreen.kt index c55cad1..fdd9642 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainScreen.kt @@ -11,8 +11,9 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import fr.iut.alldev.allin.theme.AllInTheme +import fr.iut.alldev.allin.ui.betResult.BetResultBottomSheet import fr.iut.alldev.allin.ui.betStatus.BetStatusBottomSheet -import fr.iut.alldev.allin.ui.betStatus.visitor.BetStatusBottomSheetDisplayBetVisitor +import fr.iut.alldev.allin.ui.betStatus.vo.BetStatusBottomSheetBetDisplayer import fr.iut.alldev.allin.ui.core.AllInLoading import fr.iut.alldev.allin.ui.core.snackbar.AllInSnackbarVisualsImpl import fr.iut.alldev.allin.ui.main.components.AllInScaffold @@ -21,7 +22,6 @@ import fr.iut.alldev.allin.ui.navigation.Routes import fr.iut.alldev.allin.ui.navigation.TopLevelDestination import fr.iut.alldev.allin.ui.navigation.drawer.AllInDrawer import fr.iut.alldev.allin.ui.navigation.popUpTo -import fr.iut.alldev.allin.vo.bet.factory.toBetVO import kotlinx.coroutines.launch private val topLevelDestinations = listOf( @@ -67,15 +67,18 @@ fun MainScreen( var loading by remember { mainViewModel.loading } val currentUser = remember { mainViewModel.currentUserState } - val (selectedBet, setSelectedBet) = remember { mainViewModel.selectedBet } + val selectedBet by remember { mainViewModel.selectedBet } + val (wonBet, setWonBet) = remember { mainViewModel.wonBet } val (statusVisibility, sheetBackVisibility, setStatusVisibility) = rememberBetStatusVisibilities() + val (participateSheetVisibility, setParticipateSheetVisibility) = remember { + mutableStateOf(false) + } - val betStatusDisplayVisitor = remember { - BetStatusBottomSheetDisplayBetVisitor( - userCoinAmount = currentUser.userCoins, - onParticipate = { - mainViewModel.participateToBet(it) - } + val (displayResult, setDisplayResult) = remember { mutableStateOf(true) } + + val betStatusDisplayer = remember { + BetStatusBottomSheetBetDisplayer( + openParticipateSheet = { setParticipateSheetVisibility(true) } ) } @@ -100,7 +103,7 @@ fun MainScreen( } } - val bottomSheetState = rememberModalBottomSheetState( + val statusBottomSheetState = rememberModalBottomSheetState( skipPartiallyExpanded = true, confirmValueChange = { if (it == SheetValue.Hidden) { @@ -110,6 +113,10 @@ fun MainScreen( } ) + val resultBottomSheetState = rememberModalBottomSheetState( + skipPartiallyExpanded = true + ) + AllInDrawer( drawerState = drawerState, destinations = topLevelDestinations, @@ -133,7 +140,7 @@ fun MainScreen( snackbarHostState = snackbarHostState ) { LaunchedEffect(key1 = it) { - betStatusDisplayVisitor.paddingValues.value = it + betStatusDisplayer.paddingValues.value = it } Column( modifier = Modifier @@ -145,8 +152,8 @@ fun MainScreen( AllInDrawerNavHost( navController = navController, selectBet = { bet, participate -> - setSelectedBet(bet) - betStatusDisplayVisitor.participateBottomSheetVisibility.value = participate + mainViewModel.openBetDetail(bet) + setParticipateSheetVisibility(participate) setStatusVisibility(true) }, setLoading = { loading = it }, @@ -156,15 +163,32 @@ fun MainScreen( } } + wonBet?.let { + BetResultBottomSheet( + state = resultBottomSheetState, + sheetVisibility = displayResult, + onDismiss = { setDisplayResult(false) }, + bet = wonBet, + username = currentUser.user.username, + coinAmount = 1630, + stake = 1630, + winnings = 1630, + odds = 3.62f + ) + } + BetStatusBottomSheet( - state = bottomSheetState, + state = statusBottomSheetState, sheetVisibility = statusVisibility.value, sheetBackVisibility = sheetBackVisibility.value, - onDismiss = { - setStatusVisibility(false) - }, - bet = selectedBet?.toBetVO(), - visitor = betStatusDisplayVisitor + onDismiss = { setStatusVisibility(false) }, + betDetail = selectedBet, + paddingValues = betStatusDisplayer.paddingValues.value, + displayBet = { betStatusDisplayer.DisplayBet(it) }, + userCoinAmount = mainViewModel.currentUserState.userCoins, + onParticipate = { stake, response -> mainViewModel.participateToBet(stake, response) }, + participateSheetVisibility = participateSheetVisibility, + setParticipateSheetVisibility = setParticipateSheetVisibility ) AllInLoading(visible = loading) BackHandler( diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainViewModel.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainViewModel.kt index 33d7f3e..a666bef 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainViewModel.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/main/MainViewModel.kt @@ -8,6 +8,9 @@ import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import fr.iut.alldev.allin.data.model.User import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.Participation +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail +import fr.iut.alldev.allin.data.repository.BetRepository import fr.iut.alldev.allin.di.AllInCurrentUser import fr.iut.alldev.allin.keystore.AllInKeystoreManager import fr.iut.alldev.allin.ui.core.snackbar.SnackbarType @@ -23,19 +26,38 @@ class UserState(val user: User) { @HiltViewModel class MainViewModel @Inject constructor( @AllInCurrentUser val currentUser: User, + private val betRepository: BetRepository, private val keystoreManager: AllInKeystoreManager ) : ViewModel() { var loading = mutableStateOf(false) val currentUserState = UserState(currentUser) - val selectedBet = mutableStateOf(null) + val selectedBet = mutableStateOf(null) + val wonBet = mutableStateOf( + null + /* YesNoBet( + id = "1", + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.Finished(BetFinishedStatus.WON), + creator = "creator" + )*/ + ) val snackbarContent: MutableState by lazy { mutableStateOf(null) } fun putSnackbarContent(content: SnackbarContent) { snackbarContent.value = content } + fun openBetDetail(bet: Bet) { + viewModelScope.launch { + selectedBet.value = betRepository.getBet(bet.id, keystoreManager.getToken() ?: "") + } + } fun deleteToken() { viewModelScope.launch { @@ -43,12 +65,20 @@ class MainViewModel @Inject constructor( } } - fun participateToBet(stake: Int) { + fun participateToBet(stake: Int, response: String) { viewModelScope.launch { withContext(Dispatchers.IO) { loading.value = true - currentUserState.userCoins.intValue += 50 - Thread.sleep(1000) + currentUserState.userCoins.intValue -= stake + selectedBet.value?.bet?.let { + val participation = Participation( + betId = it.id, + username = currentUser.username, + response = response, + stake = stake + ) + betRepository.participateToBet(participation, keystoreManager.getToken() ?: "") + } loading.value = false } } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/AllInDrawer.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/AllInDrawer.kt index a86410f..c9442ae 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/AllInDrawer.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/AllInDrawer.kt @@ -74,7 +74,7 @@ fun AllInDrawer( ) { Text( text = stringResource(id = R.string.Logout), - style = AllInTheme.typography.h3, + style = AllInTheme.typography.sm1, color = AllInTheme.colors.allInDarkGrey50, fontSize = 16.sp ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/components/DrawerCell.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/components/DrawerCell.kt index 2d40781..392d9ce 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/components/DrawerCell.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/components/DrawerCell.kt @@ -56,7 +56,7 @@ fun DrawerCell( ) Text( text = subtitle, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, fontSize = 9.sp, color = AllInTheme.colors.allInLightGrey300, ) diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/components/DrawerHeaderStat.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/components/DrawerHeaderStat.kt index 4d302c6..33a5bf3 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/components/DrawerHeaderStat.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/navigation/drawer/components/DrawerHeaderStat.kt @@ -23,7 +23,7 @@ fun DrawerHeaderStat( Text( text = label, color = AllInTheme.colors.allInLightGrey300, - style = AllInTheme.typography.r + style = AllInTheme.typography.p1 ) } } diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetDetailPreviewProvider.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetDetailPreviewProvider.kt new file mode 100644 index 0000000..154f04c --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetDetailPreviewProvider.kt @@ -0,0 +1,58 @@ +package fr.iut.alldev.allin.ui.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import fr.iut.alldev.allin.data.model.bet.NO_VALUE +import fr.iut.alldev.allin.data.model.bet.Participation +import fr.iut.alldev.allin.data.model.bet.YES_VALUE +import fr.iut.alldev.allin.data.model.bet.vo.BetAnswerDetail +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail + +class BetDetailPreviewProvider : PreviewParameterProvider { + override val values = BetWithStatusPreviewProvider().values.map { + BetDetail( + bet = it, + answers = listOf( + BetAnswerDetail( + response = YES_VALUE, + totalStakes = 300, + totalParticipants = 2, + highestStake = 200, + odds = 1.0f + ), + BetAnswerDetail( + response = NO_VALUE, + totalStakes = 150, + totalParticipants = 1, + highestStake = 150, + odds = 2.0f + ), + ), + participations = listOf( + Participation( + betId = it.id, + username = "User1", + response = YES_VALUE, + stake = 200 + ), + Participation( + betId = it.id, + username = "User2", + response = YES_VALUE, + stake = 100 + ), + Participation( + betId = it.id, + username = "MyUser", + response = NO_VALUE, + stake = 150 + ) + ), + userParticipation = Participation( + betId = it.id, + username = "MyUser", + response = NO_VALUE, + stake = 150 + ) + ) + } +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetPreviewProvider.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetPreviewProvider.kt new file mode 100644 index 0000000..3a97a59 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetPreviewProvider.kt @@ -0,0 +1,54 @@ +package fr.iut.alldev.allin.ui.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus +import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.data.model.bet.CustomBet +import fr.iut.alldev.allin.data.model.bet.MatchBet +import fr.iut.alldev.allin.data.model.bet.YesNoBet +import java.time.ZonedDateTime + +class BetPreviewProvider : PreviewParameterProvider { + override val values = sequenceOf( + YesNoBet( + id = "1", + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.Finished(BetFinishedStatus.WON), + creator = "creator" + ), + MatchBet( + id = "2", + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.Finished(BetFinishedStatus.WON), + creator = "creator", + nameTeam1 = "The Monarchs", + nameTeam2 = "Climate Change" + ), + CustomBet( + id = "3", + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = BetStatus.Finished(BetFinishedStatus.WON), + creator = "creator", + possibleAnswers = listOf( + "Answer 1", + "Answer 2", + "Answer 3", + "Answer 4" + ) + + ), + ) +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetStatus.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetStatus.kt deleted file mode 100644 index f0de24e..0000000 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetStatus.kt +++ /dev/null @@ -1,14 +0,0 @@ -package fr.iut.alldev.allin.ui.preview - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus -import fr.iut.alldev.allin.data.model.bet.BetStatus - -class BetStatusPreviewProvider: PreviewParameterProvider { - override val values = sequenceOf( - BetStatus.InProgress, - BetStatus.Waiting, - BetStatus.Finished(BetFinishedStatus.WON), - BetStatus.Finished(BetFinishedStatus.LOST) - ) -} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetStatusPreviewProvider.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetStatusPreviewProvider.kt new file mode 100644 index 0000000..ccb3cd8 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetStatusPreviewProvider.kt @@ -0,0 +1,8 @@ +package fr.iut.alldev.allin.ui.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import fr.iut.alldev.allin.data.model.bet.BetStatus + +class BetStatusPreviewProvider : PreviewParameterProvider { + override val values = BetStatus.entries +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetWithStatusPreviewProvider.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetWithStatusPreviewProvider.kt new file mode 100644 index 0000000..e5b3721 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/preview/BetWithStatusPreviewProvider.kt @@ -0,0 +1,56 @@ +package fr.iut.alldev.allin.ui.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.data.model.bet.CustomBet +import fr.iut.alldev.allin.data.model.bet.MatchBet +import fr.iut.alldev.allin.data.model.bet.YesNoBet +import java.time.ZonedDateTime + + +class BetWithStatusPreviewProvider : PreviewParameterProvider { + override val values = BetStatus.entries.flatMap { status -> + sequenceOf( + YesNoBet( + id = "1", + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = status, + creator = "creator" + ), + MatchBet( + id = "2", + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = status, + creator = "creator", + nameTeam1 = "The Monarchs", + nameTeam2 = "Climate Change" + ), + CustomBet( + id = "3", + theme = "Theme", + phrase = "Phrase", + endRegisterDate = ZonedDateTime.now(), + endBetDate = ZonedDateTime.now(), + isPublic = true, + betStatus = status, + creator = "creator", + possibleAnswers = listOf( + "Answer 1", + "Answer 2", + "Answer 3", + "Answer 4" + ) + + ) + ) + } +} diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/register/RegisterScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/register/RegisterScreen.kt index 35d3258..a00754b 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/register/RegisterScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/register/RegisterScreen.kt @@ -2,7 +2,6 @@ package fr.iut.alldev.allin.ui.register import androidx.compose.foundation.* import androidx.compose.foundation.layout.* -import androidx.compose.foundation.relocation.BringIntoViewRequester import androidx.compose.foundation.text.ClickableText import androidx.compose.foundation.text.KeyboardActions import androidx.compose.material3.Text @@ -49,7 +48,6 @@ fun RegisterScreen( val (password, setPassword) = remember { registerViewModel.password } val (passwordValidation, setPasswordValidation) = remember { registerViewModel.passwordValidation } - val bringIntoViewRequester = remember { BringIntoViewRequester() } val scrollState = rememberScrollState() val usernameFieldName = stringResource(id = R.string.username) @@ -89,7 +87,7 @@ fun RegisterScreen( modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.Hello_x, username), color = AllInTheme.themeColors.onMainSurface, - style = AllInTheme.typography.h3, + style = AllInTheme.typography.sm1, textAlign = TextAlign.Center, fontSize = 40.sp, overflow = TextOverflow.Ellipsis, @@ -99,7 +97,7 @@ fun RegisterScreen( modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.Register_title), color = AllInTheme.themeColors.onMainSurface, - style = AllInTheme.typography.h3, + style = AllInTheme.typography.sm1, textAlign = TextAlign.Center, fontSize = 40.sp ) @@ -108,7 +106,7 @@ fun RegisterScreen( modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.Register_subtitle), color = AllInTheme.themeColors.onMainSurface, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, textAlign = TextAlign.Center, fontSize = 23.sp ) @@ -117,46 +115,42 @@ fun RegisterScreen( verticalArrangement = Arrangement.spacedBy(20.dp) ) { AllInTextField( - modifier = Modifier.fillMaxWidth(), placeholder = usernameFieldName, value = username, - onValueChange = setUsername, + modifier = Modifier.fillMaxWidth(), maxChar = 20, + onValueChange = setUsername, errorText = usernameError.errorResource(), - bringIntoViewRequester = bringIntoViewRequester, imeAction = ImeAction.Next, keyboardActions = keyboardActions ) AllInTextField( - modifier = Modifier.fillMaxWidth(), placeholder = emailFieldName, value = email, + modifier = Modifier.fillMaxWidth(), onValueChange = setEmail, errorText = emailError.errorResource(), keyboardType = KeyboardType.Email, - bringIntoViewRequester = bringIntoViewRequester, imeAction = ImeAction.Next, keyboardActions = keyboardActions ) AllInPasswordField( - modifier = Modifier.fillMaxWidth(), placeholder = passwordFieldName, value = password, - errorText = passwordError.errorResource(), - onValueChange = setPassword, - bringIntoViewRequester = bringIntoViewRequester, + modifier = Modifier.fillMaxWidth(), imeAction = ImeAction.Next, - keyboardActions = keyboardActions + keyboardActions = keyboardActions, + errorText = passwordError.errorResource(), + onValueChange = setPassword ) AllInPasswordField( - modifier = Modifier.fillMaxWidth(), placeholder = stringResource(id = R.string.confirm_password), value = passwordValidation, - errorText = passwordValidationError.errorResource(), - onValueChange = setPasswordValidation, - bringIntoViewRequester = bringIntoViewRequester, + modifier = Modifier.fillMaxWidth(), imeAction = ImeAction.Done, - keyboardActions = keyboardActions + keyboardActions = keyboardActions, + errorText = passwordValidationError.errorResource(), + onValueChange = setPasswordValidation ) } } @@ -184,12 +178,12 @@ fun RegisterScreen( text = stringResource(id = R.string.already_have_account), color = AllInTheme.themeColors.onMainSurface, fontSize = 15.sp, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, modifier = Modifier.padding(end = 5.dp) ) ClickableText( text = AnnotatedString(stringResource(id = R.string.Login)), - style = AllInTheme.typography.r.copy( + style = AllInTheme.typography.p1.copy( color = AllInTheme.colors.allInPurple, fontSize = 15.sp, fontWeight = FontWeight.Bold diff --git a/src/app/src/main/java/fr/iut/alldev/allin/ui/welcome/WelcomeScreen.kt b/src/app/src/main/java/fr/iut/alldev/allin/ui/welcome/WelcomeScreen.kt index 99f3ae4..c805f3c 100644 --- a/src/app/src/main/java/fr/iut/alldev/allin/ui/welcome/WelcomeScreen.kt +++ b/src/app/src/main/java/fr/iut/alldev/allin/ui/welcome/WelcomeScreen.kt @@ -88,7 +88,7 @@ fun WelcomeScreen( text = stringResource(id = R.string.welcome_subtitle), color = AllInTheme.themeColors.onBackground, fontSize = 15.sp, - style = AllInTheme.typography.r + style = AllInTheme.typography.p1 ) Spacer(modifier = Modifier.height(78.dp)) AllInButton( @@ -106,12 +106,12 @@ fun WelcomeScreen( text = stringResource(id = R.string.already_have_account), color = AllInTheme.themeColors.tint1, fontSize = 15.sp, - style = AllInTheme.typography.r, + style = AllInTheme.typography.p1, modifier = Modifier.padding(end = 5.dp) ) ClickableText( text = AnnotatedString(stringResource(id = R.string.Login)), - style = AllInTheme.typography.r.copy( + style = AllInTheme.typography.p1.copy( color = AllInTheme.themeColors.tint1, fontSize = 15.sp, fontWeight = FontWeight.Bold diff --git a/src/app/src/main/java/fr/iut/alldev/allin/utils/Tuples.kt b/src/app/src/main/java/fr/iut/alldev/allin/utils/Tuples.kt deleted file mode 100644 index 922ca6e..0000000 --- a/src/app/src/main/java/fr/iut/alldev/allin/utils/Tuples.kt +++ /dev/null @@ -1,12 +0,0 @@ -package fr.iut.alldev.allin.utils - -import java.io.Serializable - -data class Quadruple( - val first: A, - val second: B, - val third: C, - val fourth: D -) : Serializable { - override fun toString(): String = "($first, $second, $third, $fourth)" -} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/ViewObject.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/ViewObject.kt deleted file mode 100644 index ebd8358..0000000 --- a/src/app/src/main/java/fr/iut/alldev/allin/vo/ViewObject.kt +++ /dev/null @@ -1,8 +0,0 @@ -package fr.iut.alldev.allin.vo - -import androidx.compose.runtime.Composable - -interface ViewObject{ - @Composable - fun Accept(v: V) -} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/Visitor.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/Visitor.kt deleted file mode 100644 index 00aa0a2..0000000 --- a/src/app/src/main/java/fr/iut/alldev/allin/vo/Visitor.kt +++ /dev/null @@ -1,3 +0,0 @@ -package fr.iut.alldev.allin.vo - -interface Visitor \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/BetDisplayer.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/BetDisplayer.kt new file mode 100644 index 0000000..40b2cb8 --- /dev/null +++ b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/BetDisplayer.kt @@ -0,0 +1,27 @@ +package fr.iut.alldev.allin.vo.bet + +import androidx.compose.runtime.Composable +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.YesNoBet +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail + +interface BetDisplayer { + @Composable + fun DisplayBet(betDetail: BetDetail) { + when (betDetail.bet) { + is CustomBet -> DisplayCustomBet(betDetail) + is MatchBet -> DisplayMatchBet(betDetail) + is YesNoBet -> DisplayYesNoBet(betDetail) + } + } + + @Composable + fun DisplayYesNoBet(betDetail: BetDetail) + + @Composable + fun DisplayMatchBet(betDetail: BetDetail) + + @Composable + fun DisplayCustomBet(betDetail: BetDetail) +} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/BetVO.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/BetVO.kt deleted file mode 100644 index 5df8223..0000000 --- a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/BetVO.kt +++ /dev/null @@ -1,28 +0,0 @@ -package fr.iut.alldev.allin.vo.bet - -import androidx.compose.runtime.Composable -import fr.iut.alldev.allin.data.model.bet.Bet -import fr.iut.alldev.allin.data.model.bet.MatchBet -import fr.iut.alldev.allin.data.model.bet.YesNoBet -import fr.iut.alldev.allin.vo.ViewObject -import fr.iut.alldev.allin.vo.bet.visitor.DisplayBetVisitor - -abstract class BetVO(val bet: T) -: ViewObject { - @Composable - abstract override fun Accept(v: DisplayBetVisitor) -} - -class YesNoBetVO(bet: YesNoBet) : BetVO(bet){ - @Composable - override fun Accept(v: DisplayBetVisitor){ - v.VisitYesNoBet(b = bet) - } -} - -class MatchBetVO(bet: MatchBet) : BetVO(bet){ - @Composable - override fun Accept(v: DisplayBetVisitor){ - v.VisitMatchBet(b = bet) - } -} \ No newline at end of file diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/factory/BetVOFactory.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/factory/BetVOFactory.kt deleted file mode 100644 index 90cbf02..0000000 --- a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/factory/BetVOFactory.kt +++ /dev/null @@ -1,30 +0,0 @@ -package fr.iut.alldev.allin.vo.bet.factory - -import fr.iut.alldev.allin.data.model.bet.Bet -import fr.iut.alldev.allin.data.model.bet.MatchBet -import fr.iut.alldev.allin.data.model.bet.YesNoBet -import fr.iut.alldev.allin.vo.bet.BetVO -import fr.iut.alldev.allin.vo.bet.MatchBetVO -import fr.iut.alldev.allin.vo.bet.YesNoBetVO - -private val betTypeToVOMap = mapOf( - YesNoBet::class.java to YesNoBetVOFactory(), - MatchBet::class.java to MatchBetVOFactory() -) -abstract class BetVOFactory { - abstract fun create(bet: @UnsafeVariance T): BetVO<@UnsafeVariance T> -} - -class YesNoBetVOFactory : BetVOFactory() { - override fun create(bet: YesNoBet) = - YesNoBetVO(bet) -} - -class MatchBetVOFactory : BetVOFactory() { - override fun create(bet: MatchBet) = - MatchBetVO(bet) -} - -fun Bet.toBetVO() = betTypeToVOMap[this.javaClass]?.create(this) - - diff --git a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/visitor/BetVisitor.kt b/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/visitor/BetVisitor.kt deleted file mode 100644 index 7c8f584..0000000 --- a/src/app/src/main/java/fr/iut/alldev/allin/vo/bet/visitor/BetVisitor.kt +++ /dev/null @@ -1,15 +0,0 @@ -package fr.iut.alldev.allin.vo.bet.visitor - -import androidx.compose.runtime.Composable -import fr.iut.alldev.allin.data.model.bet.MatchBet -import fr.iut.alldev.allin.data.model.bet.YesNoBet -import fr.iut.alldev.allin.vo.Visitor - - -interface DisplayBetVisitor : Visitor { - @Composable - fun VisitYesNoBet(b: YesNoBet) - - @Composable - fun VisitMatchBet(b: MatchBet) -} \ No newline at end of file diff --git a/src/app/src/main/res/drawable/allin_marquee.xml b/src/app/src/main/res/drawable/allin_marquee.xml new file mode 100644 index 0000000..fbd7a45 --- /dev/null +++ b/src/app/src/main/res/drawable/allin_marquee.xml @@ -0,0 +1,4307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/src/main/res/font/plusjakartasans_bold.ttf b/src/app/src/main/res/font/plusjakartasans_bold.ttf deleted file mode 100644 index 386d3a6..0000000 Binary files a/src/app/src/main/res/font/plusjakartasans_bold.ttf and /dev/null differ diff --git a/src/app/src/main/res/font/plusjakartasans_extrabold.ttf b/src/app/src/main/res/font/plusjakartasans_extrabold.ttf deleted file mode 100644 index a67cafd..0000000 Binary files a/src/app/src/main/res/font/plusjakartasans_extrabold.ttf and /dev/null differ diff --git a/src/app/src/main/res/font/plusjakartasans_extralight.ttf b/src/app/src/main/res/font/plusjakartasans_extralight.ttf deleted file mode 100644 index bb43929..0000000 Binary files a/src/app/src/main/res/font/plusjakartasans_extralight.ttf and /dev/null differ diff --git a/src/app/src/main/res/font/plusjakartasans_light.ttf b/src/app/src/main/res/font/plusjakartasans_light.ttf deleted file mode 100644 index 215db16..0000000 Binary files a/src/app/src/main/res/font/plusjakartasans_light.ttf and /dev/null differ diff --git a/src/app/src/main/res/font/plusjakartasans_medium.ttf b/src/app/src/main/res/font/plusjakartasans_medium.ttf deleted file mode 100644 index 1e58066..0000000 Binary files a/src/app/src/main/res/font/plusjakartasans_medium.ttf and /dev/null differ diff --git a/src/app/src/main/res/font/plusjakartasans_regular.ttf b/src/app/src/main/res/font/plusjakartasans_regular.ttf deleted file mode 100644 index 1e77059..0000000 Binary files a/src/app/src/main/res/font/plusjakartasans_regular.ttf and /dev/null differ diff --git a/src/app/src/main/res/font/plusjakartasans_semibold.ttf b/src/app/src/main/res/font/plusjakartasans_semibold.ttf deleted file mode 100644 index 49817ef..0000000 Binary files a/src/app/src/main/res/font/plusjakartasans_semibold.ttf and /dev/null differ diff --git a/src/app/src/main/res/values-fr/strings.xml b/src/app/src/main/res/values-fr/strings.xml index 07009f3..0f1e299 100644 --- a/src/app/src/main/res/values-fr/strings.xml +++ b/src/app/src/main/res/values-fr/strings.xml @@ -118,6 +118,7 @@ En cours… En attente… Faites vos paris + Liste des participants En cours @@ -126,4 +127,10 @@ %s [icon] gagnés ! %s [icon] perdus ! + + FÉLICITATIONS + Vous remportez + Cote totale + Mise + Gains \ No newline at end of file diff --git a/src/app/src/main/res/values/font_certs.xml b/src/app/src/main/res/values/font_certs.xml new file mode 100644 index 0000000..141bfc0 --- /dev/null +++ b/src/app/src/main/res/values/font_certs.xml @@ -0,0 +1,17 @@ + + + + @array/com_google_android_gms_fonts_certs_dev + @array/com_google_android_gms_fonts_certs_prod + + + + MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs= + + + + + MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK + + + \ No newline at end of file diff --git a/src/app/src/main/res/values/strings.xml b/src/app/src/main/res/values/strings.xml index bf11bd0..328e981 100644 --- a/src/app/src/main/res/values/strings.xml +++ b/src/app/src/main/res/values/strings.xml @@ -118,6 +118,7 @@ In progress… Waiting… Place your bets + Participants Current @@ -126,4 +127,12 @@ %s [icon] won ! %s [icon] lost ! + + CONGRATULATIONS + You win + Total odds + Stake + Winnings + + \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/api/AllInApi.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/api/AllInApi.kt index 9d3264a..550c182 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/api/AllInApi.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/api/AllInApi.kt @@ -2,15 +2,22 @@ package fr.iut.alldev.allin.data.api import fr.iut.alldev.allin.data.api.model.CheckUser import fr.iut.alldev.allin.data.api.model.RequestBet +import fr.iut.alldev.allin.data.api.model.RequestParticipation import fr.iut.alldev.allin.data.api.model.RequestUser import fr.iut.alldev.allin.data.api.model.ResponseBet +import fr.iut.alldev.allin.data.api.model.ResponseBetDetail import fr.iut.alldev.allin.data.api.model.ResponseUser import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.POST +import retrofit2.http.Path interface AllInApi { + companion object { + fun String.formatBearerToken() = "Bearer $this" + } + @POST("users/login") suspend fun login(@Body body: CheckUser): ResponseUser @@ -21,8 +28,14 @@ interface AllInApi { suspend fun login(@Header("Authorization") token: String): ResponseUser @POST("bets/add") - suspend fun createBet(@Body body: RequestBet) + suspend fun createBet(@Header("Authorization") token: String, @Body body: RequestBet) @GET("bets/gets") suspend fun getAllBets(): List + + @GET("betdetail/get/{id}") + suspend fun getBet(@Header("Authorization") token: String, @Path("id") id: String): ResponseBetDetail + + @POST("participations/add") + suspend fun participateToBet(@Header("Authorization") token: String, @Body body: RequestParticipation) } \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/api/MockAllInApi.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/api/MockAllInApi.kt new file mode 100644 index 0000000..f2b7f72 --- /dev/null +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/api/MockAllInApi.kt @@ -0,0 +1,239 @@ +package fr.iut.alldev.allin.data.api + +import fr.iut.alldev.allin.data.api.interceptors.AllInAPIException +import fr.iut.alldev.allin.data.api.model.CheckUser +import fr.iut.alldev.allin.data.api.model.RequestBet +import fr.iut.alldev.allin.data.api.model.RequestParticipation +import fr.iut.alldev.allin.data.api.model.RequestUser +import fr.iut.alldev.allin.data.api.model.ResponseBet +import fr.iut.alldev.allin.data.api.model.ResponseBetAnswerDetail +import fr.iut.alldev.allin.data.api.model.ResponseBetDetail +import fr.iut.alldev.allin.data.api.model.ResponseParticipation +import fr.iut.alldev.allin.data.api.model.ResponseUser +import fr.iut.alldev.allin.data.model.bet.NO_VALUE +import fr.iut.alldev.allin.data.model.bet.YES_VALUE +import java.time.ZonedDateTime +import java.util.UUID + +class MockAllInApi : AllInApi { + + private fun getUserFromToken(token: String) = + mockUsers.find { it.first.token == token } + + private fun getAnswerDetails(bet: ResponseBet, participations: List): List { + return bet.response.map { response -> + val responseParticipations = participations.filter { it.answer == response } + ResponseBetAnswerDetail( + response = response, + totalStakes = responseParticipations.sumOf { it.stake }, + totalParticipants = responseParticipations.size, + highestStake = responseParticipations.maxOfOrNull { it.stake } ?: 0, + odds = if (participations.isEmpty()) 0.0f else responseParticipations.size / participations.size.toFloat() + ) + } + } + + override suspend fun login(body: CheckUser): ResponseUser { + return mockUsers.find { it.first.username == body.login && it.second == body.password }?.first + ?: throw AllInAPIException("Invalid login/password.") + } + + override suspend fun login(token: String): ResponseUser { + return getUserFromToken(token)?.first + ?: throw AllInAPIException("Invalid token") + } + + override suspend fun register(body: RequestUser): ResponseUser { + val response = ResponseUser( + id = UUID.randomUUID().toString(), + username = body.username, + email = body.email, + nbCoins = 500, + token = "${body.username} ${mockUsers.size}" + ) to body.password + mockUsers.add(response) + return response.first + } + + override suspend fun createBet(token: String, body: RequestBet) { + mockBets.add( + ResponseBet( + id = UUID.randomUUID().toString(), + theme = body.theme, + sentenceBet = body.sentenceBet, + endRegistration = body.endRegistration, + endBet = body.endBet, + isPrivate = body.isPrivate, + response = body.response, + createdBy = "" + ) + ) + } + + override suspend fun getAllBets(): List = mockBets.toList() + override suspend fun getBet(token: String, id: String): ResponseBetDetail { + val bet = mockBets.find { it.id == id } ?: throw AllInAPIException("Bet not found") + val user = getUserFromToken(token) ?: throw AllInAPIException("Invalid login/password.") + val betParticipations = mockParticipations.filter { it.betId == bet.id } + val userParticipation = betParticipations.find { it.username == user.first.username } + + return ResponseBetDetail( + bet = bet, + answers = getAnswerDetails(bet, betParticipations), + participations = betParticipations, + userParticipation = userParticipation + ) + } + + override suspend fun participateToBet(token: String, body: RequestParticipation) { + getUserFromToken(token)?.let { + mockParticipations.add( + ResponseParticipation( + id = "", + betId = body.betId, + username = it.first.username, + answer = body.answer, + stake = body.stake + + ) + ) + } ?: throw AllInAPIException("Invalid token") + } +} + +private val mockUsers = mutableListOf( + ResponseUser( + id = "UUID 1", + username = "User 1", + email = "john@doe.fr", + nbCoins = 250, + token = "token 1" + ) to "12345", + ResponseUser( + id = "UUID 2", + username = "User 2", + email = "john@doe.fr", + nbCoins = 250, + token = "token 2" + ) to "12345", + ResponseUser( + id = "UUID 3", + username = "User 3", + email = "john@doe.fr", + nbCoins = 250, + token = "token 3" + ) to "12345", + ResponseUser( + id = "UUID 4", + username = "User 4", + email = "john@doe.fr", + nbCoins = 250, + token = "token 4" + ) to "12345", + ResponseUser( + id = "UUID 5", + username = "User 5", + email = "john@doe.fr", + nbCoins = 250, + token = "token 5" + ) to "12345", + ResponseUser( + id = "UUID 6", + username = "User 6", + email = "john@doe.fr", + nbCoins = 250, + token = "token 6" + ) to "12345", + ResponseUser( + id = "UUID 7", + username = "User 7", + email = "john@doe.fr", + nbCoins = 250, + token = "token 7" + ) to "12345" +) + +private val mockParticipations = mutableListOf( + ResponseParticipation( + id = "", + betId = "UUID1", + username = mockUsers[0].first.username, + answer = YES_VALUE, + stake = 200 + ), + ResponseParticipation( + id = "", + betId = "UUID1", + username = mockUsers[1].first.username, + answer = NO_VALUE, + stake = 1500 + ), + ResponseParticipation( + id = "", + betId = "UUID1", + username = mockUsers[2].first.username, + answer = YES_VALUE, + stake = 300 + ), + ResponseParticipation( + id = "", + betId = "UUID1", + username = mockUsers[3].first.username, + answer = YES_VALUE, + stake = 25 + ), + ResponseParticipation( + id = "", + betId = "UUID1", + username = mockUsers[4].first.username, + answer = NO_VALUE, + stake = 222 + ), + ResponseParticipation( + id = "", + betId = "UUID1", + username = mockUsers[5].first.username, + answer = NO_VALUE, + stake = 222 + ), + ResponseParticipation( + id = "", + betId = "UUID1", + username = mockUsers[6].first.username, + answer = NO_VALUE, + stake = 222 + ) +) + +private val mockBets = mutableListOf( + ResponseBet( + id = "UUID1", + theme = "Études", + sentenceBet = "Dave va arriver en retard demain matin ?", + endRegistration = ZonedDateTime.now().plusDays(3), + endBet = ZonedDateTime.now().plusDays(4), + isPrivate = false, + response = listOf(YES_VALUE, NO_VALUE), + createdBy = "Armure" + ), + ResponseBet( + id = "UUID2", + theme = "Études", + sentenceBet = "Dave va arriver en retard demain matin ?", + endRegistration = ZonedDateTime.now().plusDays(3), + endBet = ZonedDateTime.now().plusDays(4), + isPrivate = false, + response = listOf("Answer 1", "Answer 2", "Answer 3", "Answer 4"), + createdBy = "User 2" + ), + ResponseBet( + id = "UUID3", + theme = "Sport", + sentenceBet = "Nouveau record du monde ?", + endRegistration = ZonedDateTime.now().plusDays(3), + endBet = ZonedDateTime.now().plusDays(4), + isPrivate = false, + response = listOf(YES_VALUE, NO_VALUE), + createdBy = "Armure" + ) +) \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/api/interceptors/ErrorInterceptor.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/api/interceptors/ErrorInterceptor.kt index 16abb5a..ebbd8a7 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/api/interceptors/ErrorInterceptor.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/api/interceptors/ErrorInterceptor.kt @@ -14,14 +14,15 @@ class ErrorInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() val response = chain.proceed(request) - if(!response.isSuccessful){ + if (!response.isSuccessful) { when (response.code) { 404 -> throw AllInNotFoundException(response.message) 401 -> throw AllInUnauthorizedException(response.message) else -> throw AllInUnsuccessfulException(response.message) } } - if (response.body?.contentType()?.subtype != "json") { + + response.body?.contentType()?.subtype?.takeIf { it != "json" }?.let { throw AllInAPIException(response.message) } diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiBet.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiBet.kt index ba3c2e8..3610752 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiBet.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiBet.kt @@ -4,26 +4,31 @@ import androidx.annotation.Keep import fr.iut.alldev.allin.data.model.bet.Bet import fr.iut.alldev.allin.data.model.bet.BetStatus import fr.iut.alldev.allin.data.model.bet.CustomBet +import fr.iut.alldev.allin.data.model.bet.NO_VALUE +import fr.iut.alldev.allin.data.model.bet.YES_VALUE import fr.iut.alldev.allin.data.model.bet.YesNoBet -import fr.iut.alldev.allin.data.serialization.SimpleDateSerializer +import fr.iut.alldev.allin.data.model.bet.vo.BetAnswerDetail +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail +import fr.iut.alldev.allin.data.serialization.ZonedDateTimeSerializer import kotlinx.serialization.Serializable import java.time.ZonedDateTime @Keep @Serializable data class ResponseBet( - val id: Int?, + val id: String?, val theme: String, val sentenceBet: String, - @Serializable(SimpleDateSerializer::class) val endRegistration: ZonedDateTime, - @Serializable(SimpleDateSerializer::class) var endBet: ZonedDateTime, + @Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime, + @Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime, var isPrivate: Boolean, var response: List, val createdBy: String ) { fun toBet(): Bet { - if (response.toSet() == setOf("Yes", "No")) { + if (response.toSet() == setOf(YES_VALUE, NO_VALUE)) { return YesNoBet( + id = id ?: "", theme = theme, phrase = sentenceBet, endRegisterDate = endRegistration, @@ -34,6 +39,7 @@ data class ResponseBet( ) } else { return CustomBet( + id = id ?: "", theme = theme, phrase = sentenceBet, endRegisterDate = endRegistration, @@ -41,7 +47,7 @@ data class ResponseBet( isPublic = !isPrivate, betStatus = BetStatus.Waiting, creator = createdBy, - possibleAnswers = response.toSet() + possibleAnswers = response ) } } @@ -50,11 +56,48 @@ data class ResponseBet( @Keep @Serializable data class RequestBet( + val id: String = "", val theme: String, val sentenceBet: String, - @Serializable(SimpleDateSerializer::class) val endRegistration: ZonedDateTime, - @Serializable(SimpleDateSerializer::class) var endBet: ZonedDateTime, + @Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime, + @Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime, var isPrivate: Boolean, - var response: List, - val createdBy: String + var response: List ) + +@Keep +@Serializable +data class ResponseBetAnswerDetail( + val response: String, + val totalStakes: Int, + val totalParticipants: Int, + val highestStake: Int, + val odds: Float +) { + fun toAnswerDetail() = + BetAnswerDetail( + response = response, + totalStakes = totalStakes, + totalParticipants = totalParticipants, + highestStake = highestStake, + odds = odds + ) +} + +@Keep +@Serializable +data class ResponseBetDetail( + val bet: ResponseBet, + val answers: List, + val participations: List, + val userParticipation: ResponseParticipation? = null +) { + fun toBetDetail() = + BetDetail( + bet = bet.toBet(), + answers = answers.map { it.toAnswerDetail() }, + participations = participations.map { it.toParticipation() }, + userParticipation = userParticipation?.toParticipation() + + ) +} \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiParticipation.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiParticipation.kt new file mode 100644 index 0000000..488ca34 --- /dev/null +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiParticipation.kt @@ -0,0 +1,31 @@ +package fr.iut.alldev.allin.data.api.model + +import androidx.annotation.Keep +import fr.iut.alldev.allin.data.model.bet.Participation +import kotlinx.serialization.Serializable + +@Keep +@Serializable +data class ResponseParticipation( + val id: String, + val betId: String, + val username: String, + val answer: String, + val stake: Int +) { + fun toParticipation() = + Participation( + betId = betId, + username = username, + response = answer, + stake = stake + ) +} + +@Keep +@Serializable +data class RequestParticipation( + val betId: String, + val answer: String, + val stake: Int +) \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiUser.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiUser.kt index 37af616..f6e021c 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiUser.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/api/model/ApiUser.kt @@ -9,23 +9,23 @@ import kotlinx.serialization.Serializable data class RequestUser( val username: String, val email: String, - val password: String, - var nbCoins: Int, + val password: String ) @Keep @Serializable data class ResponseUser( + val id: String = "", val username: String, val email: String, var nbCoins: Int, - var token: String? = null, + var token: String? = null ) { fun toUser() = User( + id = id, username = username, email = email, - id = "", - coins = nbCoins + coins = nbCoins.toInt() ) } diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/di/ApiModule.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/di/ApiModule.kt index 3883391..9072cd8 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/di/ApiModule.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/di/ApiModule.kt @@ -5,18 +5,25 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import fr.iut.alldev.allin.data.api.AllInApi +import fr.iut.alldev.allin.data.api.MockAllInApi import fr.iut.alldev.allin.data.di.NetworkModule.createRetrofit import okhttp3.HttpUrl import okhttp3.OkHttpClient import javax.inject.Singleton +const val mock = false + @Module @InstallIn(SingletonComponent::class) class ApiModule { @Provides @Singleton fun provideAllInApi(@AllInUrl url: HttpUrl, okHttpClient: OkHttpClient): AllInApi { - val retrofit = createRetrofit(url = url, okHttpClient = okHttpClient) - return retrofit.create(AllInApi::class.java) + return if (mock) { + MockAllInApi() + } else { + val retrofit = createRetrofit(url = url, okHttpClient = okHttpClient) + retrofit.create(AllInApi::class.java) + } } } \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/di/NetworkModule.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/di/NetworkModule.kt index 0c26aae..981005a 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/di/NetworkModule.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/di/NetworkModule.kt @@ -17,7 +17,7 @@ import javax.inject.Qualifier internal val json by lazy { Json { ignoreUnknownKeys = true - encodeDefaults = false + encodeDefaults = true } } diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/User.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/User.kt index 5a4e882..21d650b 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/model/User.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/User.kt @@ -1,8 +1,8 @@ package fr.iut.alldev.allin.data.model data class User( - val id : String, - val username : String, - val email : String, - val coins : Int + val id: String, + val username: String, + val email: String, + val coins: Int ) \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/Bet.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/Bet.kt index 20f10bf..1f9cc17 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/Bet.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/Bet.kt @@ -3,8 +3,8 @@ package fr.iut.alldev.allin.data.model.bet import fr.iut.alldev.allin.data.api.model.RequestBet import java.time.ZonedDateTime -abstract class Bet( - open val id: Int? = null, +sealed class Bet( + open val id: String, open val creator: String, open val theme: String, open val phrase: String, @@ -16,13 +16,13 @@ abstract class Bet( abstract fun getResponses(): List fun toRequestBet(): RequestBet { return RequestBet( + id = "", theme = theme, sentenceBet = phrase, endRegistration = endRegisterDate, endBet = endBetDate, isPrivate = !isPublic, - response = getResponses(), - createdBy = creator + response = getResponses() ) } } \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/BetFactory.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/BetFactory.kt index f48a5d3..8df4afb 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/BetFactory.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/BetFactory.kt @@ -5,6 +5,7 @@ import java.time.ZonedDateTime class BetFactory { companion object { fun createBet( + id: String, betType: BetType, creator: String, theme: String, @@ -14,12 +15,13 @@ class BetFactory { isPublic: Boolean, nameTeam1: String = "", nameTeam2: String = "", - possibleAnswers: Set = emptySet(), + possibleAnswers: List = emptyList(), ): Bet = when (betType) { BetType.YES_NO -> { YesNoBet( + id = id, theme = theme, creator = creator, phrase = phrase, @@ -32,6 +34,7 @@ class BetFactory { BetType.MATCH -> { MatchBet( + id = id, theme = theme, creator = creator, phrase = phrase, @@ -47,6 +50,7 @@ class BetFactory { BetType.CUSTOM -> { CustomBet( + id = id, theme = theme, creator = creator, phrase = phrase, diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/BetStatus.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/BetStatus.kt index b42275f..66d27a8 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/BetStatus.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/BetStatus.kt @@ -6,4 +6,14 @@ sealed class BetStatus { data object InProgress : BetStatus() data object Waiting : BetStatus() + + companion object { + val entries = sequenceOf( + InProgress, + Waiting, + Finished(BetFinishedStatus.WON), + Finished(BetFinishedStatus.LOST) + ) + } + } \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/CustomBet.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/CustomBet.kt index 4a8320d..a252e51 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/CustomBet.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/CustomBet.kt @@ -3,7 +3,7 @@ package fr.iut.alldev.allin.data.model.bet import java.time.ZonedDateTime data class CustomBet( - override val id: Int? = null, + override val id: String, override val creator: String, override val theme: String, override val phrase: String, @@ -11,7 +11,7 @@ data class CustomBet( override val endBetDate: ZonedDateTime, override val isPublic: Boolean, override val betStatus: BetStatus, - val possibleAnswers: Set, + val possibleAnswers: List ) : Bet( id, creator, @@ -22,5 +22,5 @@ data class CustomBet( isPublic, betStatus ) { - override fun getResponses(): List = possibleAnswers.toList() + override fun getResponses(): List = possibleAnswers } diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/MatchBet.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/MatchBet.kt index e0a4211..03a829e 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/MatchBet.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/MatchBet.kt @@ -3,7 +3,7 @@ package fr.iut.alldev.allin.data.model.bet import java.time.ZonedDateTime data class MatchBet( - override val id: Int? = null, + override val id: String, override val creator: String, override val theme: String, override val phrase: String, @@ -12,7 +12,7 @@ data class MatchBet( override val isPublic: Boolean, override val betStatus: BetStatus, val nameTeam1: String, - val nameTeam2: String, + val nameTeam2: String ) : Bet( id, creator, diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/Participation.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/Participation.kt new file mode 100644 index 0000000..e2f15b1 --- /dev/null +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/Participation.kt @@ -0,0 +1,17 @@ +package fr.iut.alldev.allin.data.model.bet + +import fr.iut.alldev.allin.data.api.model.RequestParticipation + +data class Participation( + val betId: String, + val username: String, + val response: String, + val stake: Int +) { + fun toRequestParticipation() = + RequestParticipation( + betId = betId, + answer = response, + stake = stake + ) +} \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/YesNoBet.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/YesNoBet.kt index 8252dab..5e28f06 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/YesNoBet.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/YesNoBet.kt @@ -2,15 +2,18 @@ package fr.iut.alldev.allin.data.model.bet import java.time.ZonedDateTime +const val YES_VALUE = "Yes" +const val NO_VALUE = "No" + data class YesNoBet( - override val id: Int? = null, + override val id: String, override val creator: String, override val theme: String, override val phrase: String, override val endRegisterDate: ZonedDateTime, override val endBetDate: ZonedDateTime, override val isPublic: Boolean, - override val betStatus: BetStatus, + override val betStatus: BetStatus ) : Bet( id, creator, @@ -21,5 +24,5 @@ data class YesNoBet( isPublic, betStatus ) { - override fun getResponses(): List = listOf("Yes", "No") + override fun getResponses(): List = listOf(YES_VALUE, NO_VALUE) } \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetAnswerDetail.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetAnswerDetail.kt new file mode 100644 index 0000000..382a4b3 --- /dev/null +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetAnswerDetail.kt @@ -0,0 +1,9 @@ +package fr.iut.alldev.allin.data.model.bet.vo + +data class BetAnswerDetail( + val response: String, + val totalStakes: Int, + val totalParticipants: Int, + val highestStake: Int, + val odds: Float +) \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetDetail.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetDetail.kt new file mode 100644 index 0000000..a77f6dd --- /dev/null +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetDetail.kt @@ -0,0 +1,14 @@ +package fr.iut.alldev.allin.data.model.bet.vo + +import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.Participation + +data class BetDetail( + val bet: Bet, + val answers: List, + val participations: List, + val userParticipation: Participation? +) { + fun getAnswerOfResponse(response: String) = + answers.find { it.response == response } +} \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetResult.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetResult.kt new file mode 100644 index 0000000..407bc4e --- /dev/null +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/model/bet/vo/BetResult.kt @@ -0,0 +1,10 @@ +package fr.iut.alldev.allin.data.model.bet.vo + +import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.Participation + +data class BetResult( + val bet: Bet, + val participations: List, + val answerDetail: BetAnswerDetail +) \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/BetRepository.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/BetRepository.kt index bec1d9c..ed4bcd8 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/BetRepository.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/BetRepository.kt @@ -1,11 +1,15 @@ package fr.iut.alldev.allin.data.repository import fr.iut.alldev.allin.data.model.bet.Bet +import fr.iut.alldev.allin.data.model.bet.Participation +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail import kotlinx.coroutines.flow.Flow abstract class BetRepository { abstract suspend fun createBet(bet: Bet, token: String) abstract suspend fun getHistory(): Flow> abstract suspend fun getCurrentBets(): Flow> + abstract suspend fun getBet(id: String, token: String): BetDetail + abstract suspend fun participateToBet(participation: Participation, token: String) abstract suspend fun getAllBets(): Flow> } \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/UserRepository.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/UserRepository.kt index 338b8aa..b9a22ac 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/UserRepository.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/UserRepository.kt @@ -4,16 +4,9 @@ import fr.iut.alldev.allin.data.model.User abstract class UserRepository { lateinit var currentUser: User - abstract suspend fun login( - username: String, - password: String - ): String? + abstract suspend fun login(username: String, password: String): String? abstract suspend fun login(token: String): String? - abstract suspend fun register( - username: String, - email: String, - password: String - ): String? + abstract suspend fun register(username: String, email: String, password: String): String? } \ No newline at end of file diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/BetRepositoryImpl.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/BetRepositoryImpl.kt index bf33f40..7748092 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/BetRepositoryImpl.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/BetRepositoryImpl.kt @@ -1,10 +1,13 @@ 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.formatBearerToken import fr.iut.alldev.allin.data.model.bet.Bet import fr.iut.alldev.allin.data.model.bet.BetFinishedStatus import fr.iut.alldev.allin.data.model.bet.BetStatus +import fr.iut.alldev.allin.data.model.bet.Participation import fr.iut.alldev.allin.data.model.bet.YesNoBet +import fr.iut.alldev.allin.data.model.bet.vo.BetDetail import fr.iut.alldev.allin.data.repository.BetRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf @@ -16,7 +19,8 @@ class BetRepositoryImpl @Inject constructor( ) : BetRepository() { override suspend fun createBet(bet: Bet, token: String) { api.createBet( - bet.toRequestBet().copy(createdBy = token) + token = token.formatBearerToken(), + body = bet.toRequestBet() ) } @@ -24,6 +28,7 @@ class BetRepositoryImpl @Inject constructor( return flowOf( listOf( YesNoBet( + id = "1", creator = "Lucas", theme = "Theme", phrase = "Bet phrase 1", @@ -33,6 +38,7 @@ class BetRepositoryImpl @Inject constructor( betStatus = BetStatus.Finished(BetFinishedStatus.WON) ), YesNoBet( + id = "2", creator = "Lucas", theme = "Theme", phrase = "Bet phrase 2", @@ -42,6 +48,7 @@ class BetRepositoryImpl @Inject constructor( betStatus = BetStatus.Finished(BetFinishedStatus.LOST) ), YesNoBet( + id = "3", creator = "Lucas", theme = "Theme", phrase = "Bet phrase 3", @@ -59,6 +66,7 @@ class BetRepositoryImpl @Inject constructor( return flowOf( listOf( YesNoBet( + id = "1", creator = "Lucas", theme = "Theme", phrase = "Bet phrase 1", @@ -68,6 +76,7 @@ class BetRepositoryImpl @Inject constructor( betStatus = BetStatus.InProgress ), YesNoBet( + id = "2", creator = "Lucas", theme = "Theme", phrase = "Bet phrase 2", @@ -77,6 +86,7 @@ class BetRepositoryImpl @Inject constructor( betStatus = BetStatus.InProgress ), YesNoBet( + id = "3", creator = "Lucas", theme = "Theme", phrase = "Bet phrase 3", @@ -89,6 +99,17 @@ class BetRepositoryImpl @Inject constructor( ) } + override suspend fun getBet(id: String, token: String): BetDetail { + return api.getBet( + token = token.formatBearerToken(), + id = id + ).toBetDetail() + } + + override suspend fun participateToBet(participation: Participation, token: String) { + api.participateToBet(token = token.formatBearerToken(), body = participation.toRequestParticipation()) + } + override suspend fun getAllBets(): Flow> { return flowOf( api.getAllBets().map { it.toBet() } diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/UserRepositoryImpl.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/UserRepositoryImpl.kt index 54f3889..6c23cd8 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/UserRepositoryImpl.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/repository/impl/UserRepositoryImpl.kt @@ -1,6 +1,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.formatBearerToken import fr.iut.alldev.allin.data.api.model.CheckUser import fr.iut.alldev.allin.data.api.model.RequestUser import fr.iut.alldev.allin.data.repository.UserRepository @@ -22,7 +23,7 @@ class UserRepositoryImpl @Inject constructor( } override suspend fun login(token: String): String? { - val response = api.login(token = "Bearer $token") + val response = api.login(token = token.formatBearerToken()) currentUser = response.toUser() return response.token } @@ -33,8 +34,7 @@ class UserRepositoryImpl @Inject constructor( RequestUser( username = username, email = email, - password = password, - nbCoins = 0 + password = password ) ) currentUser = response.toUser() diff --git a/src/data/src/main/java/fr/iut/alldev/allin/data/serialization/ZonedDateTimeSerializer.kt b/src/data/src/main/java/fr/iut/alldev/allin/data/serialization/ZonedDateTimeSerializer.kt index 5810189..ae4742b 100644 --- a/src/data/src/main/java/fr/iut/alldev/allin/data/serialization/ZonedDateTimeSerializer.kt +++ b/src/data/src/main/java/fr/iut/alldev/allin/data/serialization/ZonedDateTimeSerializer.kt @@ -6,39 +6,22 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import java.time.Instant -import java.time.LocalDate -import java.time.ZoneId import java.time.ZonedDateTime import java.time.format.DateTimeFormatter object ZonedDateTimeSerializer : KSerializer { + private val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z") + override val descriptor: SerialDescriptor = - PrimitiveSerialDescriptor("ZonedDateTime", PrimitiveKind.LONG) + PrimitiveSerialDescriptor("ZonedDateTime", PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: ZonedDateTime) { - encoder.encodeLong(value.toEpochSecond()) + encoder.encodeString(formatter.format(value)) } override fun deserialize(decoder: Decoder): ZonedDateTime { - val epoch = decoder.decodeLong() - return ZonedDateTime.ofInstant(Instant.ofEpochSecond(epoch), ZoneId.systemDefault()) + val dateString = decoder.decodeString() + return ZonedDateTime.parse(dateString, formatter) } } -class SimpleDateSerializer : KSerializer { - override val descriptor: SerialDescriptor = - PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING) - - private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") - - override fun deserialize(decoder: Decoder): ZonedDateTime { - val date = LocalDate.parse(decoder.decodeString(), formatter) - return date.atStartOfDay(ZoneId.systemDefault()) - } - - override fun serialize(encoder: Encoder, value: ZonedDateTime) { - val dateString = formatter.format(value) - encoder.encodeString(dateString) - } -} diff --git a/src/data/src/release/java/fr.iut.alldev.allin.data.di/ReleaseModule.kt b/src/data/src/release/java/fr.iut.alldev.allin.data.di/ReleaseModule.kt index 02df214..11bdf83 100644 --- a/src/data/src/release/java/fr.iut.alldev.allin.data.di/ReleaseModule.kt +++ b/src/data/src/release/java/fr.iut.alldev.allin.data.di/ReleaseModule.kt @@ -1,12 +1,8 @@ package fr.iut.alldev.allin.data.di import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import javax.inject.Singleton @Module(includes = [ReleaseNetworkModule::class]) @InstallIn(SingletonComponent::class) diff --git a/src/data/src/release/java/fr.iut.alldev.allin.data.di/ReleaseNetworkModule.kt b/src/data/src/release/java/fr.iut.alldev.allin.data.di/ReleaseNetworkModule.kt index 4bb6870..adfb9d0 100644 --- a/src/data/src/release/java/fr.iut.alldev.allin.data.di/ReleaseNetworkModule.kt +++ b/src/data/src/release/java/fr.iut.alldev.allin.data.di/ReleaseNetworkModule.kt @@ -4,8 +4,8 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import fr.iut.alldev.allin.data.api.interceptors.ErrorInterceptor import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor import javax.inject.Singleton @Module diff --git a/src/gradle/libs.versions.toml b/src/gradle/libs.versions.toml index cb615ee..3ecc6ce 100644 --- a/src/gradle/libs.versions.toml +++ b/src/gradle/libs.versions.toml @@ -10,9 +10,10 @@ kotlin = "1.9.20" androidxCore = "1.12.0" androidxActivity = "1.8.2" -androidxSecurity = "1.0.0" +androidxSecurity = "1.1.0-alpha06" composeBom = "2023.10.01" +compose = "1.5.4" composePreview = "1.6.0-beta03" composeCompiler = "1.5.5" composeNavigation = "2.7.6" @@ -31,7 +32,7 @@ room = "2.6.1" okHttp = "4.11.0" # Plugins -gradlePlugin = "8.1.2" +gradlePlugin = "8.1.4" publishPlugin = "1.1" resgenPlugin = "2.5" @@ -54,6 +55,9 @@ 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" } + # Compose compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" } @@ -95,7 +99,6 @@ plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version. plugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" } plugin-hilt = { module = "com.google.dagger:hilt-android-gradle-plugin", version.ref = "hilt" } - [bundles] android = ["androidx-core", "androidx-activity", "androidx-security"] diff --git a/src/keys/debug.keystore b/src/keys/debug.keystore new file mode 100644 index 0000000..4a3c6c0 Binary files /dev/null and b/src/keys/debug.keystore differ diff --git a/src/keys/keystore.properties b/src/keys/keystore.properties new file mode 100644 index 0000000..eadbbfe --- /dev/null +++ b/src/keys/keystore.properties @@ -0,0 +1,4 @@ +debugStoreFile=../keys/debug.keystore +releaseStoreFile=../keys/release.keystore +aliasRelease=placeYourBets +passwordRelease=placeYourBets \ No newline at end of file diff --git a/src/keys/release.keystore b/src/keys/release.keystore new file mode 100644 index 0000000..005b9a8 Binary files /dev/null and b/src/keys/release.keystore differ