Compare commits

..

2 Commits

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

@ -21,7 +21,7 @@
**Description** : Ce dépôt contient l'ensemble du code pour la partie client iOS de l'application *ALL IN*. **Description** : Ce dépôt contient l'ensemble du code pour la partie client iOS de l'application *ALL IN*.
</br> </br>
# Répartition du dépot # Répartition du GitLab
[**Sources**](Sources) : **Code de l'application** [**Sources**](Sources) : **Code de l'application**
@ -32,43 +32,7 @@
- MVVM - MVVM
<div align = center>
<img src="https://codefirst.iut.uca.fr/git/AllDev/Gestion_de_projet/raw/branch/master/Documentation/Diagrammes/AllInMVVM.png" width="600" />
</div>
# Fonctionnement
- ### Comment lancer le projet ?
:information_source: *Assurez-vous d'avoir un Mac à disposition*
Tout d'abord si ce n'est pas fait cloner le dépôt de la branche **master/main**, pour cela copier le lien URL du dépôt git :
<div align = center>
![Comment cloner](Documentation/Images/HowToClone.png)
</div>
Sur votre Mac, ouvrez l'IDE **Xcode** (disponible via l'App Store), puis cloner le dépôt en utilisant l'URL copiée précédemment :
<div align = center>
<img src="Documentation/Images/WelcomeToXcode.png" width="500" >
</div>
Vous serez alors redirigé par l'IDE et pourrez lancer l'application sur l'appareil de votre choix :
<div align = center>
<img src="Documentation/Images/LaunchApp.png" width="900" >
</div>
*Si vous souhaitez lancer l'application sur votre appareil personnel, il sera nécessaire de renseigner votre compte iCloud dans l'IDE !*
# Technologies # Technologies

@ -3,6 +3,8 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array/> <array>
<string>group.alldev.AllIn</string>
</array>
</dict> </dict>
</plist> </plist>

@ -1,21 +0,0 @@
{
"images" : [
{
"filename" : "blueFlame.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

@ -1,21 +0,0 @@
{
"images" : [
{
"filename" : "globe.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

@ -1,21 +0,0 @@
{
"images" : [
{
"filename" : "pinkFlame.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

@ -8,12 +8,11 @@
import SwiftUI import SwiftUI
struct AllcoinsCapsule: View { struct AllcoinsCapsule: View {
var gains: Int
var body: some View { var body: some View {
Text("Vous remportez") Text("Vous remportez")
.foregroundColor(.white) .foregroundColor(.white)
HStack{ HStack{
Text(gains.description) Text("2340")
.textStyle(weight: .bold, color: .white, size: 60) .textStyle(weight: .bold, color: .white, size: 60)
Image("allcoinWhiteIcon") Image("allcoinWhiteIcon")
.resizable() .resizable()
@ -31,6 +30,6 @@ struct AllcoinsCapsule: View {
struct AllcoinsCapsule_Previews: PreviewProvider { struct AllcoinsCapsule_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
AllcoinsCapsule(gains: 100) AllcoinsCapsule()
} }
} }

@ -15,7 +15,7 @@ struct AllcoinsCounter: View {
var body: some View { var body: some View {
HStack(alignment: .center) { HStack(alignment: .center) {
Text(String(appStateContainer.user!.nbCoins)) Text(String(appStateContainer.user?.nbCoins ?? 0))
.contentTransition(.numericText()) .contentTransition(.numericText())
.fontWeight(.black) .fontWeight(.black)
.foregroundColor(foregroundColor) .foregroundColor(foregroundColor)

@ -22,6 +22,7 @@ struct BetCard: View {
Text("bet_proposed_by_format \(bet.author.capitalized)") Text("bet_proposed_by_format \(bet.author.capitalized)")
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
} }
Text(bet.theme) Text(bet.theme)
.font(.system(size: 15)) .font(.system(size: 15))
@ -44,8 +45,8 @@ struct BetCard: View {
VStack(alignment: .leading,spacing: 2){ VStack(alignment: .leading,spacing: 2){
HStack{ HStack{
Spacer() Spacer()
UsersPreview(users: []) UsersPreview()
Text("bet_players_waiting_format \(bet.invited.count.description)") Text("bet_players_waiting_format \(bet.registered.count.description)")
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
.fontWeight(.medium) .fontWeight(.medium)
@ -77,10 +78,11 @@ struct BetCard_Previews: PreviewProvider {
phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.",
endRegisterDate: Date().addingTimeInterval(86400), endRegisterDate: Date().addingTimeInterval(86400),
endBetDate: Date().addingTimeInterval(172800), endBetDate: Date().addingTimeInterval(172800),
isPrivate: false, isPublic: true,
status: .inProgress, status: .inProgress,
invited: [], invited: [],
author: "Imri")) author: "Imri",
registered: []))
.preferredColorScheme(.dark) .preferredColorScheme(.dark)
} }
} }

@ -11,12 +11,12 @@ import Model
struct BetLineLoading: View { struct BetLineLoading: View {
@State var showInfos: Bool = false @State var showInfos: Bool = false
var bet: BetDetail var participations: [Participation]
var value: CGFloat { var value: CGFloat {
let totalParticipations = bet.participations.count let totalParticipations = participations.count
let numberOfYes = bet.participations.filter { $0.answer.uppercased() == "YES" }.count let numberOfYes = participations.filter { $0.answer.uppercased() == "YES" }.count
let numberOfNo = bet.participations.filter { $0.answer.uppercased() == "NO" }.count let numberOfNo = participations.filter { $0.answer.uppercased() == "NO" }.count
if(numberOfNo == 0 && numberOfYes == 0){ if(numberOfNo == 0 && numberOfYes == 0){
return 0.5 return 0.5
} }
@ -25,22 +25,144 @@ struct BetLineLoading: View {
} }
var yesParticipations: [Participation] { var yesParticipations: [Participation] {
bet.participations.filter { $0.answer.uppercased() == "YES" } participations.filter { $0.answer.uppercased() == "YES" }
} }
var noParticipations: [Participation] { var noParticipations: [Participation] {
bet.participations.filter { $0.answer.uppercased() == "NO" } participations.filter { $0.answer.uppercased() == "NO" }
} }
var body: some View { var body: some View {
switch bet.bet { VStack(alignment: .leading, spacing: 0) {
case is BinaryBet: HStack(spacing: 5) {
BinaryBetLine(bet: bet) Text("OUI")
case is CustomBet: .font(.system(size: 25))
CustomBetLine(bet: bet) .fontWeight(.bold)
default: .foregroundColor(AllInColors.blue200)
BinaryBetLine(bet: bet) Spacer()
Text("NON")
.font(.system(size: 25))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
} }
GeometryReader { geometry in
ZStack(alignment: .leading) {
HStack{
Spacer()
Rectangle()
.frame(width: min(CGFloat(1-self.value) * geometry.size.width, geometry.size.width), height: 17)
.foregroundStyle(AllInColors.PinkBetGradiant).cornerRadius(999)
}
HStack(spacing: 0) {
Rectangle()
.frame(width: min(CGFloat(self.value) * geometry.size.width, geometry.size.width), height: 17)
.foregroundStyle(AllInColors.BlueBetGradiant)
.cornerRadius(999)
Image("loadingHeartIcon")
.resizable()
.frame(width: 29, height: 32)
.padding(.leading, -10)
}
}
.padding(.bottom, 5)
}
.frame(height: 40)
HStack {
Spacer()
Text("bet_status_details_drawer")
.textStyle(weight: .medium, color: AllInColors.primaryTextColor, size: 10)
Image(showInfos ? "chevronUpIcon" : "chevronDownIcon")
.resizable()
.frame(width: 10, height: 7)
.scaledToFill()
}
.onTapGesture {
withAnimation {
showInfos.toggle()
}
}
.padding(.bottom, 5)
.padding(.trailing, 5)
if showInfos {
VStack(spacing: 1) {
HStack(spacing: 5) {
Image("blueAllCoinIcon")
.resizable()
.frame(width:12, height: 12)
Text(yesParticipations.reduce(0, {x,y in x + y.stake}).description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text(noParticipations.reduce(0, {x,y in x + y.stake}).description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
Image("pinkAllCoinIcon")
.resizable()
.frame(width: 12, height: 12)
}
HStack(spacing: 5){
Image("bluePersonIcon")
.resizable()
.frame(width: 12, height: 12)
Text(yesParticipations.count.description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text(noParticipations.count.description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
Image("pinkPersonIcon")
.resizable()
.frame(width: 12, height: 12)
}
HStack(spacing: 5){
Image("blueBadgeIcon")
.resizable()
.frame(width: 12, height: 12)
Text(yesParticipations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text(noParticipations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
Image("pinkBadgeIcon")
.resizable()
.frame(width: 12, height: 12)
}
HStack(spacing: 5){
Image("blueTrophyIcon")
.resizable()
.frame(width: 12, height: 12)
Text("1.2")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text("1.2")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
Image("pinkTrophyIcon")
.resizable()
.frame(width:12, height: 12)
}
}
}
}
} }
} }

@ -1,168 +0,0 @@
//
// BinaryBetLine.swift
// AllIn
//
// Created by Lucas Delanier on 10/06/2024.
//
import SwiftUI
import Model
struct BinaryBetLine: View {
@State var showInfos: Bool = false
var bet: BetDetail
var value: CGFloat {
let totalParticipations = bet.participations.count
let numberOfYes = bet.participations.filter { $0.answer.uppercased() == "YES" }.count
let numberOfNo = bet.participations.filter { $0.answer.uppercased() == "NO" }.count
if(numberOfNo == 0 && numberOfYes == 0){
return 0.5
}
return totalParticipations > 0 ? CGFloat(numberOfYes) / CGFloat(totalParticipations) : 0.0
}
var yesParticipations: [Participation] {
bet.participations.filter { $0.answer.uppercased() == "YES" }
}
var noParticipations: [Participation] {
bet.participations.filter { $0.answer.uppercased() == "NO" }
}
var body: some View {
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 5) {
Text("OUI")
.font(.system(size: 25))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text("NON")
.font(.system(size: 25))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
}
GeometryReader { geometry in
ZStack(alignment: .leading) {
HStack{
Spacer()
Rectangle()
.frame(width: min(CGFloat(1-self.value) * geometry.size.width, geometry.size.width-20), height: 17)
.foregroundStyle(AllInColors.PinkBetGradiant).cornerRadius(999)
}
HStack(spacing: 0) {
Rectangle()
.frame(width: min(CGFloat(self.value) * geometry.size.width, geometry.size.width-20), height: 17)
.foregroundStyle(AllInColors.BlueBetGradiant)
.cornerRadius(999)
Image("loadingHeartIcon")
.resizable()
.frame(width: 29, height: 32)
.padding(.leading, -10)
}
}
.padding(.bottom, 5)
}
.frame(height: 40)
HStack {
Spacer()
Text("bet_status_details_drawer")
.textStyle(weight: .medium, color: AllInColors.primaryTextColor, size: 10)
Image(showInfos ? "chevronUpIcon" : "chevronDownIcon")
.resizable()
.frame(width: 10, height: 7)
.scaledToFill()
}
.onTapGesture {
withAnimation {
showInfos.toggle()
}
}
.padding(.bottom, 5)
.padding(.trailing, 5)
if showInfos {
VStack(spacing: 1) {
HStack(spacing: 5) {
Image("blueAllCoinIcon")
.resizable()
.frame(width:12, height: 12)
Text(yesParticipations.reduce(0, {x,y in x + y.stake}).description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text(noParticipations.reduce(0, {x,y in x + y.stake}).description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
Image("pinkAllCoinIcon")
.resizable()
.frame(width: 12, height: 12)
}
HStack(spacing: 5){
Image("bluePersonIcon")
.resizable()
.frame(width: 12, height: 12)
Text(yesParticipations.count.description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text(noParticipations.count.description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
Image("pinkPersonIcon")
.resizable()
.frame(width: 12, height: 12)
}
HStack(spacing: 5){
Image("blueBadgeIcon")
.resizable()
.frame(width: 12, height: 12)
Text(yesParticipations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text(noParticipations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
Image("pinkBadgeIcon")
.resizable()
.frame(width: 12, height: 12)
}
HStack(spacing: 5){
Image("blueTrophyIcon")
.resizable()
.frame(width: 12, height: 12)
Text("1.2")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.blue200)
Spacer()
Text("1.2")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(AllInColors.pink100)
Image("pinkTrophyIcon")
.resizable()
.frame(width:12, height: 12)
}
}
}
}
}
}

@ -14,30 +14,23 @@ struct ChoiceFinalAnswerCell: View {
var selected = false var selected = false
var answer: AnswerDetail var answer: AnswerDetail
var rawColor = AllInColors.blueAccentColor var rawColor = AllInColors.blueAccentColor
var body: some View { var body: some View {
ZStack { ZStack{
HStack { HStack{
Spacer() Spacer()
Text(answer.response) Text(answer.response)
.textStyle(weight: .bold, color: selected ? .white : rawColor, size: 40) .textStyle(weight: .bold, color: selected ? .white :rawColor, size: 40).padding(.vertical, 10)
.padding(.vertical, 10)
Spacer() Spacer()
} }
HStack { HStack{
Spacer() Spacer()
OddCapsule( OddCapsule(backgroundColor: selected ? .white : AllInColors.purpleAccentColor, foregroundColor: selected ? AllInColors.purpleAccentColor : .white ,odd: answer.odds ).padding(.trailing,20).scaleEffect(0.9)
backgroundColor: selected ? .white : AllInColors.purpleAccentColor,
foregroundColor: selected ? AllInColors.purpleAccentColor : .white,
odd: answer.odds
)
.padding(.trailing, 20)
.scaleEffect(0.9)
} }
} }.background(selected ? AllInColors.purpleAccentColor : .white).cornerRadius(17).scaleEffect(selected ? 1.02 : 1).animation(
.background(selected ? AllInColors.purpleAccentColor : .white) .easeInOut(duration: 0.3),
.cornerRadius(17) value: selected
.scaleEffect(selected ? 1.02 : 1) )
.animation(.easeInOut(duration: 0.3), value: selected)
} }
} }

@ -1,141 +0,0 @@
//
// CustomBetLine.swift
// AllIn
//
// Created by Lucas Delanier on 10/06/2024.
//
import SwiftUI
import Model
struct CustomBetLine: View {
@State var showInfos: [String: Bool] = [:]
var bet: BetDetail
var participationsForAnswer: [String: [Participation]] {
Dictionary(grouping: bet.participations, by: { $0.answer.uppercased() })
}
var sortedAnswers: [AnswerDetail] {
bet.answers.sorted { $0.totalParticipants > $1.totalParticipants }
}
func getTextStyle(for answer: AnswerDetail) -> Font.Weight {
return answer == sortedAnswers.first ? .bold : .light
}
func getColor(for answer: AnswerDetail) -> Color {
return answer == sortedAnswers.first ? AllInColors.pinkAccentColor : AllInColors.blueAccentColor
}
func getGradiant(for answer: AnswerDetail) -> LinearGradient {
return answer == sortedAnswers.first ? AllInColors.PinkBetGradiant : AllInColors.BlueBetLineGradiant
}
func getFlameImage(for answer: AnswerDetail) -> String {
return answer == sortedAnswers.first ? "pinkFlameIcon" : "blueFlameIcon"
}
var body: some View {
VStack(alignment: .leading, spacing: 0) {
ForEach(sortedAnswers, id: \.response) { answer in
let participations = participationsForAnswer[answer.response.uppercased()] ?? []
let totalParticipations = bet.participations.count
let percentage = totalParticipations > 0 ? CGFloat(participations.count) / CGFloat(totalParticipations) : 0.0
VStack {
HStack {
Text(answer.response)
.font(.system(size: 15))
.fontWeight(getTextStyle(for: answer))
.foregroundColor(getColor(for: answer))
Spacer()
}
GeometryReader { geometry in
ZStack(alignment: .leading) {
HStack(spacing: 0) {
Rectangle()
.frame(width: min(percentage * geometry.size.width, geometry.size.width-20), height: 17)
.foregroundStyle(getGradiant(for: answer))
.cornerRadius(999, corners: [.topLeft, .bottomLeft])
Image(getFlameImage(for: answer))
.resizable()
.frame(width: 29, height: 32)
.padding(.leading, -6)
Text("\(Int(percentage * 100))%")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundStyle(getColor(for: answer))
.padding(.leading, 2)
}
}
.padding(.bottom, 5)
}
.frame(height: 40)
HStack {
Spacer()
Text("bet_status_details_drawer")
.textStyle(weight: .medium, color: AllInColors.primaryTextColor, size: 10)
Image(showInfos[answer.response] ?? false ? "chevronUpIcon" : "chevronDownIcon")
.resizable()
.frame(width: 10, height: 7)
.scaledToFill()
}
.onTapGesture {
withAnimation {
showInfos[answer.response, default: false].toggle()
}
}
.padding(.trailing, 5)
if showInfos[answer.response] ?? false {
HStack{
VStack(alignment: .leading,spacing: 1) {
HStack(spacing: 5) {
Image(answer == sortedAnswers.first ? "pinkAllCoinIcon" : "blueAllCoinIcon")
.resizable()
.frame(width: 12, height: 12)
Text(participations.reduce(0, { x, y in x + y.stake }).description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(getColor(for: answer))
}
HStack(spacing: 5) {
Image(answer == sortedAnswers.first ? "pinkPersonIcon" : "bluePersonIcon")
.resizable()
.frame(width: 12, height: 12)
Text(participations.count.description)
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(getColor(for: answer))
}
HStack(spacing: 5) {
Image(answer == sortedAnswers.first ? "pinkBadgeIcon" : "blueBadgeIcon")
.resizable()
.frame(width: 12, height: 12)
Text(participations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(getColor(for: answer))
}
HStack(spacing: 5) {
Image(answer == sortedAnswers.first ? "pinkTrophyIcon" : "blueTrophyIcon")
.resizable()
.frame(width: 12, height: 12)
Text(String(format: "%.2f", answer.odds))
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(getColor(for: answer))
}
}
Spacer()
}
}
}
}
}
}
}

@ -1,3 +1,12 @@
//
// DropDownAnswerMenu.swift
// AllIn
//
// Created by Lucas Delanier on 16/01/2024.
//
import SwiftUI
// //
// DropDownMenu.swift // DropDownMenu.swift
// AllIn // AllIn
@ -6,21 +15,20 @@
// //
import SwiftUI import SwiftUI
import Model
struct DropDownAnswerMenu: View { struct DropDownAnswerMenu: View {
@State var expand = false @State var expand = false
@Binding var selectedAnswer: AnswerDetail @Binding var selectedOption: Int
var answers: [AnswerDetail] var options: [(Int, String, Float)]
var body: some View { var body: some View {
VStack(spacing: 0, content: { VStack(spacing: 0, content: {
Button(action: { withTransaction(Transaction(animation: nil)) { self.expand.toggle() } }) { Button(action: { self.expand.toggle() }) {
HStack{ HStack{
Text(selectedAnswer.response) Text(options[selectedOption].1.description)
.textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20) .textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20)
Text("\(selectedAnswer.odds, specifier: "%.2f")") Text(options[selectedOption].2.description)
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10) .textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10)
Spacer() Spacer()
@ -35,21 +43,19 @@ struct DropDownAnswerMenu: View {
.foregroundColor(AllInColors.delimiterGrey) .foregroundColor(AllInColors.delimiterGrey)
.padding(.bottom, 18) .padding(.bottom, 18)
VStack(spacing: 0) { VStack(spacing: 0) {
ForEach(answers) { (answer: AnswerDetail) in ForEach(0..<options.count, id: \.self) { index in
if answer != selectedAnswer { if options[index].0 != selectedOption {
Button(action: { Button(action: {self.selectedOption = options[index].0
self.selectedAnswer = answer self.expand.toggle()}) {
self.expand.toggle()} HStack{
) { Text(options[index].1.description)
HStack{ .textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20)
Text(answer.response) Text(options[index].2.description)
.textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20) .textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10)
Text("\(answer.odds, specifier: "%.2f")") Spacer()
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10) }
Spacer()
} }
} .padding(.bottom, 15)
.padding(.bottom, 15)
} }
} }
} }
@ -64,3 +70,15 @@ struct DropDownAnswerMenu: View {
) )
} }
} }
struct DropDownAnswerMenu_Previews: PreviewProvider {
static var previews: some View {
DropDownAnswerMenu(selectedOption: .constant(0), options: [
(0, "questionMarkIcon", 1.2),
(1, "footballIcon", 2.2),
(2, "paintbrushIcon", 3.3)
])
.preferredColorScheme(.dark)
}
}

@ -6,19 +6,25 @@
// //
import SwiftUI import SwiftUI
import Model
struct DropDownFriends: View { struct DropDownFriends: View {
@Binding var selectedItems: Set<String> @State private var selectedItems: Set<Int> = []
@State var expand = false @State var expand = false
var friends: [User] let friends: [(Int, Int, String, String)] = [
(0, 541, "David", "defaultUserImage"),
(1, 541, "David", "defaultUserImage"),
(2, 541, "David", "defaultUserImage"),
(3, 541, "David", "defaultUserImage"),
(4, 541, "David", "defaultUserImage"),
(5, 541, "David", "defaultUserImage")
]
var body: some View { var body: some View {
VStack(spacing: 0, content: { VStack(spacing: 0, content: {
Button(action: { self.expand.toggle() }) { Button(action: { self.expand.toggle() }) {
HStack(spacing: 3){ HStack(spacing: 3){
Text(friends.count.description) Text("41")
.textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 15) .textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 15)
Text("bet_creation_friends_available_format") Text("bet_creation_friends_available_format")
.textStyle(weight: .regular, color: AllInColors.grey800Color, size: 15) .textStyle(weight: .regular, color: AllInColors.grey800Color, size: 15)
@ -36,33 +42,33 @@ struct DropDownFriends: View {
.foregroundColor(AllInColors.delimiterGrey) .foregroundColor(AllInColors.delimiterGrey)
ScrollView(.vertical) { ScrollView(.vertical) {
VStack(spacing: 0) { VStack(spacing: 0) {
ForEach(friends, id: \.self) { (friend: User) in ForEach(0..<friends.count, id: \.self) { item in
HStack { HStack {
Circle() Circle()
.fill(selectedItems.contains(friend.id) ? AllInColors.lightPurpleColor : Color.clear) .fill(selectedItems.contains(friends[item].0) ? AllInColors.lightPurpleColor : Color.clear)
.overlay( .overlay(
Circle() Circle()
.stroke(selectedItems.contains(friend.id) ? Color.clear : AllInColors.skyBlueColor, lineWidth: 1) .stroke(selectedItems.contains(friends[item].0) ? Color.clear : AllInColors.skyBlueColor, lineWidth: 1)
) )
.frame(width: 15, height: 15) .frame(width: 15, height: 15)
.padding(.trailing, 5) .padding(.trailing, 5)
UserInfo(username: friend.username, value: friend.nbCoins) UserInfo()
.contentShape(Rectangle()) .contentShape(Rectangle())
} }
.padding([.leading, .trailing], 15) .padding([.leading, .trailing], 15)
.padding([.top, .bottom], 5) .padding([.top, .bottom], 5)
.overlay( .overlay(
selectedItems.contains(friend.id) ? selectedItems.contains(friends[item].0) ?
Rectangle() Rectangle()
.fill(AllInColors.lightPurpleColor.opacity(0.13)) .fill(AllInColors.lightPurpleColor.opacity(0.13))
: nil : nil
) )
.opacity(1.0) .opacity(1.0)
.onTapGesture { .onTapGesture {
if selectedItems.contains(friend.id) { if selectedItems.contains(friends[item].0) {
selectedItems.remove(friend.id) selectedItems.remove(friends[item].0)
} else { } else {
selectedItems.insert(friend.id) selectedItems.insert(friends[item].0)
} }
} }
Rectangle() Rectangle()
@ -84,3 +90,9 @@ struct DropDownFriends: View {
) )
} }
} }
struct DropDownFriends_Previews: PreviewProvider {
static var previews: some View {
DropDownFriends()
}
}

@ -20,8 +20,6 @@ struct EmptyInfo: View {
} }
} }
struct EmptyInfo_Previews: PreviewProvider { #Preview {
static var previews: some View { EmptyInfo(emoji:"👥", title: "Vous navez pas encore damis", explain: "Ajoutez les depuis cet écran")
EmptyInfo(emoji:"👥", title: "Vous navez pas encore damis", explain: "Ajoutez les depuis cet écran")
}
} }

@ -29,7 +29,10 @@ struct Friend: View {
var body: some View { var body: some View {
HStack{ HStack{
UserPicture(picture: user.image,username: user.username, size: 45) AsyncImage(url: URL(string: "https://picsum.photos/536/354"))
.frame(width: 50, height: 50)
.cornerRadius(180)
.scaledToFit()
Text(user.username) Text(user.username)
.fontWeight(.medium) .fontWeight(.medium)
.padding(.leading, 5) .padding(.leading, 5)

@ -14,19 +14,24 @@ struct Menu: View {
let parameters: [(String, String, String, String)] = [ let parameters: [(String, String, String, String)] = [
("videoGameImage", String(localized: "drawer_create_a_bet"), String(localized: "drawer_create_a_bet_subtitle"), "CreationBet"), ("videoGameImage", String(localized: "drawer_create_a_bet"), String(localized: "drawer_create_a_bet_subtitle"), "CreationBet"),
("globeImage", String(localized: "drawer_public_bets"), String(localized: "drawer_public_bets_subtitle"), "Bet"),
("moneyImage", String(localized: "drawer_current_bets"), String(localized: "drawer_current_bets_subtitle"), "Current"),
("eyesImage", String(localized: "drawer_bet_history"), String(localized: "drawer_bet_history_subtitle"),"Historic"), ("eyesImage", String(localized: "drawer_bet_history"), String(localized: "drawer_bet_history_subtitle"),"Historic"),
("friendsImage", String(localized: "drawer_friends"), String(localized: "drawer_friends_subtitle"), "Friends"), ("friendsImage", String(localized: "drawer_friends"), String(localized: "drawer_friends_subtitle"), "Friends"),
("moneyImage", String(localized: "drawer_public_bets"), String(localized: "drawer_public_bets_subtitle"), "Bet"),
("rankingImage", String(localized: "drawer_ranking"), String(localized: "drawer_ranking_subtitle"), "Ranking"), ("rankingImage", String(localized: "drawer_ranking"), String(localized: "drawer_ranking_subtitle"), "Ranking"),
("eyesImage", String(localized: "drawer_current_bets"), String(localized: "drawer_current_bets_subtitle"), "Current")
] ]
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
HStack() { HStack() {
Spacer() Spacer()
VStack(){ VStack(){
UserPicture(picture: AppStateContainer.shared.user?.image, username: (AppStateContainer.shared.user?.username)!,size: 100) Image("defaultUserImage")
.resizable()
.scaledToFit()
.frame(width: 100, height: 100)
.cornerRadius(180)
Text(AppStateContainer.shared.user?.username.capitalized ?? "") Text(AppStateContainer.shared.user?.username.capitalized ?? "")
.fontWeight(.medium) .fontWeight(.medium)
.font(.system(size: 17)) .font(.system(size: 17))
@ -39,7 +44,7 @@ struct Menu: View {
HStack(spacing: 30) { HStack(spacing: 30) {
Spacer() Spacer()
VStack(){ VStack(){
Text(AppStateContainer.shared.user?.bestWin ?? 0, format: .number) Text("114")
.fontWeight(.heavy) .fontWeight(.heavy)
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(.white) .foregroundColor(.white)
@ -49,7 +54,7 @@ struct Menu: View {
.foregroundColor(AllInColors.grey600Color) .foregroundColor(AllInColors.grey600Color)
} }
VStack(){ VStack(){
Text(AppStateContainer.shared.user!.bestWin, format: .number) Text("343")
.fontWeight(.heavy) .fontWeight(.heavy)
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(.white) .foregroundColor(.white)
@ -59,7 +64,7 @@ struct Menu: View {
.foregroundColor(AllInColors.grey600Color) .foregroundColor(AllInColors.grey600Color)
} }
VStack(){ VStack(){
Text(AppStateContainer.shared.user!.nbFriends, format: .number) Text("5")
.fontWeight(.heavy) .fontWeight(.heavy)
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(.white) .foregroundColor(.white)
@ -103,9 +108,6 @@ struct Menu: View {
.frame(maxWidth: .infinity,alignment: .leading) .frame(maxWidth: .infinity,alignment: .leading)
.background(AllInColors.primaryColor) .background(AllInColors.primaryColor)
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)
.onAppear {
authService.refreshAuthentication()
}
} }
} }

@ -14,7 +14,7 @@ struct OddCapsule: View {
var odd: Float = 0.0 var odd: Float = 0.0
var body: some View { var body: some View {
HStack(alignment: .center) { HStack(alignment: .center) {
Text("x\(odd, specifier: "%.2f")") Text("x\(odd.description)")
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(foregroundColor) .foregroundColor(foregroundColor)
} }

@ -15,8 +15,6 @@ struct ParticipateButton: View {
var bet: Bet? var bet: Bet?
var isDisabled: Bool { var isDisabled: Bool {
guard bet?.author != AppStateContainer.shared.user?.username else { return true }
if let betType = bet?.status { if let betType = bet?.status {
switch betType { switch betType {
case .inProgress: case .inProgress:

@ -0,0 +1,35 @@
//
// ParticipationCell.swift
// AllIn
//
// Created by Lucas Delanier on 21/01/2024.
//
import SwiftUI
import Model
struct ParticipationCell: View {
@State var participation: Participation
var body: some View {
HStack(alignment: .center, spacing: 0){
Circle()
.frame(width: 30, height: 30)
.foregroundColor(AllInColors.grey700Color)
.padding(.trailing, 7)
Text(participation.username)
.font(.system(size: 15))
.foregroundStyle(AllInColors.primaryTextColor)
.fontWeight(.semibold)
Spacer()
Text(participation.stake.description)
.font(.system(size: 18))
.foregroundStyle(AllInColors.lightPurpleColor)
.fontWeight(.bold)
.padding(.trailing, 8)
Image("PurpleAllCoin")
.resizable()
.frame(width: 11, height: 12)
}
}
}

@ -6,25 +6,33 @@
// //
import SwiftUI import SwiftUI
import Model
struct ParticipationModal: View { struct ParticipationModal: View {
@Binding var selectedAnswer: AnswerDetail @Binding private var selectedOption: Int
@Binding var mise: String @Binding private var mise: String
var phrase: String private var description: String
var answers: [AnswerDetail] var participationAddedCallback: (() -> Void)?
var participationAddedCallback: () -> Void
var checkAndSetError: () -> Bool
var possibleGain: Int { var possibleGain: Int {
if let stake = Float(mise) { if let stake = Float(mise), let selectedOption = options.first(where: { $0.0 == self.selectedOption }) {
return Int(round(stake * selectedAnswer.odds)) return Int(round(stake * selectedOption.2))
} else { } else {
return 0 return 0
} }
} }
init(answer: Binding<Int>, mise: Binding<String>, description: String, participationAddedCallback: (() -> Void)? = nil) {
self._selectedOption = answer
self._mise = mise
self.description = description
self.participationAddedCallback = participationAddedCallback
}
let options: [(Int, String, Float)] = [
(0, "OUI", 1.2),
(1, "NON", 3.3),
]
var body: some View { var body: some View {
GeometryReader { geometry in GeometryReader { geometry in
VStack(alignment: .leading){ VStack(alignment: .leading){
@ -48,12 +56,12 @@ struct ParticipationModal: View {
} }
.padding(.leading, 15) .padding(.leading, 15)
VStack(alignment: .leading){ VStack(alignment: .leading){
Text(phrase) Text(description)
.font(.system(size: 13)) .font(.system(size: 13))
.foregroundColor(AllInColors.primaryTextColor) .foregroundColor(AllInColors.primaryTextColor)
.fontWeight(.light) .fontWeight(.light)
DropDownAnswerMenu(selectedAnswer: $selectedAnswer, answers: answers) DropDownAnswerMenu(selectedOption: $selectedOption, options: options)
TextField("", text: $mise, prompt: Text("generic_stake") TextField("", text: $mise, prompt: Text("generic_stake")
.foregroundColor(AllInColors.lightGrey300Color) .foregroundColor(AllInColors.lightGrey300Color)
@ -96,7 +104,7 @@ struct ParticipationModal: View {
.padding(.top, 10) .padding(.top, 10)
.padding(.bottom, 0) .padding(.bottom, 0)
Button { Button {
participationAddedCallback() participationAddedCallback?()
} label: { } label: {
Text("Miser") Text("Miser")
.font(.system(size: 23)) .font(.system(size: 23))
@ -117,4 +125,16 @@ struct ParticipationModal: View {
.background(AllInColors.underComponentBackgroundColor) .background(AllInColors.underComponentBackgroundColor)
} }
} }
func checkAndSetError() -> Bool {
if let stake = Int(mise) {
if stake <= AppStateContainer.shared.user?.nbCoins ?? 0 && stake > 0 {
return false
} else {
return true
}
} else {
return true
}
}
} }

@ -10,7 +10,7 @@ import SwiftUI
struct RankingRow: View { struct RankingRow: View {
var number: Int var number: Int
var image: String? var image: String
var pseudo: String var pseudo: String
var allCoins: Int var allCoins: Int
@ -18,12 +18,29 @@ struct RankingRow: View {
HStack(){ HStack(){
Text(number.description) Text(number.description)
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 18) .textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 18)
UserInfo(username: pseudo, picture: image, value: allCoins) .padding(.leading, 15)
Image(image)
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
.cornerRadius(180)
.padding([.bottom,.top], 10)
Text(pseudo)
.fontWeight(.medium)
.font(.system(size: 16))
.lineLimit(1)
Spacer()
Image("allcoinIcon")
.resizable()
.frame(width: 17, height: 17, alignment: .leading)
Text(allCoins.description)
.textStyle(weight: .black, color: AllInColors.lightPurpleColor, size: 16)
.padding(.trailing, 15)
} }
.padding(10)
.padding(.horizontal, 5)
.background(AllInColors.componentBackgroundColor) .background(AllInColors.componentBackgroundColor)
.cornerRadius(8) .cornerRadius(8)
.padding([.leading,.trailing],20)
.frame(maxWidth: 750) .frame(maxWidth: 750)
} }
} }

@ -6,11 +6,9 @@
// //
import SwiftUI import SwiftUI
import Model
struct RecapBetCard: View { struct RecapBetCard: View {
var betResult: BetResultDetail
@GestureState private var longPressTap = false @GestureState private var longPressTap = false
@State private var isPressed = false @State private var isPressed = false
@State var showDetails: Bool = false @State var showDetails: Bool = false
@ -21,22 +19,22 @@ struct RecapBetCard: View {
VStack(alignment: .leading,spacing: 2){ VStack(alignment: .leading,spacing: 2){
HStack{ HStack{
Spacer() Spacer()
Text("bet_proposed_by_format \(betResult.bet.author)") Text("bet_proposed_by_format \("Lucas")")
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
} }
Text(betResult.bet.theme) Text("Etudes")
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
Text(betResult.bet.phrase) Text("Emre va réussir son TP de CI/CD mercredi?")
.font(.system(size: 20)) .font(.system(size: 20))
.fontWeight(.bold) .fontWeight(.bold)
HStack{ HStack{
Text("bet_ends") Text("bet_ends")
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
TextCapsule(date: betResult.bet.endBetDate) TextCapsule(date: Date())
Spacer() Spacer()
} }
} }
@ -50,7 +48,7 @@ struct RecapBetCard: View {
Text("Mise") Text("Mise")
.textStyle(weight: .regular, color: AllInColors.grey800Color, size: 15) .textStyle(weight: .regular, color: AllInColors.grey800Color, size: 15)
Spacer() Spacer()
Text(betResult.participation.stake.description) Text("1630")
.textStyle(weight: .regular, color: AllInColors.grey800Color, size: 15) .textStyle(weight: .regular, color: AllInColors.grey800Color, size: 15)
Image("Allcoins") Image("Allcoins")
.resizable() .resizable()
@ -67,13 +65,13 @@ struct RecapBetCard: View {
Text("Gains") Text("Gains")
.textStyle(weight: .medium, color: AllInColors.lightPurpleColor, size: 15) .textStyle(weight: .medium, color: AllInColors.lightPurpleColor, size: 15)
Spacer() Spacer()
Text(betResult.amount.description) Text("1630")
.font(.system(size: 15)) .font(.system(size: 15))
.fontWeight(.medium) .fontWeight(.medium)
.overlay { .overlay {
AllInColors.primaryGradient.frame(width: 50) AllInColors.primaryGradient.frame(width: 50)
.mask( .mask(
Text(betResult.amount.description).font(.system(size: 15)).fontWeight(.medium) Text("1630").font(.system(size: 15)).fontWeight(.medium)
) )
} }
.padding(0) .padding(0)
@ -89,8 +87,7 @@ struct RecapBetCard: View {
HStack{ HStack{
Text("Côte totale").font(.system(size: 15)).fontWeight(.medium) Text("Côte totale").font(.system(size: 15)).fontWeight(.medium)
Spacer() Spacer()
// TODO bind le odd Text("3,46")
Text("1,0")
.textStyle(weight: .bold, color: .white, size: 18) .textStyle(weight: .bold, color: .white, size: 18)
.padding([.leading,.trailing],10) .padding([.leading,.trailing],10)
.padding([.top,.bottom],5) .padding([.top,.bottom],5)
@ -111,7 +108,7 @@ struct RecapBetCard: View {
.onTapGesture { .onTapGesture {
showDetails.toggle() showDetails.toggle()
}.fullScreenCover(isPresented: $showDetails) { }.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, isModalParticipated: $showPartipated, id: betResult.bet.id) DetailsView(isModalPresented: $showDetails, isModalParticipated: $showPartipated,id: "1")
} }
.gesture( .gesture(
LongPressGesture(minimumDuration: 0.5) LongPressGesture(minimumDuration: 0.5)
@ -121,3 +118,10 @@ struct RecapBetCard: View {
) )
} }
} }
struct RecapBetCard_Previews: PreviewProvider {
static var previews: some View {
RecapBetCard()
.preferredColorScheme(.dark)
}
}

@ -6,29 +6,26 @@
// //
import SwiftUI import SwiftUI
import Model
struct ResultBanner: View { struct ResultBanner: View {
var finalAnswer: Participation
var odds: Float
var body: some View { var body: some View {
VStack{ VStack{
HStack{ HStack{
Image(systemName: "trophy.fill").resizable().frame(maxWidth: 70, maxHeight: 60).foregroundColor(AllInColors.blueGrey800Color) Image("BleueTrophyIcon").resizable().frame(maxWidth: 70, maxHeight: 60)
Text(finalAnswer.answer).font(.system(size: 70)).fontWeight(.bold).foregroundStyle(AllInColors.blueGrey800Color) Text("OUI").font(.system(size: 70)).fontWeight(.bold).foregroundStyle(AllInColors.blueGrey800Color)
}.frame(height: 80) }.frame(height: 80)
HStack(spacing: 20){ HStack(spacing: 20){
HStack{ HStack{
Image("blueAllCoinIcon").resizable().frame(maxWidth: 12, maxHeight: 12) Image("BlueAllCoinIcon").resizable().frame(maxWidth: 12, maxHeight: 12)
Text(finalAnswer.stake.description).font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color) Text("460").font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color)
} }
HStack{ HStack{
Image("bluePersonIcon").resizable().frame(maxWidth: 15, maxHeight: 12) Image("BleuePersonIcon").resizable().frame(maxWidth: 15, maxHeight: 12)
Text(finalAnswer.username).font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color) Text("ImriDu43").font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color)
} }
HStack{ HStack{
Image("blueTrophyIcon").resizable().frame(maxWidth: 15, maxHeight: 12) Image("BleueTrophyIcon").resizable().frame(maxWidth: 15, maxHeight: 12)
Text("\(odds, specifier: "%.2f")").font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color) Text("x1.2").font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color)
} }
} }
} }

@ -12,25 +12,26 @@ struct ReviewCard: View {
@State var showDetails: Bool = false @State var showDetails: Bool = false
@State var showPartipated: Bool = false @State var showPartipated: Bool = false
var bet: Bet @State var betDetail: BetDetail
var amount: Int
var isWin: Bool var amountBetted: Int
var isAWin: Bool
var body: some View { var body: some View {
VStack(spacing: 0){ VStack(spacing: 0){
VStack(alignment: .leading,spacing: 2){ VStack(alignment: .leading,spacing: 2){
HStack{ HStack{
Spacer() Spacer()
Text("bet_proposed_by_format \(bet.author)") Text("bet_proposed_by_format \(betDetail.bet.author)")
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
} }
Text(bet.theme).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) Text(betDetail.bet.theme).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
Text(bet.phrase).font(.system(size: 20)).fontWeight(.bold) Text(betDetail.bet.phrase).font(.system(size: 20)).fontWeight(.bold)
HStack{ HStack{
Text("bet_ends").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) Text("bet_ends").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
TextCapsule(date: bet.endBetDate) TextCapsule(date: betDetail.bet.endBetDate)
Spacer() Spacer()
} }
@ -39,37 +40,25 @@ struct ReviewCard: View {
.padding(.all,15) .padding(.all,15)
.background(AllInColors.componentBackgroundColor) .background(AllInColors.componentBackgroundColor)
.cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0) .cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0)
VStack(alignment: .center,spacing:0){ VStack(alignment: .center,spacing:0){
HStack(){ HStack(){
Spacer() Spacer()
if bet.status == .finished { if(betDetail.bet.endBetDate < Date()){
Text(amount.description) Text("bet_finished")
.foregroundColor(.white) .foregroundColor(.white)
.font(.system(size: 25)) .font(.system(size: 25))
.fontWeight(.bold) .fontWeight(.bold)
Image("allcoinWhiteIcon")
.resizable()
.frame(width: 18, height: 20)
} }
else{
switch bet.status { Text(amountBetted.description)
case .waiting, .inProgress:
Text("bet_status_stake")
.foregroundColor(.white) .foregroundColor(.white)
.font(.system(size: 25)) .font(.system(size: 25))
.fontWeight(.bold) .fontWeight(.bold)
case .closing: Image("allcoinWhiteIcon")
Text("bet_status_finished") .resizable()
.foregroundColor(.white) .frame(width: 20, height: 20, alignment: .bottom)
.font(.system(size: 25)) Text(isAWin ? "Gagnés!" : "Perdus!")
.fontWeight(.bold)
case .finished:
Text(isWin ? "Gagnés!" : "Perdus!")
.foregroundColor(.white)
.font(.system(size: 25))
.fontWeight(.bold)
case .cancelled:
Text("cancelled")
.foregroundColor(.white) .foregroundColor(.white)
.font(.system(size: 25)) .font(.system(size: 25))
.fontWeight(.bold) .fontWeight(.bold)
@ -83,31 +72,17 @@ struct ReviewCard: View {
} }
.frame(width: .infinity) .frame(width: .infinity)
.padding(.all,2) .padding(.all,2)
.background(backgroundColor()) .background(
.cornerRadius(20, corners: [.bottomLeft,.bottomRight]) isAWin || betDetail.bet.endBetDate < Date() ?
AnyView(AllInColors.primaryGradient) :
AnyView(Color.black)
) .cornerRadius(20, corners: [.bottomLeft,.bottomRight])
.border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
} }
.onTapGesture { .onTapGesture {
showDetails.toggle() showDetails.toggle()
}.fullScreenCover(isPresented: $showDetails) { }.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, isModalParticipated: $showPartipated, id: bet.id) DetailsView(isModalPresented: $showDetails, isModalParticipated: $showPartipated, id: betDetail.bet.id)
} }
} }
private func backgroundColor() -> some View {
Group {
if bet.status == .finished && isWin {
AllInColors.primaryGradient
} else {
switch bet.status {
case .inProgress, .waiting, .closing:
AllInColors.grey50Color
case .finished:
Color.black
case .cancelled:
Color.red
}
}
}
}
} }

@ -12,7 +12,6 @@ struct TrendingBetCard: View {
var bet: Bet var bet: Bet
@State var showDetails: Bool = false @State var showDetails: Bool = false
@State var showParticipate: Bool = false
var body: some View { var body: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
@ -62,12 +61,6 @@ struct TrendingBetCard: View {
.stroke(AllInColors.primaryGradient, lineWidth: 5) .stroke(AllInColors.primaryGradient, lineWidth: 5)
) )
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous)) .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
.onTapGesture {
showDetails.toggle()
}
.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, isModalParticipated: $showParticipate, id: bet.id)
}
} }
} }
@ -77,9 +70,10 @@ struct TrendingBetCard_Previews: PreviewProvider {
phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.",
endRegisterDate: Date().addingTimeInterval(86400), endRegisterDate: Date().addingTimeInterval(86400),
endBetDate: Date().addingTimeInterval(172800), endBetDate: Date().addingTimeInterval(172800),
isPrivate: true, isPublic: true,
status: .inProgress, status: .inProgress,
invited: [], invited: [],
author: "Imri")) author: "Imri",
registered: []))
} }
} }

@ -6,29 +6,27 @@
// //
import SwiftUI import SwiftUI
import Model
struct UserInfo: View { struct UserInfo: View {
var username: String
var picture: String?
var value: Int
var body: some View { var body: some View {
HStack { HStack {
UserPicture(picture: picture, username: username, size: 35) Image("defaultUserImage")
.padding(.trailing, 7) .resizable()
Text(username) .frame(width: 35, height: 35)
.font(.system(size: 15)) Text("David")
.foregroundStyle(AllInColors.primaryTextColor) .textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 13)
.fontWeight(.semibold)
Spacer() Spacer()
Text(value.description) Image("allcoinIcon")
.font(.system(size: 18))
.foregroundStyle(AllInColors.lightPurpleColor)
.fontWeight(.bold)
.padding(.trailing, 4)
Image("PurpleAllCoin")
.resizable() .resizable()
.frame(width: 15, height: 16) .frame(width: 17, height: 17, alignment: .leading)
Text("541")
.textStyle(weight: .black, color: AllInColors.lightPurpleColor, size: 16)
} }
} }
} }
struct UserInfo_Previews: PreviewProvider {
static var previews: some View {
UserInfo()
}
}

@ -6,19 +6,22 @@
// //
import SwiftUI import SwiftUI
import Model
struct UsersPreview: View { struct UsersPreview: View {
var users: [User]?
var body: some View { var body: some View {
if users != nil { HStack(spacing: -20){
HStack(spacing: -20){ Image("defaultUserImage")
ForEach(users!.prefix(4)) { user in .resizable()
Image("defaultUserImage") .frame(width: 35, height: 35)
.resizable() Image("defaultUserImage")
.frame(width: 35, height: 35) .resizable()
} .frame(width: 35, height: 35)
} Image("defaultUserImage")
.resizable()
.frame(width: 35, height: 35)
Image("defaultUserImage")
.resizable()
.frame(width: 35, height: 35)
} }
} }
} }

@ -6,11 +6,9 @@
// //
import SwiftUI import SwiftUI
import Model
struct WinModal: View { struct WinModal: View {
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
var betResult: BetResultDetail
@State var xOffset: CGFloat = 0 @State var xOffset: CGFloat = 0
var body: some View { var body: some View {
@ -37,15 +35,15 @@ struct WinModal: View {
} }
HStack{ HStack{
Text("FÉLICITATIONS").font(.system(size: 20)).foregroundColor(.white).fontWeight(.semibold).italic() Text("FÉLICITATIONS").font(.system(size: 20)).foregroundColor(.white).fontWeight(.semibold).italic()
Text(AppStateContainer.shared.user?.username ?? "").padding(.top,9).font(.system(size: 33)).fontWeight(.heavy).foregroundColor(.white) Text("PSEUDO!").padding(.top,9).font(.system(size: 33)).fontWeight(.heavy).foregroundColor(.white)
} }
.rotationEffect(.degrees(-4)) .rotationEffect(.degrees(-4))
.padding(.top,40) .padding(.top,40)
Spacer() Spacer()
AllcoinsCapsule(gains: betResult.amount) AllcoinsCapsule()
Spacer() Spacer()
RecapBetCard(betResult: betResult) RecapBetCard()
Spacer() Spacer()
} }
.padding([.all],20) .padding([.all],20)
@ -60,6 +58,12 @@ struct WinModal: View {
} }
} }
struct WinModal_Previews: PreviewProvider {
static var previews: some View {
WinModal()
}
}
struct InfiniteScroller<Content: View>: View { struct InfiniteScroller<Content: View>: View {
var contentWidth: CGFloat var contentWidth: CGFloat
var content: (() -> Content) var content: (() -> Content)

@ -1,58 +0,0 @@
//
// userPicture.swift
// AllIn
//
// Created by Lucas Delanier on 04/06/2024.
//
import SwiftUI
struct UserPicture: View {
var picture: String?
var username: String
var size: CGFloat
var body: some View {
ZStack {
if let pictureURL = picture {
userImage(url: pictureURL)
} else {
placeholderImage
}
}
}
@MainActor private func userImage(url: String) -> some View {
AsyncCachedImage(url: URL(string: url)) { image in
image
.resizable()
.frame(width: size, height: size)
.clipShape(Circle())
} placeholder: {
placeholderImage
}
}
private var placeholderImage: some View {
Circle()
.foregroundColor(.gray)
.frame(width: size, height: size)
.overlay(
Text(username.prefix(2).uppercased())
.fontWeight(.medium)
.foregroundStyle(.white)
.font(.system(size: fontSize(for: size)))
)
}
private func fontSize(for diameter: CGFloat) -> CGFloat {
let fontScaleFactor: CGFloat = 0.45
return diameter * fontScaleFactor
}
}
struct UserPicture_Previews: PreviewProvider {
static var previews: some View {
UserPicture(picture: nil, username: "Lucas", size: 100)
}
}

@ -77,12 +77,6 @@ struct AllInColors {
endPoint: .trailing endPoint: .trailing
) )
static let BlueBetLineGradiant = LinearGradient(
gradient: Gradient(colors: [AllInColors.blue200, AllInColors.blueAccentColor]),
startPoint: .leading,
endPoint: .trailing
)
static let PinkBetGradiant = LinearGradient( static let PinkBetGradiant = LinearGradient(
gradient: Gradient(colors: [AllInColors.pink100, AllInColors.pink200]), gradient: Gradient(colors: [AllInColors.pink100, AllInColors.pink200]),
startPoint: .leading, startPoint: .leading,

@ -46,13 +46,15 @@
"drawer_nb_friends" = "Friends"; "drawer_nb_friends" = "Friends";
"drawer_friends" = "FRIENDS"; "drawer_friends" = "FRIENDS";
"drawer_friends_subtitle" = "Challenge your folks by adding them as friends."; "drawer_friends_subtitle" = "Challenge your folks by adding them as friends.";
"drawer_public_bets" = "PARTICIPATE"; "drawer_public_bets" = "PUBLIC BETS";
"drawer_public_bets_subtitle" = "Browse the most popular bets of the moment."; "drawer_public_bets_subtitle" = "Browse the most popular bets of the moment.";
"drawer_create_a_bet" = "NEW BET"; "drawer_current_bets" = "CURRENT BETS";
"drawer_current_bets_subtitle" = "View your current bets.";
"drawer_create_a_bet" = "CREATE A BET";
"drawer_create_a_bet_subtitle" = "Create a net bet and get your friends participating."; "drawer_create_a_bet_subtitle" = "Create a net bet and get your friends participating.";
"drawer_bet_history" = "HISTORY"; "drawer_bet_history" = "BET HISTORY";
"drawer_bet_history_subtitle" = "View your current and finished bets."; "drawer_bet_history_subtitle" = "View your current and finished bets.";
"drawer_current_bets" = "MY PARTICIPATIONS"; "drawer_current_bets" = "CURRENT BETS";
"drawer_current_bets_subtitle" = "Manage your bets and reward the winners."; "drawer_current_bets_subtitle" = "Manage your bets and reward the winners.";
"drawer_ranking" = "RANKING"; "drawer_ranking" = "RANKING";
"drawer_ranking_subtitle" = "Check your ranking among your friends."; "drawer_ranking_subtitle" = "Check your ranking among your friends.";
@ -133,7 +135,7 @@
"bet_participate" = "Participate"; "bet_participate" = "Participate";
"bet_proposed_by_format %@" = "Proposed by %@"; "bet_proposed_by_format %@" = "Proposed by %@";
"bet_proposed_by_format" = "Proposed by"; "bet_proposed_by_format" = "Proposed by";
"bet_players_waiting_format %@" = "%@ players waiting"; "bet_players_waiting_format %@" = "%@ joueurs en attente";
"bet_players_format" = "players"; "bet_players_format" = "players";
"bet_points_at_stake_format" = "points at stake"; "bet_points_at_stake_format" = "points at stake";
@ -148,7 +150,6 @@
"bet_status_participants_list" = "Participants"; "bet_status_participants_list" = "Participants";
"bet_status_details_drawer" = "Details"; "bet_status_details_drawer" = "Details";
"participation_possible_winnings" = "Possible winnings"; "participation_possible_winnings" = "Possible winnings";
"bet_status_stake" = "Gambled";
/// Bet history /// Bet history
@ -178,7 +179,7 @@
/// Notification /// Notification
"notification_title_end_bet_date" = "Who will be the winners?"; "notification_title_end_bet_date" = "Who will be the winners?";
"notification_subtitle_end_bet_date %@" = "The %@ bet has reached its deadline. Go to the app to enter the winning answer."; "notification_subtitle_end_bet_date %@" = "The %@ bet has reached its deadline. Go to the app to enter the winning answer.";`
/// Empty Views /// Empty Views
@ -187,8 +188,3 @@
"empty_bets_title"= "No bet matches your search"; "empty_bets_title"= "No bet matches your search";
"empty_friends_title" = "You don't have any friends yet"; "empty_friends_title" = "You don't have any friends yet";
"empty_friends_explain" = "Add them from this screen"; "empty_friends_explain" = "Add them from this screen";
/// Error Messages
"error_title" = "Error: Failed to Load Content.";
"error_message" = "The content you are trying to load could not be retrieved. Please check your internet connection and try again";

@ -46,13 +46,15 @@
"drawer_nb_friends" = "Amis"; "drawer_nb_friends" = "Amis";
"drawer_friends" = "AMIS"; "drawer_friends" = "AMIS";
"drawer_friends_subtitle" = "Défiez vos proches en les ajoutant en amis."; "drawer_friends_subtitle" = "Défiez vos proches en les ajoutant en amis.";
"drawer_public_bets" = "PARTICIPER"; "drawer_public_bets" = "BETS PUBLIQUES";
"drawer_public_bets_subtitle" = "Parcourez les bets les plus populaires du moment."; "drawer_public_bets_subtitle" = "Parcourez les bets les plus populaires du moment.";
"drawer_create_a_bet" = "NOUVEAU BET"; "drawer_current_bets" = "BETS EN COURS";
"drawer_current_bets_subtitle" = "Consultez vos paris en cours.";
"drawer_create_a_bet" = "CREER UN BET";
"drawer_create_a_bet_subtitle" = "Créez un nouveau bet et faites participer vos amis."; "drawer_create_a_bet_subtitle" = "Créez un nouveau bet et faites participer vos amis.";
"drawer_bet_history" = "HISTORIQUE"; "drawer_bet_history" = "HISTORIQUE DES BETS";
"drawer_bet_history_subtitle" = "Consultez vos paris en cours et terminés."; "drawer_bet_history_subtitle" = "Consultez vos paris en cours et terminés.";
"drawer_current_bets" = "MES PARTICIPATIONS"; "drawer_current_bets" = "BETS EN COURS";
"drawer_current_bets_subtitle" = "Gérez vos bets et récompensez les gagnants."; "drawer_current_bets_subtitle" = "Gérez vos bets et récompensez les gagnants.";
"drawer_ranking" = "CLASSEMENT"; "drawer_ranking" = "CLASSEMENT";
"drawer_ranking_subtitle" = "Consultez votre classement parmis vos amis."; "drawer_ranking_subtitle" = "Consultez votre classement parmis vos amis.";
@ -133,7 +135,7 @@
"bet_participate" = "Participer"; "bet_participate" = "Participer";
"bet_proposed_by_format %@" = "Proposé par %@"; "bet_proposed_by_format %@" = "Proposé par %@";
"bet_proposed_by_format" = "Proposé par"; "bet_proposed_by_format" = "Proposé par";
"bet_players_waiting_format %@" = "%@ joueurs en attente"; "bet_players_waiting_format %@" = "%@ players waiting";
"bet_players_format" = "joueurs"; "bet_players_format" = "joueurs";
"bet_points_at_stake_format" = "points en jeu"; "bet_points_at_stake_format" = "points en jeu";
@ -148,7 +150,6 @@
"bet_status_participants_list" = "Liste des participants"; "bet_status_participants_list" = "Liste des participants";
"bet_status_details_drawer" = "Détails"; "bet_status_details_drawer" = "Détails";
"participation_possible_winnings" = "Gains possibles"; "participation_possible_winnings" = "Gains possibles";
"bet_status_stake" = "Pariés";
/// Bet history /// Bet history
@ -187,8 +188,3 @@
"empty_bets_title"= "Aucun Bet ne correspond à votre recherche"; "empty_bets_title"= "Aucun Bet ne correspond à votre recherche";
"empty_friends_title" = "Vous navez pas encore damis"; "empty_friends_title" = "Vous navez pas encore damis";
"empty_friends_explain" = "Ajoutez les depuis cet écran"; "empty_friends_explain" = "Ajoutez les depuis cet écran";
/// Error Messages
"error_title" = "Erreur : Échec du chargement du contenu.";
"error_message" = "Le contenu que vous essayez de charger n'a pas pu être récupéré. Veuillez vérifier votre connexion internet et réessayer.";

@ -148,7 +148,7 @@ class AuthService: IAuthService {
} }
private func initManagerVM(token: String) { private func initManagerVM(token: String) {
DependencyInjection.shared.addSingleton(Manager.self, Manager(withBetDataManager: BetApiManager(withUserToken: token, andApiUrl: Config.allInApi), withUserDataManager: UserApiManager(withUserToken: token, andApiUrl: Config.allInApi))) DependencyInjection.shared.addSingleton(Manager.self, Manager(withBetDataManager: BetApiManager(withUserToken: token), withUserDataManager: UserApiManager(withUserToken: token)))
} }
public func logout() { public func logout() {

@ -1,71 +0,0 @@
//
// asyncCachedImage.swift
// AllIn
//
// Created by Lucas Delanier on 06/06/2024.
//
import SwiftUI
@MainActor
struct AsyncCachedImage<ImageView: View, PlaceholderView: View>: View {
// Input dependencies
var url: URL?
@ViewBuilder var content: (Image) -> ImageView
@ViewBuilder var placeholder: () -> PlaceholderView
// Downloaded image
@State var image: UIImage? = nil
init(
url: URL?,
@ViewBuilder content: @escaping (Image) -> ImageView,
@ViewBuilder placeholder: @escaping () -> PlaceholderView
) {
self.url = url
self.content = content
self.placeholder = placeholder
}
var body: some View {
VStack {
if let uiImage = image {
content(Image(uiImage: uiImage))
} else {
placeholder()
.onAppear {
Task {
image = await downloadPhoto()
}
}
}
}
}
// Downloads if the image is not cached already
// Otherwise returns from the cache
private func downloadPhoto() async -> UIImage? {
do {
guard let url else { return nil }
// Check if the image is cached already
if let cachedResponse = URLCache.shared.cachedResponse(for: .init(url: url)) {
return UIImage(data: cachedResponse.data)
} else {
let (data, response) = try await URLSession.shared.data(from: url)
// Save returned image data into the cache
URLCache.shared.storeCachedResponse(.init(response: response, data: data), for: .init(url: url))
guard let image = UIImage(data: data) else {
return nil
}
return image
}
} catch {
print("Error downloading: \(error)")
return nil
}
}
}

@ -13,13 +13,11 @@ import Combine
class BetViewModel: ObservableObject { class BetViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Inject var authService: IAuthService
@Published var popularBet: Bet? @Published var popularBet: Bet?
@Published private(set) var bets: [Bet] = [] @Published private(set) var bets: [Bet] = []
@Published var betsOver: [BetDetail] = [] @Published var betsOver: [BetDetail] = []
@Published var betsWon: [BetResultDetail] = [] @Published var showingSheet: Bool = false
@Published var showingSheetOver: Bool = false
@Published var showingSheetWon: Bool = false
@Published var filters: Set<BetFilter> = [] { @Published var filters: Set<BetFilter> = [] {
didSet { didSet {
getItems() getItems()
@ -29,8 +27,6 @@ class BetViewModel: ObservableObject {
init() { init() {
getItems() getItems()
getPopularBet() getPopularBet()
getBetsOver()
getBetsWon()
} }
func getItems() { func getItems() {
@ -39,26 +35,11 @@ class BetViewModel: ObservableObject {
self.bets = bets self.bets = bets
} }
} }
}
func getBetsOver() {
manager.getBetsOver() { bets in manager.getBetsOver() { bets in
DispatchQueue.main.async { DispatchQueue.main.async {
self.betsOver = bets self.betsOver = bets
if !self.betsOver.isEmpty { if !self.betsOver.isEmpty {
self.showingSheetOver = true self.showingSheet = true
}
}
}
}
func getBetsWon() {
manager.getBetsWon() { bets in
DispatchQueue.main.async {
self.betsWon = bets
if !self.betsWon.isEmpty {
self.showingSheetWon = true
self.authService.refreshAuthentication()
} }
} }
} }

@ -15,67 +15,30 @@ class CreationBetViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Published var theme: String = "" @Published var theme: String = ""
@Published var description: String = "" @Published var description: String = ""
@Published var isPrivate = false { @Published var isPublic = true
didSet {
invited.removeAll()
}
}
@Published var endRegisterDate = Date() @Published var endRegisterDate = Date()
@Published var endBetDate = Date() @Published var endBetDate = Date()
@Published var betAdded = false @Published var betAdded = false
@Published var selectedTypeBet = 0 { @Published var selectedOption = 0
didSet {
values.removeAll()
groupedItems.removeAll()
response = ""
}
}
@Published var values: [String] = []
@Published var invited: Set<String> = []
@Published var themeFieldError: String? @Published var themeFieldError: String?
@Published var descriptionFieldError: String? @Published var descriptionFieldError: String?
@Published var endRegisterDateFieldError: String? @Published var endRegisterDateFieldError: String?
@Published var endBetDateFieldError: String? @Published var endBetDateFieldError: String?
@Published var responsesFieldError: String?
@Published var errorMessage: String? @Published var errorMessage: String?
@Published var showErrorMessage = false @Published var showErrorMessage = false
@Published var friends: [User] = []
let options: [(Int, String, String)] = [
(0, "questionMarkIcon", String(localized: "bet_type_binary")),
(1, "footballIcon", String(localized: "bet_type_match")),
(2, "paintbrushIcon", String(localized: "bet_type_custom"))
]
@Published var response = ""
@Published var groupedItems: [[String]] = [[String]] ()
init() {
getFriends()
}
func getFriends() {
manager.getFriends() { friends in
DispatchQueue.main.async {
self.friends = friends
}
}
}
func create() { func create() {
guard checkAndSetError(forTheme: true, forDescription: true, forEndRegisterDate: true, forEndBetDate: true, forResponse: true) else { guard checkAndSetError(forTheme: true, forDescription: true, forEndRegisterDate: true, forEndBetDate: true) else {
return return
} }
resetAllFieldErrors() resetAllFieldErrors()
if let user = AppStateContainer.shared.user { if let user = AppStateContainer.shared.user {
manager.addBet(bet: toBet(theme: theme, description: description, endRegister: endRegisterDate, endBet: endBetDate, isPrivate: isPrivate, status: .inProgress, creator: user.username, invited: Array(invited), type: selectedTypeBet)) { statusCode in manager.addBet(bet: toBet(theme: theme, description: description, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, status: .inProgress, creator: user.username, type: selectedOption)) { statusCode in
print(statusCode)
switch statusCode { switch statusCode {
case 201: case 201:
self.betAdded = true self.betAdded = true
@ -89,13 +52,12 @@ class CreationBetViewModel: ObservableObject {
} }
} }
func checkAndSetError(forTheme checkTheme: Bool, forDescription checkDescription: Bool, forEndRegisterDate checkEndRegisterDate: Bool, forEndBetDate checkEndBetDate: Bool, forResponse checkResponse: Bool) -> Bool { func checkAndSetError(forTheme checkTheme: Bool, forDescription checkDescription: Bool, forEndRegisterDate checkEndRegisterDate: Bool, forEndBetDate checkEndBetDate: Bool) -> Bool {
var newThemeFieldError: String? var newThemeFieldError: String?
var newDescriptionFieldError: String? var newDescriptionFieldError: String?
var newEndRegisterDateFieldError: String? var newEndRegisterDateFieldError: String?
var newEndBetDateFieldError: String? var newEndBetDateFieldError: String?
var newResponsesFieldError: String?
var hasError = false var hasError = false
@ -123,19 +85,6 @@ class CreationBetViewModel: ObservableObject {
hasError = true hasError = true
} }
if checkResponse, selectedTypeBet == 2 {
if values.count < 2 {
newResponsesFieldError = "Il doit y'avoir 2 réponses minimum"
hasError = true
} else {
let uniqueValues = Set(values)
if uniqueValues.count != values.count {
newResponsesFieldError = "Les réponses doivent être uniques"
hasError = true
}
}
}
if !hasError { if !hasError {
// No error // No error
return true return true
@ -146,7 +95,6 @@ class CreationBetViewModel: ObservableObject {
descriptionFieldError = newDescriptionFieldError descriptionFieldError = newDescriptionFieldError
endRegisterDateFieldError = newEndRegisterDateFieldError endRegisterDateFieldError = newEndRegisterDateFieldError
endBetDateFieldError = newEndBetDateFieldError endBetDateFieldError = newEndBetDateFieldError
responsesFieldError = newResponsesFieldError
} }
return false return false
} }
@ -157,7 +105,6 @@ class CreationBetViewModel: ObservableObject {
descriptionFieldError = nil descriptionFieldError = nil
endRegisterDateFieldError = nil endRegisterDateFieldError = nil
endBetDateFieldError = nil endBetDateFieldError = nil
responsesFieldError = nil
} }
} }
@ -166,20 +113,16 @@ class CreationBetViewModel: ObservableObject {
self.errorMessage = errorMessage self.errorMessage = errorMessage
} }
func toBet(theme: String, description: String, endRegister: Date, endBet: Date, isPrivate: Bool, status: BetStatus, creator: String, invited: [String], type: Int) -> Bet { func toBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: String, type: Int) -> Bet {
switch type { switch type {
case 0: case 0:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator) return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
case 1: case 1:
return MatchBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator, nameTeam1: "", nameTeam2: "") return MatchBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "")
case 2: case 2:
var bet = CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator) return CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
for answer in values {
bet.addCustomResponse(answer)
}
return bet
default: default:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator) return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
} }
} }
} }

@ -21,9 +21,7 @@ class CurrentBetViewModel: ObservableObject {
func getItems() { func getItems() {
manager.getCurrentBets(withIndex: 0, withCount: 20) { bets in manager.getCurrentBets(withIndex: 0, withCount: 20) { bets in
DispatchQueue.main.async { self.bets = bets
self.bets = bets
}
} }
} }

@ -15,9 +15,9 @@ class DetailsViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
var id: String var id: String
@Published var selectedAnswer = AnswerDetail(response: "", totalStakes: 0, totalParticipants: 0, highestStake: 0, odds: 0) @Published var answer = 0
@Published var mise: String = "" @Published var mise: String = ""
@Published var betDetail: BetDetail? @Published var betDetail: BetDetail?
init(id: String) { init(id: String) {
@ -26,31 +26,25 @@ class DetailsViewModel: ObservableObject {
} }
func getItem(withId id: String) { func getItem(withId id: String) {
let semaphore = DispatchSemaphore(value: 0)
manager.getBet(withId: id) { bet in manager.getBet(withId: id) { bet in
self.betDetail = bet self.betDetail = bet
if let firstAnswer = bet.answers.first {
self.selectedAnswer = firstAnswer
}
semaphore.signal()
}
let result = semaphore.wait(timeout: DispatchTime.now() + .seconds(2))
if result == .timedOut {
print("The request has exceeded the deadline")
return
} }
} }
func addParticipate() { func addParticipate() {
if let stake = Int(mise) { if let stake = Int(mise) {
manager.addParticipation(withId: id, withAnswer: selectedAnswer.response, andStake: stake) { statusCode in var rep: String = ""
if answer == 0 {
rep = "Yes"
} else {
rep = "No"
}
manager.addParticipation(withId: id, withAnswer: rep, andStake: stake) { statusCode in
switch statusCode { switch statusCode {
case 201: case 201:
AppStateContainer.shared.user?.nbCoins -= stake AppStateContainer.shared.user?.nbCoins -= stake
WidgetCenter.shared.reloadAllTimelines() WidgetCenter.shared.reloadAllTimelines()
self.getItem(withId: self.id) self.getItem(withId: self.id)
default: default:
break break
@ -58,20 +52,10 @@ class DetailsViewModel: ObservableObject {
} }
} }
mise = "" mise = ""
if let firstAnswer = betDetail!.answers.first { answer = 0
self.selectedAnswer = firstAnswer
}
} }
func checkAndSetError() -> Bool { func checkAndSetError() {
if let stake = Int(mise) {
if stake <= AppStateContainer.shared.user?.nbCoins ?? 0 && stake > 0 {
return false
} else {
return true
}
} else {
return true
}
} }
} }

@ -6,6 +6,7 @@
// //
import Foundation import Foundation
import SwiftUI
import DependencyInjection import DependencyInjection
import Model import Model
@ -13,7 +14,7 @@ class HistoricBetViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Published private(set) var bets: [BetResultDetail] = [] @Published private(set) var bets: [BetDetail] = []
init() { init() {
getItems() getItems()

@ -23,9 +23,7 @@ class RankingViewModel: ObservableObject {
manager.getFriends() { users in manager.getFriends() { users in
var friends = users var friends = users
friends.append(AppStateContainer.shared.user!) friends.append(AppStateContainer.shared.user!)
DispatchQueue.main.async { self.friends = friends.sorted(by: { $0.nbCoins > $1.nbCoins })
self.friends = friends.sorted(by: { $0.nbCoins > $1.nbCoins })
}
} }
} }
} }

@ -102,7 +102,6 @@ class RegisterViewModel: ObservableObject {
registerPasswordFieldError = newRegisterPasswordFieldError registerPasswordFieldError = newRegisterPasswordFieldError
registerConfirmPasswordFieldError = newRegisterConfirmPasswordFieldError registerConfirmPasswordFieldError = newRegisterConfirmPasswordFieldError
} }
return false return false
} }

@ -15,10 +15,10 @@ struct BetEndingValidationView: View {
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@StateObject private var viewModel: BetEndingValidationViewModel @StateObject private var viewModel: BetEndingValidationViewModel
var betDetail: BetDetail var bet: BetDetail
init(bet: BetDetail) { init(bet: BetDetail) {
self.betDetail = bet self.bet = bet
self._viewModel = StateObject(wrappedValue: BetEndingValidationViewModel(id: bet.bet.id)) self._viewModel = StateObject(wrappedValue: BetEndingValidationViewModel(id: bet.bet.id))
} }
@ -48,7 +48,7 @@ struct BetEndingValidationView: View {
dismiss() dismiss()
} }
} }
ReviewCard(bet: betDetail.bet, amount: 0, isWin: false) ReviewCard(betDetail: bet, amountBetted: 0, isAWin: false)
.padding(.top, 20) .padding(.top, 20)
.padding(.bottom, 10) .padding(.bottom, 10)
Text("bet_confirmation_text") Text("bet_confirmation_text")
@ -64,7 +64,7 @@ struct BetEndingValidationView: View {
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
VStack(spacing: 14){ VStack(spacing: 14){
ForEach(betDetail.answers) { answer in ForEach(bet.answers) { answer in
ChoiceFinalAnswerCell(selected : answer.response == viewModel.selectedAnswer, answer: answer).onTapGesture { ChoiceFinalAnswerCell(selected : answer.response == viewModel.selectedAnswer, answer: answer).onTapGesture {
if(viewModel.selectedAnswer == answer.response){ if(viewModel.selectedAnswer == answer.response){
viewModel.selectedAnswer = nil viewModel.selectedAnswer = nil

@ -59,22 +59,14 @@ struct BetView: View {
.refreshable { .refreshable {
viewModel.getItems() viewModel.getItems()
} }
.sheet(isPresented: $viewModel.showingSheetOver, onDismiss: { .sheet(isPresented: $viewModel.showingSheet, onDismiss: {
viewModel.betsOver.removeFirst() viewModel.betsOver.removeFirst()
viewModel.showingSheetOver = !viewModel.betsOver.isEmpty viewModel.showingSheet = !viewModel.betsOver.isEmpty
}) { }) {
if let firstBetDetail = viewModel.betsOver.first { if let firstBetDetail = viewModel.betsOver.first {
BetEndingValidationView(bet: firstBetDetail) BetEndingValidationView(bet: firstBetDetail)
} }
} }
.sheet(isPresented: $viewModel.showingSheetWon, onDismiss: {
viewModel.betsWon.removeFirst()
viewModel.showingSheetWon = !viewModel.betsWon.isEmpty
}) {
if let firstBetResultDetail = viewModel.betsWon.first {
WinModal(betResult: firstBetResultDetail)
}
}
Spacer() Spacer()
} }
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)

@ -28,6 +28,17 @@ struct CreationBetView: View {
}() }()
let screenWidth = UIScreen.main.bounds.width let screenWidth = UIScreen.main.bounds.width
@State private var response = ""
@State private var values: [String] = []
let options: [(Int, String, String)] = [
(0, "questionMarkIcon", String(localized: "bet_type_binary")),
(1, "footballIcon", String(localized: "bet_type_match")),
(2, "paintbrushIcon", String(localized: "bet_type_custom"))
]
@State var groupedItems: [[String]] = [[String]] ()
private func updateGroupedItems() { private func updateGroupedItems() {
var updatedGroupedItems: [[String]] = [[String]] () var updatedGroupedItems: [[String]] = [[String]] ()
@ -35,7 +46,7 @@ struct CreationBetView: View {
var width: CGFloat = 0 var width: CGFloat = 0
var dynamicWidthLimit: CGFloat var dynamicWidthLimit: CGFloat
for value in viewModel.values { for value in values {
let label = UILabel() let label = UILabel()
label.text = value label.text = value
label.sizeToFit() label.sizeToFit()
@ -54,7 +65,7 @@ struct CreationBetView: View {
} }
updatedGroupedItems.append(tempItems) updatedGroupedItems.append(tempItems)
viewModel.groupedItems = updatedGroupedItems groupedItems = updatedGroupedItems
} }
var body: some View { var body: some View {
@ -97,7 +108,6 @@ struct CreationBetView: View {
.foregroundColor(AllInColors.lightGrey300Color) .foregroundColor(AllInColors.lightGrey300Color)
.font(.system(size: 14)) .font(.system(size: 14))
.fontWeight(.light)) .fontWeight(.light))
.autocorrectionDisabled(true)
.padding() .padding()
.background( .background(
RoundedRectangle(cornerRadius: 9) RoundedRectangle(cornerRadius: 9)
@ -141,7 +151,6 @@ struct CreationBetView: View {
.foregroundColor(AllInColors.lightGrey300Color) .foregroundColor(AllInColors.lightGrey300Color)
.font(.system(size: 14)) .font(.system(size: 14))
.fontWeight(.light), axis: .vertical) .fontWeight(.light), axis: .vertical)
.autocorrectionDisabled(true)
.lineLimit(4, reservesSpace: true) .lineLimit(4, reservesSpace: true)
.padding() .padding()
.background( .background(
@ -182,7 +191,7 @@ struct CreationBetView: View {
DatePicker( DatePicker(
"", "",
selection: $viewModel.endRegisterDate, selection: $viewModel.endRegisterDate,
in: Date()..., in: dateRange,
displayedComponents: [.date, .hourAndMinute] displayedComponents: [.date, .hourAndMinute]
) )
.accentColor(AllInColors.lightPurpleColor) .accentColor(AllInColors.lightPurpleColor)
@ -220,7 +229,7 @@ struct CreationBetView: View {
DatePicker( DatePicker(
"", "",
selection: $viewModel.endBetDate, selection: $viewModel.endBetDate,
in: viewModel.endRegisterDate..., in: dateRange,
displayedComponents: [.date, .hourAndMinute] displayedComponents: [.date, .hourAndMinute]
) )
.accentColor(AllInColors.lightPurpleColor) .accentColor(AllInColors.lightPurpleColor)
@ -248,15 +257,15 @@ struct CreationBetView: View {
.padding(.leading, 10) .padding(.leading, 10)
HStack(spacing: 5) { HStack(spacing: 5) {
ConfidentialityButton(image: "globe", text: String(localized: "bet_public"), selected: !viewModel.isPrivate) ConfidentialityButton(image: "globe", text: String(localized: "bet_public"), selected: viewModel.isPublic)
.onTapGesture { .onTapGesture {
viewModel.isPrivate = false viewModel.isPublic = true
} }
.padding(.trailing, 5) .padding(.trailing, 5)
ConfidentialityButton(image: "lock", text: String(localized: "bet_private"), selected: viewModel.isPrivate) ConfidentialityButton(image: "lock", text: String(localized: "bet_private"), selected: !viewModel.isPublic)
.onTapGesture { .onTapGesture {
viewModel.isPrivate = true viewModel.isPublic = false
} }
Spacer() Spacer()
} }
@ -267,8 +276,8 @@ struct CreationBetView: View {
VStack(spacing: 10) { VStack(spacing: 10) {
if self.viewModel.isPrivate { if !self.viewModel.isPublic {
DropDownFriends(selectedItems: $viewModel.invited, friends: viewModel.friends) DropDownFriends()
.padding(.bottom, 30) .padding(.bottom, 30)
HStack() { HStack() {
@ -351,14 +360,14 @@ struct CreationBetView: View {
VStack(spacing: 5) { VStack(spacing: 5) {
VStack() { VStack() {
DropDownMenu(selectedOption: $viewModel.selectedTypeBet, options: viewModel.options) DropDownMenu(selectedOption: $viewModel.selectedOption, options: options)
} }
.padding([.bottom], 15) .padding([.bottom], 15)
.frame(width: 340) .frame(width: 340)
Group { Group {
switch viewModel.selectedTypeBet { switch viewModel.selectedOption {
case 0: case 0:
Text("bet_creation_yes_no_bottom_text_1") Text("bet_creation_yes_no_bottom_text_1")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13) .textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
@ -376,18 +385,12 @@ struct CreationBetView: View {
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13) .textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.padding(.bottom, 15) .padding(.bottom, 15)
if let responseError = $viewModel.responsesFieldError.wrappedValue {
Text(responseError)
.textStyle(weight: .bold, color: .red, size: 10)
}
VStack(spacing: 5) { VStack(spacing: 5) {
HStack(spacing: 0) { HStack(spacing: 0) {
TextField("", text: $viewModel.response, prompt: Text("bet_creation_response_title") TextField("", text: $response, prompt: Text("bet_creation_response_title")
.foregroundColor(AllInColors.lightGrey200Color) .foregroundColor(AllInColors.lightGrey200Color)
.font(.system(size: 16)) .font(.system(size: 16))
.fontWeight(.medium)) .fontWeight(.medium))
.autocorrectionDisabled(true)
.padding() .padding()
.background( .background(
Rectangle() Rectangle()
@ -397,17 +400,17 @@ struct CreationBetView: View {
) )
.frame(width: 250, height: 38) .frame(width: 250, height: 38)
.foregroundColor(.black) .foregroundColor(.black)
.onChange(of: viewModel.response) { newValue in .onChange(of: response) { newValue in
if newValue.count > 20 { if newValue.count > 20 {
viewModel.response = String(newValue.prefix(20)) response = String(newValue.prefix(20))
} }
} }
Button(action: { Button(action: {
if !viewModel.response.isEmpty && viewModel.values.count < 5 { if !response.isEmpty && values.count < 5 {
viewModel.values.append(viewModel.response) values.append(response)
updateGroupedItems() updateGroupedItems()
viewModel.response = "" response = ""
} }
}) { }) {
Text("generic_add") Text("generic_add")
@ -420,12 +423,12 @@ struct CreationBetView: View {
} }
HStack { HStack {
Spacer() Spacer()
Text(String(localized: "bet_creation_max_answers \(5 - viewModel.values.count)")) Text(String(localized: "bet_creation_max_answers \(5 - values.count)"))
.textStyle(weight: .regular, color: AllInColors.primaryTextColor, size: 12) .textStyle(weight: .regular, color: AllInColors.primaryTextColor, size: 12)
} }
VStack(spacing: 10) { VStack(spacing: 10) {
ForEach(viewModel.groupedItems, id: \.self) { items in ForEach(groupedItems, id: \.self) { items in
HStack { HStack {
ForEach(items, id: \.self) { text in ForEach(items, id: \.self) { text in
HStack { HStack {
@ -433,8 +436,8 @@ struct CreationBetView: View {
.foregroundColor(.white) .foregroundColor(.white)
.lineLimit(1) .lineLimit(1)
Button(action: { Button(action: {
if let index = viewModel.values.firstIndex(of: text) { if let index = values.firstIndex(of: text) {
viewModel.values.remove(at: index) values.remove(at: index)
updateGroupedItems() updateGroupedItems()
} }
}) { }) {

@ -23,8 +23,8 @@ struct CurrentBetView: View {
.textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25) .textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25)
.padding([.top],15) .padding([.top],15)
VStack(spacing: 20){ VStack(spacing: 20){
ForEach(viewModel.bets, id: \.bet.id) { (betDetail: BetDetail) in ForEach(viewModel.bets, id: \.bet.id) { (bet: BetDetail) in
ReviewCard(bet: betDetail.bet, amount: betDetail.userParticipation?.stake ?? 0, isWin: false) ReviewCard(betDetail: bet, amountBetted: 110, isAWin: false)
} }
} }
.padding([.trailing, .leading, .bottom],25) .padding([.trailing, .leading, .bottom],25)

@ -5,10 +5,11 @@ struct DetailsView: View {
@Binding var isModalPresented: Bool @Binding var isModalPresented: Bool
@Binding var isModalParticipated: Bool @Binding var isModalParticipated: Bool
@State var progressValue: Float = 0.2
@StateObject private var viewModel: DetailsViewModel @StateObject private var viewModel: DetailsViewModel
var isFinished: Bool { var isFinished: Bool {
viewModel.betDetail?.wonParticipation == nil ? false : true viewModel.betDetail?.finalAnswer == nil ? false : true
} }
var StatusValues: (String, Color) { var StatusValues: (String, Color) {
@ -57,117 +58,97 @@ struct DetailsView: View {
} }
.padding(.horizontal, 15) .padding(.horizontal, 15)
.background(StatusValues.1) .background(StatusValues.1)
if viewModel.betDetail != nil{
ScrollView { VStack(spacing: 0) {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 5) {
HStack(spacing: 3) { HStack(spacing: 3) {
Spacer() Spacer()
Text("bet_proposed_by_format") Text("bet_proposed_by_format")
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color)
Text((viewModel.betDetail?.bet.author ?? "Unknown").capitalized)
.font(.system(size: 10))
.fontWeight(.semibold)
.foregroundColor(AllInColors.primaryTextColor)
}
Text(viewModel.betDetail?.bet.theme ?? "Not loaded")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
Text(viewModel.betDetail?.bet.phrase ?? "Not loaded") Text((viewModel.betDetail?.bet.author ?? "Unknown").capitalized)
.font(.system(size: 20)) .font(.system(size: 10))
.fontWeight(.bold) .fontWeight(.semibold)
.padding(.bottom, 10) .foregroundColor(AllInColors.primaryTextColor)
HStack {
HStack { }
Spacer() Text(viewModel.betDetail?.bet.theme ?? "Not loaded")
Text("bet_starting") .font(.system(size: 15))
.font(.system(size: 15)) .foregroundColor(AllInColors.grey800Color)
.foregroundColor(AllInColors.grey800Color) Text(viewModel.betDetail?.bet.phrase ?? "Not loaded")
} .font(.system(size: 20))
.frame(width: 105) .fontWeight(.bold)
.padding(.trailing, 10) .padding(.bottom, 10)
TextCapsule(date: viewModel.betDetail?.bet.endRegisterDate ?? Date()) HStack {
Spacer()
}.padding(.bottom, 10)
HStack { HStack {
HStack {
Spacer()
Text("bet_ends")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
}
.frame(width: 105)
.padding(.trailing, 10)
TextCapsule(date: viewModel.betDetail?.bet.endBetDate ?? Date())
Spacer() Spacer()
Text("bet_starting")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
} }
} .frame(width: 105)
.padding(.all, 15) .padding(.trailing, 10)
.padding(.top, 6) TextCapsule(date: viewModel.betDetail?.bet.endRegisterDate ?? Date())
.border(width: 1, edges: [.bottom], color: AllInColors.delimiterGrey) Spacer()
.background(AllInColors.componentBackgroundColor)
.cornerRadius(20, corners: [.topLeft,.topRight])
if isFinished {
ResultBanner(finalAnswer: (viewModel.betDetail?.wonParticipation)!, odds: (viewModel.betDetail?.odds)!)
}
VStack(alignment: .leading, spacing: 0) {
if let bet = viewModel.betDetail{
BetLineLoading(bet: bet).padding(.vertical, 20)
}
Text("bet_status_participants_list")
.font(.system(size: 18))
.foregroundStyle(AllInColors.grey100Color)
.fontWeight(.bold)
.padding(.bottom, 10)
ForEach(viewModel.betDetail?.participations ?? []) { participation in }.padding(.bottom, 10)
UserInfo(username: participation.username, picture: nil , value: participation.stake).padding(.horizontal, 10) HStack {
HStack {
Spacer()
Text("bet_ends")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
} }
.padding(.bottom) .frame(width: 105)
.padding(.trailing, 10)
TextCapsule(date: viewModel.betDetail?.bet.endBetDate ?? Date())
Spacer() Spacer()
} }
.padding([.trailing,.leading], 15)
.padding(.bottom, 100)
} }
.frame(maxWidth: .infinity, maxHeight: (geometry.size.height + geometry.safeAreaInsets.bottom) - 50) .padding(.all, 15)
.background(AllInColors.underComponentBackgroundColor) .padding(.vertical, 10)
.cornerRadius(15, corners: [.topLeft, .topRight]) .background(AllInColors.componentBackgroundColor)
} .cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0)
else{
ScrollView { if isFinished {
HStack(alignment: .center){ ResultBanner()
Spacer() }
Image(systemName: "exclamationmark.triangle.fill").font(.system(size: 45)) VStack(alignment: .leading, spacing: 5) {
VStack(alignment:.leading){ BetLineLoading(participations: viewModel.betDetail?.participations ?? [])
Text("error_title").font(.system(size: 10)) .padding(.vertical,15)
Text("error_message").font(.system(size: 10)) Text("bet_status_participants_list")
.font(.system(size: 18))
.foregroundStyle(AllInColors.grey100Color)
.fontWeight(.bold)
.padding(.bottom, 10)
ScrollView(showsIndicators: false) {
ForEach(viewModel.betDetail?.participations ?? []) { participation in
ParticipationCell(participation: participation).padding(.horizontal, 10)
} }
Spacer() }
}.opacity(0.6) .padding(.bottom, geometry.safeAreaInsets.bottom + 28)
.padding(.vertical, 20)
Spacer()
} }
.frame(maxWidth: .infinity, maxHeight: (geometry.size.height + geometry.safeAreaInsets.bottom) - 50) .padding([.bottom,.trailing,.leading], 15)
.background(AllInColors.underComponentBackgroundColor) .background(AllInColors.underComponentBackgroundColor)
.cornerRadius(15, corners: [.topLeft, .topRight]) .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
Spacer()
} }
.frame(maxWidth: .infinity, maxHeight: (geometry.size.height + geometry.safeAreaInsets.bottom) - 50)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(15, corners: [.topLeft, .topRight])
ParticipateButton(isOpen: $isModalPresented, isParticapatedOpen: $isModalParticipated, bet: viewModel.betDetail?.bet) ParticipateButton(isOpen: $isModalPresented, isParticapatedOpen: $isModalParticipated, bet: viewModel.betDetail?.bet)
.padding(.bottom, geometry.safeAreaInsets.bottom + 5) .padding(.bottom, geometry.safeAreaInsets.bottom + 5)
.padding(.horizontal, 10) .padding(.horizontal, 10)
} }
.sheet(isPresented: $isModalParticipated) { .sheet(isPresented: $isModalParticipated) {
ParticipationModal(selectedAnswer: $viewModel.selectedAnswer, mise: $viewModel.mise, phrase: viewModel.betDetail?.bet.phrase ?? "", answers: viewModel.betDetail?.answers ?? [], participationAddedCallback: { ParticipationModal(answer: $viewModel.answer, mise: $viewModel.mise, description: viewModel.betDetail?.bet.phrase ?? "Not loaded", participationAddedCallback: {
viewModel.addParticipate() viewModel.addParticipate()
isModalParticipated.toggle() isModalParticipated.toggle()
}, })
checkAndSetError: viewModel.checkAndSetError)
.presentationDetents([.fraction(0.55)]) .presentationDetents([.fraction(0.55)])
} }
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)

@ -50,6 +50,7 @@ struct FriendsView: View {
EmptyInfo(emoji:"👥", title: String(localized: "empty_friends_title"), explain: String(localized: "empty_friends_explain")).padding(.top, 40) EmptyInfo(emoji:"👥", title: String(localized: "empty_friends_title"), explain: String(localized: "empty_friends_explain")).padding(.top, 40)
} }
else{ else{
ForEach(viewModel.users, id: \.self) { friend in ForEach(viewModel.users, id: \.self) { friend in
Friend(user: friend, isRequest: false, viewModel: viewModel) Friend(user: friend, isRequest: false, viewModel: viewModel)
} }
@ -64,26 +65,22 @@ struct FriendsView: View {
} }
.padding(.top, 50) .padding(.top, 50)
.tag(0) .tag(0)
ScrollView{ VStack(alignment: .center, spacing: 0) {
VStack(alignment: .center, spacing: 0) { if(viewModel.requests.isEmpty){
if(viewModel.requests.isEmpty){ EmptyInfo(emoji:"📬", title: "Aucune demande d'amis en attente", explain: "").padding(.top, 40)
EmptyInfo(emoji:"📬", title: "Aucune demande d'amis en attente", explain: "").padding(.top, 40) }
} else{
else{ ScrollView(showsIndicators: false){
ScrollView(showsIndicators: false){ ForEach(viewModel.requests, id: \.self) { request in
ForEach(viewModel.requests, id: \.self) { request in Friend(user: request, isRequest: true, viewModel: viewModel)
Friend(user: request, isRequest: true, viewModel: viewModel)
}
}
.refreshable {
viewModel.getRequests()
} }
.padding(.top, 25)
} }
Spacer() .refreshable {
viewModel.getRequests()
}
.padding(.top, 25)
} }
}.refreshable { Spacer()
viewModel.getRequests()
} }
.padding(.top, 50) .padding(.top, 50)
.tag(1) .tag(1)

@ -24,8 +24,8 @@ struct HistoricBetView: View {
.textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25) .textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25)
.padding([.top],15) .padding([.top],15)
VStack(spacing: 20){ VStack(spacing: 20){
ForEach(viewModel.bets, id: \.bet.id) { (betDetail: BetResultDetail) in ForEach(viewModel.bets, id: \.bet.id) { (bet: BetDetail) in
ReviewCard(bet: betDetail.bet, amount: betDetail.participation.stake, isWin: betDetail.won) ReviewCard(betDetail: bet, amountBetted: 110, isAWin: false)
} }
} }
.padding([.trailing, .leading, .bottom],25) .padding([.trailing, .leading, .bottom],25)

@ -60,8 +60,8 @@ struct MainView: View {
if self.showMenu { if self.showMenu {
Menu() Menu()
.transition(.move(edge: .leading))
.frame(width: geometry.size.width*0.83) .frame(width: geometry.size.width*0.83)
.transition(.move(edge: .leading))
} }
} }

@ -51,7 +51,12 @@ struct RankingView: View {
.cornerRadius(41.5, corners: .topLeft) .cornerRadius(41.5, corners: .topLeft)
.cornerRadius(8, corners: .topRight) .cornerRadius(8, corners: .topRight)
.cornerRadius(15, corners: [.bottomLeft, .bottomRight]) .cornerRadius(15, corners: [.bottomLeft, .bottomRight])
UserPicture(picture: viewModel.friends[0].image, username: viewModel.friends[0].username, size: 70)
Image("defaultUserImage")
.resizable()
.frame(width: 70, height: 70)
.scaledToFit()
.cornerRadius(180)
.offset(x: 0, y: -55) .offset(x: 0, y: -55)
Text("1") Text("1")
@ -95,7 +100,11 @@ struct RankingView: View {
.cornerRadius(8, corners: .topLeft) .cornerRadius(8, corners: .topLeft)
.cornerRadius(15, corners: [.bottomLeft, .bottomRight]) .cornerRadius(15, corners: [.bottomLeft, .bottomRight])
UserPicture(picture: viewModel.friends[1].image, username: viewModel.friends[1].username, size: 50) Image("defaultUserImage")
.resizable()
.frame(width: 50, height: 50)
.scaledToFit()
.cornerRadius(180)
.offset(x: 0, y: -50) .offset(x: 0, y: -50)
Text("2") Text("2")
@ -122,14 +131,13 @@ struct RankingView: View {
let friend = viewModel.friends[index] let friend = viewModel.friends[index]
RankingRow( RankingRow(
number: index + 1, number: index + 1,
image: friend.image, image: "defaultUserImage",
pseudo: friend.username, pseudo: friend.username,
allCoins: friend.nbCoins allCoins: friend.nbCoins
) )
} }
} }
.padding(.top, 10) .padding(.top, 10)
.padding(.horizontal, 20)
} }
Spacer() Spacer()
} }

@ -9,20 +9,17 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */; }; 120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */; };
1209191A2B56DC6C00D0FA29 /* DropDownAnswerMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */; }; 1209191A2B56DC6C00D0FA29 /* DropDownAnswerMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */; };
12228A212C1760D2008524F4 /* BinaryBetLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12228A202C1760D2008524F4 /* BinaryBetLine.swift */; };
12228A232C176117008524F4 /* CustomBetLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12228A222C176117008524F4 /* CustomBetLine.swift */; };
123225D92B67B46100D30BB3 /* BetEndingValidationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */; }; 123225D92B67B46100D30BB3 /* BetEndingValidationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */; };
123225DB2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */; }; 123225DB2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */; };
123590B42B51792000F7AEBD /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B32B51792000F7AEBD /* DetailsView.swift */; }; 123590B42B51792000F7AEBD /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B32B51792000F7AEBD /* DetailsView.swift */; };
123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B52B5537E200F7AEBD /* ResultBanner.swift */; }; 123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B52B5537E200F7AEBD /* ResultBanner.swift */; };
123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */; }; 123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */; };
123F31DB2C0F26E8009B6D65 /* userPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123F31DA2C0F26E8009B6D65 /* userPicture.swift */; };
123F31E02C11E99E009B6D65 /* asyncCachedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */; };
1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */; }; 1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */; };
1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF612B4EC67000374ABF /* ReviewCard.swift */; }; 1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF612B4EC67000374ABF /* ReviewCard.swift */; };
129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */; }; 129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */; };
12A9E4942C07132600AB8677 /* EmptyInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A9E4932C07132600AB8677 /* EmptyInfo.swift */; }; 12A9E4942C07132600AB8677 /* EmptyInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A9E4932C07132600AB8677 /* EmptyInfo.swift */; };
12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */; }; 12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */; };
12C3704A2B5D5BD000CD9F0F /* ParticipationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370492B5D5BD000CD9F0F /* ParticipationCell.swift */; };
EC0193782B25BF16005D81E6 /* AllcoinsCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */; }; EC0193782B25BF16005D81E6 /* AllcoinsCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */; };
EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; }; EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; };
EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */; }; EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */; };
@ -36,7 +33,6 @@
EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770A2B24D9160060E34D /* WelcomeView.swift */; }; EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770A2B24D9160060E34D /* WelcomeView.swift */; };
EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770C2B24DB7A0060E34D /* Extensions.swift */; }; EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770C2B24DB7A0060E34D /* Extensions.swift */; };
EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770E2B24FCB00060E34D /* RegisterView.swift */; }; EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770E2B24FCB00060E34D /* RegisterView.swift */; };
EC34FDCE2C0DB46C0020A371 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC34FDCD2C0DB46C0020A371 /* Config.swift */; };
EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; }; EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; };
EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC60C5672B5A83FB00FFD6EF /* StubLib */; }; EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC60C5672B5A83FB00FFD6EF /* StubLib */; };
EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; }; EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; };
@ -60,6 +56,7 @@
EC6B96B72B24B4CC00FC1C58 /* AllInUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96B62B24B4CC00FC1C58 /* AllInUITests.swift */; }; EC6B96B72B24B4CC00FC1C58 /* AllInUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96B62B24B4CC00FC1C58 /* AllInUITests.swift */; };
EC6B96B92B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96B82B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift */; }; EC6B96B92B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96B82B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift */; };
EC6B96CC2B24B7E500FC1C58 /* IAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96CB2B24B7E500FC1C58 /* IAuthService.swift */; }; EC6B96CC2B24B7E500FC1C58 /* IAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96CB2B24B7E500FC1C58 /* IAuthService.swift */; };
EC6B96CF2B24B8D900FC1C58 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96CE2B24B8D900FC1C58 /* Config.swift */; };
EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D02B24BAE800FC1C58 /* AuthService.swift */; }; EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D02B24BAE800FC1C58 /* AuthService.swift */; };
EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D42B24BE0E00FC1C58 /* MainView.swift */; }; EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D42B24BE0E00FC1C58 /* MainView.swift */; };
EC6B96D82B24BF2100FC1C58 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D72B24BF2100FC1C58 /* Menu.swift */; }; EC6B96D82B24BF2100FC1C58 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D72B24BF2100FC1C58 /* Menu.swift */; };
@ -151,20 +148,17 @@
120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownAnswerMenu.swift; sourceTree = "<group>"; }; 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownAnswerMenu.swift; sourceTree = "<group>"; };
122278B72B4BDE1100E632AA /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 122278B72B4BDE1100E632AA /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; };
122278B92B4BDE9500E632AA /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Package.swift; path = ../Model/Package.swift; sourceTree = "<group>"; }; 122278B92B4BDE9500E632AA /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Package.swift; path = ../Model/Package.swift; sourceTree = "<group>"; };
12228A202C1760D2008524F4 /* BinaryBetLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryBetLine.swift; sourceTree = "<group>"; };
12228A222C176117008524F4 /* CustomBetLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomBetLine.swift; sourceTree = "<group>"; };
123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetEndingValidationView.swift; sourceTree = "<group>"; }; 123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetEndingValidationView.swift; sourceTree = "<group>"; };
123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceFinalAnswerCell.swift; sourceTree = "<group>"; }; 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceFinalAnswerCell.swift; sourceTree = "<group>"; };
123590B32B51792000F7AEBD /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; }; 123590B32B51792000F7AEBD /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; };
123590B52B5537E200F7AEBD /* ResultBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultBanner.swift; sourceTree = "<group>"; }; 123590B52B5537E200F7AEBD /* ResultBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultBanner.swift; sourceTree = "<group>"; };
123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.swift; sourceTree = "<group>"; }; 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.swift; sourceTree = "<group>"; };
123F31DA2C0F26E8009B6D65 /* userPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = userPicture.swift; sourceTree = "<group>"; };
123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = asyncCachedImage.swift; sourceTree = "<group>"; };
1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetView.swift; sourceTree = "<group>"; }; 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetView.swift; sourceTree = "<group>"; };
1244EF612B4EC67000374ABF /* ReviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewCard.swift; sourceTree = "<group>"; }; 1244EF612B4EC67000374ABF /* ReviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewCard.swift; sourceTree = "<group>"; };
129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OddCapsule.swift; sourceTree = "<group>"; }; 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OddCapsule.swift; sourceTree = "<group>"; };
12A9E4932C07132600AB8677 /* EmptyInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyInfo.swift; sourceTree = "<group>"; }; 12A9E4932C07132600AB8677 /* EmptyInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyInfo.swift; sourceTree = "<group>"; };
12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetLineLoading.swift; sourceTree = "<group>"; }; 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetLineLoading.swift; sourceTree = "<group>"; };
12C370492B5D5BD000CD9F0F /* ParticipationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipationCell.swift; sourceTree = "<group>"; };
EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCapsule.swift; sourceTree = "<group>"; }; EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCapsule.swift; sourceTree = "<group>"; };
EC0193792B25C12B005D81E6 /* BetCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetCard.swift; sourceTree = "<group>"; }; EC0193792B25C12B005D81E6 /* BetCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetCard.swift; sourceTree = "<group>"; };
EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCounter.swift; sourceTree = "<group>"; }; EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCounter.swift; sourceTree = "<group>"; };
@ -178,7 +172,6 @@
EC30770A2B24D9160060E34D /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; }; EC30770A2B24D9160060E34D /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
EC30770C2B24DB7A0060E34D /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; }; EC30770C2B24DB7A0060E34D /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
EC30770E2B24FCB00060E34D /* RegisterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterView.swift; sourceTree = "<group>"; }; EC30770E2B24FCB00060E34D /* RegisterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterView.swift; sourceTree = "<group>"; };
EC34FDCD2C0DB46C0020A371 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = "<group>"; };
EC650A412B25C817003AFCAD /* Friend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Friend.swift; sourceTree = "<group>"; }; EC650A412B25C817003AFCAD /* Friend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Friend.swift; sourceTree = "<group>"; };
EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterMenu.swift; sourceTree = "<group>"; }; EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterMenu.swift; sourceTree = "<group>"; };
EC650A452B25D686003AFCAD /* RankingRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankingRow.swift; sourceTree = "<group>"; }; EC650A452B25D686003AFCAD /* RankingRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankingRow.swift; sourceTree = "<group>"; };
@ -203,6 +196,7 @@
EC6B96B62B24B4CC00FC1C58 /* AllInUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInUITests.swift; sourceTree = "<group>"; }; EC6B96B62B24B4CC00FC1C58 /* AllInUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInUITests.swift; sourceTree = "<group>"; };
EC6B96B82B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInUITestsLaunchTests.swift; sourceTree = "<group>"; }; EC6B96B82B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInUITestsLaunchTests.swift; sourceTree = "<group>"; };
EC6B96CB2B24B7E500FC1C58 /* IAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAuthService.swift; sourceTree = "<group>"; }; EC6B96CB2B24B7E500FC1C58 /* IAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAuthService.swift; sourceTree = "<group>"; };
EC6B96CE2B24B8D900FC1C58 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = "<group>"; };
EC6B96D02B24BAE800FC1C58 /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = "<group>"; }; EC6B96D02B24BAE800FC1C58 /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = "<group>"; };
EC6B96D42B24BE0E00FC1C58 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; }; EC6B96D42B24BE0E00FC1C58 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
EC6B96D72B24BF2100FC1C58 /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = "<group>"; }; EC6B96D72B24BF2100FC1C58 /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = "<group>"; };
@ -280,14 +274,6 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
123F31DE2C11E979009B6D65 /* Utils */ = {
isa = PBXGroup;
children = (
123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */,
);
path = Utils;
sourceTree = "<group>";
};
EC1D15402B715A7A0094833E /* Protocols */ = { EC1D15402B715A7A0094833E /* Protocols */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -323,7 +309,6 @@
EC6B969A2B24B4CC00FC1C58 /* AllIn */ = { EC6B969A2B24B4CC00FC1C58 /* AllIn */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
123F31DE2C11E979009B6D65 /* Utils */,
ECF872852B93B9D900F9D240 /* AllIn.entitlements */, ECF872852B93B9D900F9D240 /* AllIn.entitlements */,
EC7EF7462B87E3470022B5D9 /* QuickActions */, EC7EF7462B87E3470022B5D9 /* QuickActions */,
ECB7BC662B2F1AAD002A6654 /* ViewModels */, ECB7BC662B2F1AAD002A6654 /* ViewModels */,
@ -380,9 +365,9 @@
EC6B96CD2B24B8A300FC1C58 /* Ressources */ = { EC6B96CD2B24B8A300FC1C58 /* Ressources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
EC6B96CE2B24B8D900FC1C58 /* Config.swift */,
EC3077082B24CF7F0060E34D /* Colors.swift */, EC3077082B24CF7F0060E34D /* Colors.swift */,
ECDDD48C2BF4A7920009223A /* Localizable.strings */, ECDDD48C2BF4A7920009223A /* Localizable.strings */,
EC34FDCD2C0DB46C0020A371 /* Config.swift */,
); );
path = Ressources; path = Ressources;
sourceTree = "<group>"; sourceTree = "<group>";
@ -444,12 +429,10 @@
120919172B56D0AE00D0FA29 /* ParticipationModal.swift */, 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */,
120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */, 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */,
12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */, 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */,
12C370492B5D5BD000CD9F0F /* ParticipationCell.swift */,
123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */, 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */,
129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */, 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */,
12A9E4932C07132600AB8677 /* EmptyInfo.swift */, 12A9E4932C07132600AB8677 /* EmptyInfo.swift */,
123F31DA2C0F26E8009B6D65 /* userPicture.swift */,
12228A202C1760D2008524F4 /* BinaryBetLine.swift */,
12228A222C176117008524F4 /* CustomBetLine.swift */,
); );
path = Components; path = Components;
sourceTree = "<group>"; sourceTree = "<group>";
@ -681,20 +664,17 @@
files = ( files = (
EC6B96CC2B24B7E500FC1C58 /* IAuthService.swift in Sources */, EC6B96CC2B24B7E500FC1C58 /* IAuthService.swift in Sources */,
ECB26A172B4073F100FE06B3 /* CreationBetViewModel.swift in Sources */, ECB26A172B4073F100FE06B3 /* CreationBetViewModel.swift in Sources */,
12228A232C176117008524F4 /* CustomBetLine.swift in Sources */,
EC3077092B24CF7F0060E34D /* Colors.swift in Sources */, EC3077092B24CF7F0060E34D /* Colors.swift in Sources */,
EC6B969E2B24B4CC00FC1C58 /* ContentView.swift in Sources */, EC6B969E2B24B4CC00FC1C58 /* ContentView.swift in Sources */,
EC89F7BD2B250D66003821CE /* LoginView.swift in Sources */, EC89F7BD2B250D66003821CE /* LoginView.swift in Sources */,
EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */, EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */,
120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */, 120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */,
123F31DB2C0F26E8009B6D65 /* userPicture.swift in Sources */,
ECB26A132B406A9400FE06B3 /* BetViewModel.swift in Sources */, ECB26A132B406A9400FE06B3 /* BetViewModel.swift in Sources */,
EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */, EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */,
EC650A522B2794DD003AFCAD /* BetView.swift in Sources */, EC650A522B2794DD003AFCAD /* BetView.swift in Sources */,
EC6B969C2B24B4CC00FC1C58 /* AllInApp.swift in Sources */, EC6B969C2B24B4CC00FC1C58 /* AllInApp.swift in Sources */,
123590B42B51792000F7AEBD /* DetailsView.swift in Sources */, 123590B42B51792000F7AEBD /* DetailsView.swift in Sources */,
ECB26A192B40744F00FE06B3 /* RankingViewModel.swift in Sources */, ECB26A192B40744F00FE06B3 /* RankingViewModel.swift in Sources */,
123F31E02C11E99E009B6D65 /* asyncCachedImage.swift in Sources */,
EC650A502B2793D5003AFCAD /* TextCapsule.swift in Sources */, EC650A502B2793D5003AFCAD /* TextCapsule.swift in Sources */,
EC650A482B25DCFF003AFCAD /* UsersPreview.swift in Sources */, EC650A482B25DCFF003AFCAD /* UsersPreview.swift in Sources */,
EC17A15E2B6A955E008A8679 /* CurrentBetView.swift in Sources */, EC17A15E2B6A955E008A8679 /* CurrentBetView.swift in Sources */,
@ -712,9 +692,9 @@
EC7A882B2B28D1E0004F226A /* DropDownMenu.swift in Sources */, EC7A882B2B28D1E0004F226A /* DropDownMenu.swift in Sources */,
EC7A882D2B28D8A1004F226A /* CreationBetView.swift in Sources */, EC7A882D2B28D8A1004F226A /* CreationBetView.swift in Sources */,
ECED90B52B6D9CEC00F50937 /* DailyGiftPage.swift in Sources */, ECED90B52B6D9CEC00F50937 /* DailyGiftPage.swift in Sources */,
EC6B96CF2B24B8D900FC1C58 /* Config.swift in Sources */,
1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */, 1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */,
EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */, EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */,
EC34FDCE2C0DB46C0020A371 /* Config.swift in Sources */,
EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */, EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */,
EC6B96D82B24BF2100FC1C58 /* Menu.swift in Sources */, EC6B96D82B24BF2100FC1C58 /* Menu.swift in Sources */,
EC650A4E2B278EDB003AFCAD /* TrendingBetCard.swift in Sources */, EC650A4E2B278EDB003AFCAD /* TrendingBetCard.swift in Sources */,
@ -727,8 +707,8 @@
EC3077072B24CB840060E34D /* SplashView.swift in Sources */, EC3077072B24CB840060E34D /* SplashView.swift in Sources */,
EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */, EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */,
ECA9D1CB2B2DA2320076E0EC /* DropDownFriends.swift in Sources */, ECA9D1CB2B2DA2320076E0EC /* DropDownFriends.swift in Sources */,
12C3704A2B5D5BD000CD9F0F /* ParticipationCell.swift in Sources */,
123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */, 123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */,
12228A212C1760D2008524F4 /* BinaryBetLine.swift in Sources */,
EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */, EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */,
ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */, ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */,
ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */, ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */,

@ -7,21 +7,5 @@
<key>NSExtensionPointIdentifier</key> <key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string> <string>com.apple.widgetkit-extension</string>
</dict> </dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>codefirst.iut.uca.fr</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
</dict> </dict>
</plist> </plist>

@ -3,6 +3,8 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array/> <array>
<string>group.alldev.AllIn</string>
</array>
</dict> </dict>
</plist> </plist>

@ -11,15 +11,13 @@ import Model
public struct BetApiManager: BetDataManager { public struct BetApiManager: BetDataManager {
public let token: String public let token: String
public let url: String
public init(withUserToken token: String, andApiUrl url: String) { public init(withUserToken token: String) {
self.token = token self.token = token
self.url = url
} }
public func getBets(withIndex index: Int, withCount count: Int, filters: [BetFilter] = [], completion: @escaping ([Bet]) -> Void) { public func getBets(withIndex index: Int, withCount count: Int, filters: [BetFilter] = [], completion: @escaping ([Bet]) -> Void) {
let url = URL(string: url + "bets/gets")! let url = URL(string: allInApi + "bets/gets")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
@ -64,7 +62,7 @@ public struct BetApiManager: BetDataManager {
} }
public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) { public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) {
let url = URL(string: url + "betdetail/get/" + id)! let url = URL(string: allInApi + "betdetail/get/" + id)!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -76,11 +74,11 @@ public struct BetApiManager: BetDataManager {
print ("ALLIN : get bet with id :" + id) print ("ALLIN : get bet with id :" + id)
do { do {
if let httpResponse = response as? HTTPURLResponse, let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { if let httpResponse = response as? HTTPURLResponse, let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
print(httpResponse.statusCode)
print(json)
if let betDetail = FactoryApiBet().toBetDetail(from: json) { if let betDetail = FactoryApiBet().toBetDetail(from: json) {
completion(betDetail) completion(betDetail)
} }
print(httpResponse.statusCode)
} }
} catch { } catch {
print("Error parsing JSON: \(error)") print("Error parsing JSON: \(error)")
@ -90,7 +88,7 @@ public struct BetApiManager: BetDataManager {
} }
public func getPopularBet(completion: @escaping (Bet) -> Void) { public func getPopularBet(completion: @escaping (Bet) -> Void) {
let url = URL(string: url + "bets/popular")! let url = URL(string: allInApi + "bets/popular")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"

@ -23,14 +23,11 @@ public class FactoryApiBet: FactoryBet {
"sentenceBet": bet.phrase, "sentenceBet": bet.phrase,
"endRegistration": formatZonedDateTime(dateTime: bet.endRegisterDate), "endRegistration": formatZonedDateTime(dateTime: bet.endRegisterDate),
"endBet": formatZonedDateTime(dateTime: bet.endBetDate), "endBet": formatZonedDateTime(dateTime: bet.endBetDate),
"isPrivate": String(bet.isPrivate), "isPrivate": String(bet.isPublic),
"response": bet.getResponses(), "response": ["Yes","No"],
"userInvited": bet.invited,
"type": betTypeString(fromType: String(describing: type(of: bet))) "type": betTypeString(fromType: String(describing: type(of: bet)))
] ]
print(json)
return json return json
} }
@ -63,8 +60,6 @@ public class FactoryApiBet: FactoryBet {
} }
var participations: [Participation] = [] var participations: [Participation] = []
var wonParticipation: Participation?
var userParticipation: Participation?
if let participationsJson = json["participations"] as? [[String: Any]] { if let participationsJson = json["participations"] as? [[String: Any]] {
do { do {
@ -84,53 +79,7 @@ public class FactoryApiBet: FactoryBet {
} }
} }
if let participationJson = json["wonParticipation"] as? [String: Any] { return BetDetail(bet: bet, answers: answers, participations: participations)
do {
wonParticipation = try JSONDecoder().decode(Participation.self, from: JSONSerialization.data(withJSONObject: participationJson))
} catch {
print("Error decoding participation: \(error)")
}
}
if let participationUserJson = json["userParticipation"] as? [String: Any] {
do {
userParticipation = try JSONDecoder().decode(Participation.self, from: JSONSerialization.data(withJSONObject: participationUserJson))
} catch {
print("Error decoding participation: \(error)")
}
}
return BetDetail(bet: bet, answers: answers, participations: participations, wonParticipation: wonParticipation, userParticipation: userParticipation)
}
public func toBetResultDetail(from json: [String: Any]) -> BetResultDetail? {
guard let amount = json["amount"] as? Int,
let won = json["won"] as? Bool else {
return nil
}
guard let betJson = json["bet"] as? [String: Any],
let bet = self.toBet(from: betJson) else {
return nil
}
let decoder = JSONDecoder()
guard let betResultJson = json["betResult"] as? [String: Any],
let betResultData = try? JSONSerialization.data(withJSONObject: betResultJson),
let betResult = try? decoder.decode(BetResult.self, from: betResultData) else {
print("Error decoding bet result")
return nil
}
guard let participationJson = json["participation"] as? [String: Any],
let participationData = try? JSONSerialization.data(withJSONObject: participationJson),
let participation = try? decoder.decode(Participation.self, from: participationData) else {
print("Error decoding participation")
return nil
}
return BetResultDetail(betResult: betResult, bet: bet, participation: participation, amount: amount, won: won)
} }
public func betTypeString(fromType type: String) -> String { public func betTypeString(fromType type: String) -> String {

@ -8,14 +8,14 @@
import Foundation import Foundation
import Model import Model
let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/"
public struct UserApiManager: UserDataManager { public struct UserApiManager: UserDataManager {
public let token: String public let token: String
public let url: String
public init(withUserToken token: String, andApiUrl url: String) { public init(withUserToken token: String) {
self.token = token self.token = token
self.url = url
} }
public func getBets(withIndex index: Int, withCount count: Int) -> [Bet] { public func getBets(withIndex index: Int, withCount count: Int) -> [Bet] {
@ -23,7 +23,7 @@ public struct UserApiManager: UserDataManager {
} }
public func getBetsOver(completion : @escaping ([BetDetail])-> ()) { public func getBetsOver(completion : @escaping ([BetDetail])-> ()) {
let url = URL(string: url + "bets/toConfirm")! let url = URL(string: allInApi + "bets/toConfirm")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -52,41 +52,9 @@ public struct UserApiManager: UserDataManager {
}.resume() }.resume()
} }
public func getBetsWon(completion : @escaping ([BetResultDetail])-> ()) {
let url = URL(string: url + "bets/getWon")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var bets: [BetResultDetail] = []
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print ("ALLIN : get bets won")
do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for json in jsonArray {
if let bet = FactoryApiBet().toBetResultDetail(from: json) {
print(bet)
bets.append(bet)
}
}
print(httpResponse.statusCode)
completion(bets)
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
}
public func addBet(bet: Bet, completion : @escaping (Int)-> ()) { public func addBet(bet: Bet, completion : @escaping (Int)-> ()) {
let url = URL(string: url + "bets/add")! let url = URL(string: allInApi + "bets/add")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
@ -107,7 +75,7 @@ public struct UserApiManager: UserDataManager {
public func addFriend(username: String, completion : @escaping (Int)-> ()) { public func addFriend(username: String, completion : @escaping (Int)-> ()) {
let url = URL(string: url + "friends/add")! let url = URL(string: allInApi + "friends/add")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
@ -128,7 +96,7 @@ public struct UserApiManager: UserDataManager {
public func removeFriend(username: String, completion : @escaping (Int)-> ()) { public func removeFriend(username: String, completion : @escaping (Int)-> ()) {
let url = URL(string: url + "friends/delete")! let url = URL(string: allInApi + "friends/delete")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
@ -148,7 +116,7 @@ public struct UserApiManager: UserDataManager {
} }
public func getFriends(completion: @escaping ([User]) -> Void) { public func getFriends(completion: @escaping ([User]) -> Void) {
let url = URL(string: url + "friends/gets")! let url = URL(string: allInApi + "friends/gets")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -162,6 +130,7 @@ public struct UserApiManager: UserDataManager {
print ("ALLIN : get friends") print ("ALLIN : get friends")
do { do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
print(jsonArray)
users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray)) users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray))
print(httpResponse.statusCode) print(httpResponse.statusCode)
completion(users) completion(users)
@ -174,7 +143,7 @@ public struct UserApiManager: UserDataManager {
} }
public func getRequests(completion: @escaping ([User]) -> Void) { public func getRequests(completion: @escaping ([User]) -> Void) {
let url = URL(string: url + "friends/requests")! let url = URL(string: allInApi + "friends/requests")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -188,6 +157,7 @@ public struct UserApiManager: UserDataManager {
print ("ALLIN : get friends") print ("ALLIN : get friends")
do { do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
print(jsonArray)
users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray)) users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray))
print(httpResponse.statusCode) print(httpResponse.statusCode)
completion(users) completion(users)
@ -200,7 +170,7 @@ public struct UserApiManager: UserDataManager {
} }
public func getUsers(withName name: String, completion: @escaping ([User]) -> Void) { public func getUsers(withName name: String, completion: @escaping ([User]) -> Void) {
let url = URL(string: url + "friends/search/" + name)! let url = URL(string: allInApi + "friends/search/" + name)!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -214,6 +184,7 @@ public struct UserApiManager: UserDataManager {
print ("ALLIN : get friends by search") print ("ALLIN : get friends by search")
do { do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
print(jsonArray)
users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray)) users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray))
print(httpResponse.statusCode) print(httpResponse.statusCode)
completion(users) completion(users)
@ -226,7 +197,7 @@ public struct UserApiManager: UserDataManager {
} }
public func getGifts(completion : @escaping (Int, Int)-> ()) { public func getGifts(completion : @escaping (Int, Int)-> ()) {
let url = URL(string: url + "users/gift")! let url = URL(string: allInApi + "users/gift")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -250,24 +221,24 @@ public struct UserApiManager: UserDataManager {
}.resume() }.resume()
} }
public func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetResultDetail]) -> Void) { public func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetDetail]) -> Void) {
let url = URL(string: url + "bets/history")! let url = URL(string: allInApi + "bets/history")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var bets: [BetResultDetail] = [] var bets: [BetDetail] = []
URLSession.shared.dataTask(with: request) { data, response, error in URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data { if let data = data {
print ("ALLIN : get old bets") print ("ALLIN : get old bets")
do { do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
print(jsonArray)
for json in jsonArray { for json in jsonArray {
if let bet = FactoryApiBet().toBetResultDetail(from: json) { print(json)
if let bet = FactoryApiBet().toBetDetail(from: json) {
bets.append(bet) bets.append(bet)
} }
} }
@ -282,7 +253,7 @@ public struct UserApiManager: UserDataManager {
} }
public func getCurrentBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetDetail]) -> Void) { public func getCurrentBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetDetail]) -> Void) {
let url = URL(string: url + "bets/current")! let url = URL(string: allInApi + "bets/current")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -297,6 +268,7 @@ public struct UserApiManager: UserDataManager {
do { do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for json in jsonArray { for json in jsonArray {
print(json)
if let bet = FactoryApiBet().toBetDetail(from: json) { if let bet = FactoryApiBet().toBetDetail(from: json) {
bets.append(bet) bets.append(bet)
} }
@ -312,7 +284,7 @@ public struct UserApiManager: UserDataManager {
} }
public func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int, completion : @escaping (Int)-> ()) { public func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int, completion : @escaping (Int)-> ()) {
let url = URL(string: url + "participations/add")! let url = URL(string: allInApi + "participations/add")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
@ -336,7 +308,7 @@ public struct UserApiManager: UserDataManager {
} }
public func addResponse(withIdBet id: String, andResponse responseBet: String) { public func addResponse(withIdBet id: String, andResponse responseBet: String) {
let url = URL(string: url + "bets/confirm/" + id)! let url = URL(string: allInApi + "bets/confirm/" + id)!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"

@ -339,11 +339,9 @@
ECEE18C82B3C9CF400C95E8A /* Debug */ = { ECEE18C82B3C9CF400C95E8A /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = P39ZK4GA2T;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
@ -378,11 +376,9 @@
ECEE18C92B3C9CF400C95E8A /* Release */ = { ECEE18C92B3C9CF400C95E8A /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = P39ZK4GA2T;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
@ -420,7 +416,6 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 35KQ5BDC64;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.4; IPHONEOS_DEPLOYMENT_TARGET = 16.4;
MACOSX_DEPLOYMENT_TARGET = 13.3; MACOSX_DEPLOYMENT_TARGET = 13.3;
@ -441,7 +436,6 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 35KQ5BDC64;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.4; IPHONEOS_DEPLOYMENT_TARGET = 16.4;
MACOSX_DEPLOYMENT_TARGET = 13.3; MACOSX_DEPLOYMENT_TARGET = 13.3;

@ -8,7 +8,7 @@
import Foundation import Foundation
/// A class representing detailed information about a specific answer option for a bet. /// A class representing detailed information about a specific answer option for a bet.
public class AnswerDetail: ObservableObject, Codable, Equatable, Identifiable, Hashable { public class AnswerDetail: ObservableObject, Identifiable, Codable {
/// The response or outcome associated with this answer. /// The response or outcome associated with this answer.
public private(set) var response: String public private(set) var response: String
@ -41,19 +41,4 @@ public class AnswerDetail: ObservableObject, Codable, Equatable, Identifiable, H
self.odds = odds self.odds = odds
} }
public static func == (lhs: AnswerDetail, rhs: AnswerDetail) -> Bool {
return lhs.response == rhs.response &&
lhs.totalStakes == rhs.totalStakes &&
lhs.totalParticipants == rhs.totalParticipants &&
lhs.highestStake == rhs.highestStake &&
lhs.odds == rhs.odds
}
public func hash(into hasher: inout Hasher) {
hasher.combine(response)
hasher.combine(totalStakes)
hasher.combine(totalParticipants)
hasher.combine(highestStake)
hasher.combine(odds)
}
} }

@ -8,7 +8,7 @@
import Foundation import Foundation
/// A class representing a betting entity, including details about the bet theme, participants, and deadlines. /// A class representing a betting entity, including details about the bet theme, participants, and deadlines.
public class Bet: ObservableObject, Codable { public class Bet: ObservableObject, Identifiable, Codable {
/// The id for the bet. /// The id for the bet.
public private(set) var id: String public private(set) var id: String
@ -26,24 +26,27 @@ public class Bet: ObservableObject, Codable {
public private(set) var endBetDate: Date public private(set) var endBetDate: Date
/// Indicates whether the bet is public or private. /// Indicates whether the bet is public or private.
public private(set) var isPrivate: Bool public private(set) var isPublic: Bool
/// The current status of the bet. /// The current status of the bet.
public private(set) var status: BetStatus public private(set) var status: BetStatus
/// List of users who are invited to participate in the bet. /// List of users who are invited to participate in the bet.
public private(set) var invited: [String] = [] public private(set) var invited: [User] = []
/// The user who created the bet. /// The user who created the bet.
public private(set) var author: String public private(set) var author: String
/// List of users who have registered for the bet.
public private(set) var registered: [User] = []
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case id case id
case theme case theme
case phrase = "sentenceBet" case phrase = "sentenceBet"
case endRegisterDate = "endRegistration" case endRegisterDate = "endRegistration"
case endBetDate = "endBet" case endBetDate = "endBet"
case isPrivate = "isPrivate" case isPublic = "isPrivate"
case status case status
case author = "createdBy" case author = "createdBy"
} }
@ -60,7 +63,7 @@ public class Bet: ObservableObject, Codable {
self.endRegisterDate = formatter.date(from: endRegisterDateString)! self.endRegisterDate = formatter.date(from: endRegisterDateString)!
let endBetDateString = try container.decode(String.self, forKey: .endBetDate) let endBetDateString = try container.decode(String.self, forKey: .endBetDate)
self.endBetDate = formatter.date(from: endBetDateString)! self.endBetDate = formatter.date(from: endBetDateString)!
self.isPrivate = try container.decode(Bool.self, forKey: .isPrivate) self.isPublic = try container.decode(Bool.self, forKey: .isPublic)
self.status = try container.decode(BetStatus.self, forKey: .status) self.status = try container.decode(BetStatus.self, forKey: .status)
self.author = try container.decode(String.self, forKey: .author) self.author = try container.decode(String.self, forKey: .author)
} }
@ -77,16 +80,18 @@ public class Bet: ObservableObject, Codable {
/// - status: The current status of the bet. /// - status: The current status of the bet.
/// - invited: List of users who are invited to participate in the bet. /// - invited: List of users who are invited to participate in the bet.
/// - author: The user who created the bet. /// - author: The user who created the bet.
public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPrivate: Bool, status: BetStatus, invited: [String], author: String) { /// - registered: List of users who have registered for the bet.
public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: String, registered: [User]) {
self.id = id self.id = id
self.theme = theme self.theme = theme
self.phrase = phrase self.phrase = phrase
self.endRegisterDate = endRegisterDate self.endRegisterDate = endRegisterDate
self.endBetDate = endBetDate self.endBetDate = endBetDate
self.isPrivate = isPrivate self.isPublic = isPublic
self.status = status self.status = status
self.invited = invited self.invited = invited
self.author = author self.author = author
self.registered = registered
} }
/// Custom Constructor without Id /// Custom Constructor without Id
@ -100,23 +105,18 @@ public class Bet: ObservableObject, Codable {
/// - status: The current status of the bet. /// - status: The current status of the bet.
/// - invited: List of users who are invited to participate in the bet. /// - invited: List of users who are invited to participate in the bet.
/// - author: The user who created the bet. /// - author: The user who created the bet.
public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPrivate: Bool, status: BetStatus, invited: [String], author: String) { /// - registered: List of users who have registered for the bet.
public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: String, registered: [User]) {
self.id = UUID().uuidString self.id = UUID().uuidString
self.theme = theme self.theme = theme
self.phrase = phrase self.phrase = phrase
self.endRegisterDate = endRegisterDate self.endRegisterDate = endRegisterDate
self.endBetDate = endBetDate self.endBetDate = endBetDate
self.isPrivate = isPrivate self.isPublic = isPublic
self.status = status self.status = status
self.invited = invited self.invited = invited
self.author = author self.author = author
} self.registered = registered
/// Function that returns an empty list of responses
///
/// - Returns: An empty list of responses
public func getResponses() -> [String] {
return []
} }
} }

@ -20,19 +20,7 @@ public class BetDetail: ObservableObject {
public private(set) var participations: [Participation] public private(set) var participations: [Participation]
/// The final answer selected for the bet, if available. /// The final answer selected for the bet, if available.
public private(set) var wonParticipation: Participation? public private(set) var finalAnswer: String?
public private(set) var userParticipation: Participation?
public var odds: Float? {
guard let wonParticipation = self.wonParticipation else {
return nil
}
if let matchingAnswer = self.answers.first(where: { $0.response == wonParticipation.answer }) {
return matchingAnswer.odds
} else {
return nil
}
}
/// Custom Constructor /// Custom Constructor
/// ///
@ -41,19 +29,18 @@ public class BetDetail: ObservableObject {
/// - answers: Details about the answers available for the bet. /// - answers: Details about the answers available for the bet.
/// - participations: List of user participations in the bet. /// - participations: List of user participations in the bet.
/// - finalAnswer: The final answer selected for the bet, if available. /// - finalAnswer: The final answer selected for the bet, if available.
public init(bet: Bet, answers: [AnswerDetail], participations: [Participation], wonParticipation: Participation? = nil, userParticipation: Participation? = nil) { public init(bet: Bet, answers: [AnswerDetail], participations: [Participation], finalAnswer: String? = nil) {
self.bet = bet self.bet = bet
self.answers = answers self.answers = answers
self.participations = participations self.participations = participations
self.wonParticipation = wonParticipation self.finalAnswer = finalAnswer
self.userParticipation = userParticipation
} }
/// Updates the final answer selected for the bet. /// Updates the final answer selected for the bet.
/// ///
/// - Parameter newFinalAnswer: The new final answer for the bet. /// - Parameter newFinalAnswer: The new final answer for the bet.
public func updateFinalAnswer(wonParticipation: Participation) { public func updateFinalAnswer(newFinalAnswer: String) {
self.wonParticipation = wonParticipation self.finalAnswer = newFinalAnswer
} }
/// Adds a new user participation to the list of participations for the bet. /// Adds a new user participation to the list of participations for the bet.

@ -1,21 +0,0 @@
//
// BetResult.swift
//
//
// Created by Emre on 06/06/2024.
//
import Foundation
public class BetResult: Codable {
public private(set) var betId: String
public private(set) var result: String
public init(betId: String, result: String) {
self.betId = betId
self.result = result
}
}

@ -1,30 +0,0 @@
//
// BetResultDetail.swift
//
//
// Created by Emre on 06/06/2024.
//
import Foundation
public class BetResultDetail: Codable {
public private(set) var betResult: BetResult
public private(set) var bet: Bet
public private(set) var participation: Participation
public private(set) var amount: Int
public private(set) var won: Bool
public init(betResult: BetResult, bet: Bet, participation: Participation, amount: Int, won: Bool) {
self.betResult = betResult
self.bet = bet
self.participation = participation
self.amount = amount
self.won = won
}
}

@ -10,21 +10,4 @@ import Foundation
/// A subclass of Bet that represents a custom bet, allowing users to define their own parameters and rules. /// A subclass of Bet that represents a custom bet, allowing users to define their own parameters and rules.
public class CustomBet: Bet { public class CustomBet: Bet {
/// List of custom responses
private var customResponses: [String] = []
/// Override the getResponses function to return custom responses
///
/// - Returns: A list of custom responses
public override func getResponses() -> [String] {
return customResponses
}
/// Add a custom response
///
/// - Parameter response: The custom response to add
public func addCustomResponse(_ response: String) {
customResponses.append(response)
}
} }

@ -11,5 +11,4 @@ public protocol FactoryBet {
func toResponse(bet: Bet) -> [String: Any] func toResponse(bet: Bet) -> [String: Any]
func toBet(from json: [String: Any]) -> Bet? func toBet(from json: [String: Any]) -> Bet?
func toBetDetail(from json: [String: Any]) -> BetDetail? func toBetDetail(from json: [String: Any]) -> BetDetail?
func toBetResultDetail(from json: [String: Any]) -> BetResultDetail?
} }

@ -46,12 +46,6 @@ public struct Manager {
} }
} }
public func getBetsWon(completion: @escaping ([BetResultDetail]) -> Void) {
userDataManager.getBetsWon() { bets in
completion(bets)
}
}
public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) { public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) {
betDataManager.getBet(withId: id) { bet in betDataManager.getBet(withId: id) { bet in
completion(bet) completion(bet)
@ -76,7 +70,7 @@ public struct Manager {
} }
} }
public func getHistoricBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetResultDetail]) -> Void) { public func getHistoricBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetDetail]) -> Void) {
userDataManager.getOldBets(withIndex: index, withCount: count) { bets in userDataManager.getOldBets(withIndex: index, withCount: count) { bets in
completion(bets) completion(bets)
} }

@ -33,12 +33,13 @@ public class MatchBet: Bet {
/// - status: The current status of the match bet. /// - status: The current status of the match bet.
/// - invited: List of users who are invited to participate in the match bet. /// - invited: List of users who are invited to participate in the match bet.
/// - author: The user who created the match bet. /// - author: The user who created the match bet.
/// - registered: List of users who have registered for the match bet.
/// - nameTeam1: The name of the first team involved in the match. /// - nameTeam1: The name of the first team involved in the match.
/// - nameTeam2: The name of the second team involved in the match. /// - nameTeam2: The name of the second team involved in the match.
public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPrivate: Bool, status: BetStatus, invited: [String], author: String, nameTeam1: String, nameTeam2: String) { public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: String, registered: [User], nameTeam1: String, nameTeam2: String) {
self.nameTeam1 = nameTeam1 self.nameTeam1 = nameTeam1
self.nameTeam2 = nameTeam2 self.nameTeam2 = nameTeam2
super.init(id: id, theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPrivate: isPrivate, status: status, invited: invited, author: author) super.init(id: id, theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPublic: isPublic, status: status, invited: invited, author: author, registered: registered)
} }
/// Custom Constructor without Id /// Custom Constructor without Id
@ -52,12 +53,13 @@ public class MatchBet: Bet {
/// - status: The current status of the match bet. /// - status: The current status of the match bet.
/// - invited: List of users who are invited to participate in the match bet. /// - invited: List of users who are invited to participate in the match bet.
/// - author: The user who created the match bet. /// - author: The user who created the match bet.
/// - registered: List of users who have registered for the match bet.
/// - nameTeam1: The name of the first team involved in the match. /// - nameTeam1: The name of the first team involved in the match.
/// - nameTeam2: The name of the second team involved in the match. /// - nameTeam2: The name of the second team involved in the match.
public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPrivate: Bool, status: BetStatus, invited: [String], author: String, nameTeam1: String, nameTeam2: String) { public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: String, registered: [User], nameTeam1: String, nameTeam2: String) {
self.nameTeam1 = nameTeam1 self.nameTeam1 = nameTeam1
self.nameTeam2 = nameTeam2 self.nameTeam2 = nameTeam2
super.init(theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPrivate: isPrivate, status: status, invited: invited, author: author) super.init(theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPublic: isPublic, status: status, invited: invited, author: author, registered: registered)
} }
public required init(from decoder: Decoder) throws { public required init(from decoder: Decoder) throws {

@ -8,7 +8,9 @@
import Foundation import Foundation
/// A class representing a user's participation in a bet. /// A class representing a user's participation in a bet.
public class Participation: ObservableObject, Codable, Identifiable, Hashable { public class Participation: ObservableObject, Codable, Identifiable {
public let id: String
/// The amount of stake in the bet. /// The amount of stake in the bet.
public private(set) var stake: Int public private(set) var stake: Int
@ -26,29 +28,15 @@ public class Participation: ObservableObject, Codable, Identifiable, Hashable {
/// ///
/// - Parameters: /// - Parameters:
/// - stake: The amount of stake in the bet. /// - stake: The amount of stake in the bet.
/// - answer: The response or outcome of the participation. /// - date: The date and time when the participation occurred.
/// - username: The user who participated in the bet. /// - response: The response or outcome of the participation.
/// - user: The user who participated in the bet.
/// - betId: The unique identifier of the bet. /// - betId: The unique identifier of the bet.
public init(stake: Int, answer: String, username: String, betId: String) { public init(id: String, stake: Int, answer: String, username: String, betId: String) {
self.id = id
self.stake = stake self.stake = stake
self.answer = answer self.answer = answer
self.username = username self.username = username
self.betId = betId self.betId = betId
} }
// Conformance to Equatable
public static func == (lhs: Participation, rhs: Participation) -> Bool {
return lhs.stake == rhs.stake &&
lhs.answer == rhs.answer &&
lhs.username == rhs.username &&
lhs.betId == rhs.betId
}
// Conformance to Hashable
public func hash(into hasher: inout Hasher) {
hasher.combine(stake)
hasher.combine(answer)
hasher.combine(username)
hasher.combine(betId)
}
} }

@ -8,9 +8,7 @@
import Foundation import Foundation
/// A struct representing a user with details such as username, email, number of coins, and friends. /// A struct representing a user with details such as username, email, number of coins, and friends.
public struct User: Codable, Hashable, Identifiable { public struct User: Codable, Hashable {
public var id: String
/// The username of the user. /// The username of the user.
public private(set) var username: String public private(set) var username: String
@ -24,17 +22,17 @@ public struct User: Codable, Hashable, Identifiable {
/// The friendship status with the main user. /// The friendship status with the main user.
public var friendStatus: FriendStatus? public var friendStatus: FriendStatus?
/// The user's profile image. /// Custom constructor to initialize a User instance.
public var image: String? ///
/// - Parameters:
/// The number of bets made by the user. /// - username: The username of the user.
public var nbBets: Int /// - email: The email address of the user.
/// - nbCoins: The number of coins associated with the user.
/// The number of friends the user has. public init(username: String, email: String, nbCoins: Int) {
public var nbFriends: Int self.username = username
self.email = email
/// The user's best win. self.nbCoins = nbCoins
public var bestWin: Int }
/// Custom constructor to initialize a User instance. /// Custom constructor to initialize a User instance.
/// ///
@ -42,20 +40,11 @@ public struct User: Codable, Hashable, Identifiable {
/// - username: The username of the user. /// - username: The username of the user.
/// - email: The email address of the user. /// - email: The email address of the user.
/// - nbCoins: The number of coins associated with the user. /// - nbCoins: The number of coins associated with the user.
/// - friendStatus: The friendship status with the main user. /// - status: The friendship status with the main user.
/// - image: The user's profile image. public init(username: String, email: String, nbCoins: Int, status: FriendStatus) {
/// - nbBets: The number of bets made by the user.
/// - nbFriends: The number of friends the user has.
/// - bestWin: The user's best win.
public init(username: String, email: String, nbCoins: Int, friendStatus: FriendStatus? = nil, image: String? = nil, nbBets: Int, nbFriends: Int, bestWin: Int) {
self.id = UUID().description
self.username = username self.username = username
self.email = email self.email = email
self.nbCoins = nbCoins self.nbCoins = nbCoins
self.friendStatus = friendStatus self.friendStatus = status
self.image = image
self.nbBets = nbBets
self.nbFriends = nbFriends
self.bestWin = bestWin
} }
} }

@ -10,7 +10,6 @@ import Foundation
public protocol UserDataManager { public protocol UserDataManager {
func getBets(withIndex index: Int, withCount count: Int) -> [Bet] func getBets(withIndex index: Int, withCount count: Int) -> [Bet]
func getBetsOver(completion: @escaping ([BetDetail]) -> Void) func getBetsOver(completion: @escaping ([BetDetail]) -> Void)
func getBetsWon(completion : @escaping ([BetResultDetail])-> ())
func addBet(bet: Bet, completion : @escaping (Int)-> ()) func addBet(bet: Bet, completion : @escaping (Int)-> ())
func addFriend(username: String, completion : @escaping (Int)-> ()) func addFriend(username: String, completion : @escaping (Int)-> ())
func removeFriend(username: String, completion : @escaping (Int)-> ()) func removeFriend(username: String, completion : @escaping (Int)-> ())
@ -18,7 +17,7 @@ public protocol UserDataManager {
func getRequests(completion: @escaping ([User]) -> Void) func getRequests(completion: @escaping ([User]) -> Void)
func getUsers(withName name: String, completion: @escaping ([User]) -> Void) func getUsers(withName name: String, completion: @escaping ([User]) -> Void)
func getGifts(completion : @escaping (Int, Int)-> ()) func getGifts(completion : @escaping (Int, Int)-> ())
func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetResultDetail]) -> Void) func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetDetail]) -> Void)
func getCurrentBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetDetail]) -> Void) func getCurrentBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetDetail]) -> Void)
func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int, completion : @escaping (Int)-> ()) func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int, completion : @escaping (Int)-> ())
func addResponse(withIdBet id: String, andResponse responseBet: String) func addResponse(withIdBet id: String, andResponse responseBet: String)

@ -21,13 +21,13 @@ struct Stub {
public mutating func loadBets() { public mutating func loadBets() {
let user1 = User(username: "Lucas", email: "lucas.delanier@etu.uca.fr", nbCoins: 100, nbBets: 0, nbFriends: 0, bestWin: 0) let user1 = User(username: "Lucas", email: "lucas.delanier@etu.uca.fr", nbCoins: 100)
users.append(user1) users.append(user1)
let user2 = User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, nbBets: 0, nbFriends: 0, bestWin: 0) let user2 = User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75)
users.append(user2) users.append(user2)
let user3 = User(username: "Arthur", email: "arthur.valin@etu.uca.fr", nbCoins: 30, nbBets: 0, nbFriends: 0, bestWin: 0) let user3 = User(username: "Arthur", email: "arthur.valin@etu.uca.fr", nbCoins: 30)
users.append(user3) users.append(user3)
let bet1 = BinaryBet( let bet1 = BinaryBet(
@ -35,10 +35,11 @@ struct Stub {
phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.",
endRegisterDate: Date().addingTimeInterval(-86400), endRegisterDate: Date().addingTimeInterval(-86400),
endBetDate: Date().addingTimeInterval(172800), endBetDate: Date().addingTimeInterval(172800),
isPrivate: false, isPublic: true,
status: .inProgress, status: .inProgress,
invited: [], invited: [],
author: "Lucas" author: "Lucas",
registered: [user2]
) )
self.bets.append(bet1) self.bets.append(bet1)
@ -47,10 +48,11 @@ struct Stub {
phrase: "Le plat préféré du jury sera une recette végétarienne.", phrase: "Le plat préféré du jury sera une recette végétarienne.",
endRegisterDate: Date().addingTimeInterval(172800), endRegisterDate: Date().addingTimeInterval(172800),
endBetDate: Date().addingTimeInterval(259200), endBetDate: Date().addingTimeInterval(259200),
isPrivate: false, isPublic: false,
status: .inProgress, status: .inProgress,
invited: [], invited: [user3],
author: "Lucas" author: "Lucas",
registered: [user2]
) )
self.bets.append(bet2) self.bets.append(bet2)
@ -59,10 +61,11 @@ struct Stub {
phrase: "Le nombre total de précommandes dépassera-t-il 1 million dans la première semaine ?", phrase: "Le nombre total de précommandes dépassera-t-il 1 million dans la première semaine ?",
endRegisterDate: Date().addingTimeInterval(259200), endRegisterDate: Date().addingTimeInterval(259200),
endBetDate: Date().addingTimeInterval(345600), endBetDate: Date().addingTimeInterval(345600),
isPrivate: true, isPublic: true,
status: .finished, status: .finished,
invited: [], invited: [],
author: "Lucas" author: "Lucas",
registered: [user2, user1, user3]
) )
self.bets.append(bet3) self.bets.append(bet3)
@ -71,10 +74,11 @@ struct Stub {
phrase: "Le film favori des critiques remportera-t-il le prix du meilleur film ?", phrase: "Le film favori des critiques remportera-t-il le prix du meilleur film ?",
endRegisterDate: Date().addingTimeInterval(345600), endRegisterDate: Date().addingTimeInterval(345600),
endBetDate: Date().addingTimeInterval(432000), endBetDate: Date().addingTimeInterval(432000),
isPrivate: false, isPublic: false,
status: .finished, status: .finished,
invited: [], invited: [user1],
author: "Lucase" author: "Lucase",
registered: [user3]
) )
self.bets.append(bet4) self.bets.append(bet4)
@ -83,15 +87,15 @@ struct Stub {
self.betsDetail.append(betDetail) self.betsDetail.append(betDetail)
} }
self.betsDetail[0].addParticipation(newParticipation: Participation(stake: 120, answer: "OUI", username: user1.username, betId: "1")) self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 120, answer: "OUI", username: user1.username, betId: "1"))
self.betsDetail[0].addParticipation(newParticipation: Participation(stake: 20, answer: "NON", username: user2.username, betId: "2")) self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 20, answer: "NON", username: user2.username, betId: "2"))
self.betsDetail[0].addParticipation(newParticipation: Participation(stake: 320, answer: "OUI", username: user3.username, betId: "3")) self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 320, answer: "OUI", username: user3.username, betId: "3"))
self.betsDetail[0].addParticipation(newParticipation: Participation(stake: 320, answer: "OUI", username: user3.username, betId: "3")) self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 320, answer: "OUI", username: user3.username, betId: "3"))
} }
public mutating func add(bet: Bet) { public mutating func add(bet: Bet) {
let newBetDetail = BetDetail(bet: bet, answers: [], participations: []) let newBetDetail = BetDetail(bet: bet, answers: [], participations: [], finalAnswer: "test")
self.betsDetail.append(newBetDetail) self.betsDetail.append(newBetDetail)
} }
} }

Loading…
Cancel
Save