feature/display_bet_details #16

Merged
emre.kartal merged 18 commits from feature/display_bet_details into master 1 year ago

@ -2,16 +2,13 @@
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "group:Api"> location = "group:StubLib">
</FileRef>
<FileRef
location = "group:AllInApp/AllInApp.xcodeproj">
</FileRef> </FileRef>
<FileRef <FileRef
location = "group:StubLib"> location = "group:Api">
</FileRef> </FileRef>
<FileRef <FileRef
location = "group:ViewModel"> location = "group:AllInApp/AllInApp.xcodeproj">
</FileRef> </FileRef>
<FileRef <FileRef
location = "group:DependencyInjection/DependencyInjection.xcodeproj"> location = "group:DependencyInjection/DependencyInjection.xcodeproj">

@ -8,7 +8,6 @@
import SwiftUI import SwiftUI
import DependencyInjection import DependencyInjection
import Model import Model
import ViewModel
@main @main
struct AllInApp: App { struct AllInApp: App {

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x49",
"green" : "0x49",
"red" : "0x49"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x49",
"green" : "0x49",
"red" : "0x49"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xF8",
"green" : "0x99",
"red" : "0x23"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xF8",
"green" : "0x99",
"red" : "0x23"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

@ -20,7 +20,7 @@
} }
], ],
"color" : { "color" : {
"color-space" : "srgb", "color-space" : "display-p3",
"components" : { "components" : {
"alpha" : "1.000", "alpha" : "1.000",
"blue" : "0x45", "blue" : "0x45",

@ -0,0 +1,20 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x8A",
"green" : "0x2B",
"red" : "0xFE"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x8A",
"green" : "0x2B",
"red" : "0xFE"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xA8",
"green" : "0x49",
"red" : "0xC2"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xA8",
"green" : "0x49",
"red" : "0xC2"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 B

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xC5",
"green" : "0x66",
"red" : "0x8A"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xC5",
"green" : "0x66",
"red" : "0x8A"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFF",
"green" : "0xE8",
"red" : "0xD1"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFF",
"green" : "0xE8",
"red" : "0xD1"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct AllcoinsCounter: View { struct AllcoinsCounter: View {
var backgroundColor: Color = .white
var foregroundColor: Color = AllInColors.primaryColor
var body: some View { var body: some View {
HStack(alignment: .center) { HStack(alignment: .center) {
Image("allcoinIcon") Image("allcoinIcon")
@ -15,10 +17,10 @@ struct AllcoinsCounter: View {
.frame(width: 17, height: 17, alignment: .leading) .frame(width: 17, height: 17, alignment: .leading)
Text(String(AppStateContainer.shared.user?.nbCoins ?? 0)) Text(String(AppStateContainer.shared.user?.nbCoins ?? 0))
.fontWeight(.black) .fontWeight(.black)
.foregroundColor(AllInColors.primaryColor) .foregroundColor(foregroundColor)
} }
.frame(width: 90, height: 40) .frame(width: 90, height: 40)
.background(Color.white) .background(backgroundColor)
.cornerRadius(9999, corners: [.topLeft, .bottomLeft]) .cornerRadius(9999, corners: [.topLeft, .bottomLeft])
} }

@ -11,22 +11,29 @@ import Model
struct BetCard: View { struct BetCard: View {
var bet: Bet var bet: Bet
@State var showDetails: Bool = false
@State var showParticipate: Bool = false
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("proposé par " + bet.author.username.capitalized).font(.system(size: 10)).foregroundColor(AllInColors.grey800Color) Text("proposé par " + bet.author.username.capitalized)
.font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color)
} }
Text(bet.theme).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) Text(bet.theme)
Text(bet.phrase).font(.system(size: 20)).fontWeight(.bold) .font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
Text(bet.phrase)
.font(.system(size: 20))
.fontWeight(.bold)
HStack{ HStack{
Text("Commence le").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) Text("Commence le").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
TextCapsule(date: bet.endRegisterDate) TextCapsule(date: bet.endRegisterDate)
Spacer() Spacer()
} }
} }
.frame(width: .infinity) .frame(width: .infinity)
@ -37,35 +44,15 @@ struct BetCard: View {
HStack{ HStack{
Spacer() Spacer()
UsersPreview() UsersPreview()
Text(String(bet.registered.count) + " joueurs en attente").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color).fontWeight(.medium) Text(String(bet.registered.count) + " joueurs en attente")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
.fontWeight(.medium)
Spacer() Spacer()
}.padding(0) }.padding(0)
Button { ParticipateButton(isOpen: $showDetails, isParticapatedOpen: $showParticipate, bet: bet)
.padding(.top, 5)
} label: {
Text("Participer")
.font(.system(size: 30))
.fontWeight(.bold)
.frame(maxWidth: .infinity).padding(10)
.multilineTextAlignment(.center)
.overlay {
AllInColors.primaryGradient.frame(width: 170)
.mask(
Text("Participer")
.font(.system(size: 30))
.fontWeight(.bold)
.frame(maxWidth: .infinity).padding(10)
)
}
}
.accentColor(AllInColors.componentBackgroundColor)
.buttonStyle(.borderedProminent).cornerRadius(4.0)
.overlay(
RoundedRectangle(cornerRadius: 12).stroke(AllInColors.delimiterGrey, lineWidth: 1)
).padding([.top],5)
} }
.frame(width: .infinity) .frame(width: .infinity)
.padding(.all,8) .padding(.all,8)
@ -73,6 +60,12 @@ struct BetCard: View {
.cornerRadius(20, corners: [.bottomLeft,.bottomRight]) .cornerRadius(20, corners: [.bottomLeft,.bottomRight])
.border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
} }
.onTapGesture {
showDetails.toggle()
}
.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, isModalParticipated: $showParticipate,id: bet.id)
}
} }
} }
@ -82,8 +75,8 @@ 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),
totalStakes: 100,
isPublic: true, isPublic: true,
status: .FINISHED,
invited: [], invited: [],
author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []), author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []),
registered: [])) registered: []))

@ -0,0 +1,101 @@
//
// BetLineLoading.swift
// AllIn
//
// Created by Lucas Delanier on 19/01/2024.
//
import SwiftUI
import Model
struct BetLineLoading: View {
var participations: [Participation]
var value: CGFloat {
let totalParticipations = participations.count
let numberOfYes = participations.filter { $0.response.uppercased() == "YES" }.count
let numberOfNo = participations.filter { $0.response.uppercased() == "NO" }.count
if(numberOfNo == 0 && numberOfYes == 0){
return 0.5
}
return totalParticipations > 0 ? CGFloat(numberOfYes) / CGFloat(totalParticipations) : 0.0
}
var yesParticipations: [Participation] {
return participations.filter { $0.response.uppercased() == "YES" }
}
var noParticipations: [Participation] {
return participations.filter { $0.response.uppercased() == "NO" }
}
var body: some View {
GeometryReader { geometry in
VStack(alignment: .leading,spacing: 0){
HStack(spacing: 5){
Text("OUI").font(.system(size: 25)).fontWeight(.bold).foregroundColor(AllInColors.bleue200)
Spacer()
Text("NON").font(.system(size: 25)).fontWeight(.bold).foregroundColor(AllInColors.pink100)
}
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)
.animation(.linear)
Image("LoadingHeart").resizable().frame(width: 29, height: 32).padding(.leading, -10)
}
}
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.bleue200)
Spacer()
Text(noParticipations.reduce(0, {x,y in x + y.stake}).description).font(.system(size: 15)).fontWeight(.bold).foregroundColor(AllInColors.pink100)
Image("PinkBadge").resizable().frame(width:10, height: 14)
}
HStack(spacing: 5){
Image("BleuePersonIcon").resizable().frame(width:14, height: 12)
Text(yesParticipations.count.description).font(.system(size: 15)).fontWeight(.bold).foregroundColor(AllInColors.bleue200)
Spacer()
Text(noParticipations.count.description).font(.system(size: 15)).fontWeight(.bold).foregroundColor(AllInColors.pink100)
Image("PinkBadge").resizable().frame(width:10, height: 14)
}
HStack(spacing: 5){
Image("BleueBadge").resizable().frame(width:10, height: 14)
Text(yesParticipations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0").font(.system(size: 15)).fontWeight(.bold).foregroundColor(AllInColors.bleue200)
Spacer()
Text(noParticipations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0").font(.system(size: 15)).fontWeight(.bold).foregroundColor(AllInColors.pink100)
Image("PinkBadge").resizable().frame(width:10, height: 14)
}
HStack(spacing: 5){
Image("BleueTrophyIcon").resizable().frame(width:14, height: 13)
Text("1.2").font(.system(size: 15)).fontWeight(.bold).foregroundColor(AllInColors.bleue200)
Spacer()
Text("1.2").font(.system(size: 15)).fontWeight(.bold).foregroundColor(AllInColors.pink100)
Image("PinkBadge").resizable().frame(width:10, height: 14)
}
}
}
}.frame(height: 140)
}
}

@ -0,0 +1,81 @@
//
// DropDownAnswerMenu.swift
// AllIn
//
// Created by Lucas Delanier on 16/01/2024.
//
import SwiftUI
//
// DropDownMenu.swift
// AllIn
//
// Created by Emre on 19/10/2023.
//
import SwiftUI
struct DropDownAnswerMenu: View {
@State var expand = false
@Binding var selectedOption: Int
var options: [(Int, String, Float)]
var body: some View {
VStack(spacing: 0, content: {
Button(action: { self.expand.toggle() }) {
HStack{
Text(options[selectedOption].1.description)
.textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20)
Text(options[selectedOption].2.description)
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10)
Spacer()
Image(expand ? "chevronUpIcon" : "chevronDownIcon").resizable().frame(width: 15, height: 10).scaledToFill()
}
.padding([.leading, .trailing], 15)
.frame(height: 43)
}
if expand {
Rectangle()
.frame(height: 1)
.foregroundColor(AllInColors.delimiterGrey)
.padding(.bottom, 18)
VStack(spacing: 0) {
ForEach(0..<options.count, id: \.self) { index in
if options[index].0 != selectedOption {
Button(action: {self.selectedOption = options[index].0
self.expand.toggle()}) {
HStack{
Text(options[index].1.description)
.textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20)
Text(options[index].2.description)
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10)
Spacer()
}
}
.padding(.bottom, 15)
}
}
}
.padding([.leading, .trailing], 15)
}
})
.frame(width: .infinity)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(10)
}
}
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,8 +6,12 @@
// //
import SwiftUI import SwiftUI
import DependencyInjection
struct Menu: View { struct Menu: View {
@Inject var authService: IAuthService
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
@ -93,6 +97,17 @@ struct Menu: View {
.padding([.leading,.trailing], 13) .padding([.leading,.trailing], 13)
} }
HStack {
Spacer()
Button {
authService.logout()
} label: {
Text("Deconnexion")
.foregroundColor(.white)
}
Spacer()
}
Spacer() Spacer()
Image("gearIcon") Image("gearIcon")
.resizable() .resizable()

@ -0,0 +1,29 @@
//
// ParticiationCell.swift
// AllIn
//
// Created by Lucas Delanier on 21/01/2024.
//
import SwiftUI
import Model
struct ParticiationCell: 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, 5)
Text(participation?.user.username ?? "Unknown")
.font(.system(size: 15))
.foregroundStyle(AllInColors.grey100Color)
.fontWeight(.semibold)
Spacer()
Text(participation?.stake.description ?? "NaN")
.font(.system(size: 18))
.foregroundStyle(AllInColors.lightPurpleColor)
.fontWeight(.bold).padding(.trailing, 5)
Image("PurpleAllCoin").resizable().frame(width: 11, height: 12)
}
}
}

@ -0,0 +1,71 @@
//
// ParticipateButton.swift
// AllIn
//
// Created by Lucas Delanier on 15/01/2024.
//
import SwiftUI
import Model
struct ParticipateButton: View {
@Binding var isOpen : Bool
@Binding var isParticapatedOpen: Bool
var bet: Bet?
var isDisabled: Bool {
guard let endRegisterDate = bet?.endRegisterDate else {
return true
}
let currentDate = Date()
switch currentDate.compare(endRegisterDate) {
case .orderedAscending:
return false
case .orderedDescending, .orderedSame:
return true
}
}
var body: some View {
Button {
isOpen = true
isParticapatedOpen = true
} label: {
Text("Participer")
.font(.system(size: 27))
.fontWeight(.semibold)
.frame(maxWidth: .infinity).padding(10)
.multilineTextAlignment(.center)
.overlay {
switch isDisabled {
case true:
AllInColors.grey700Color.frame(width: 170)
.mask(
Text("Participer")
.font(.system(size: 27))
.fontWeight(.semibold)
.frame(maxWidth: .infinity).padding(10)
)
case false:
AllInColors.primaryGradient.frame(width: 170)
.mask(
Text("Participer")
.font(.system(size: 27))
.fontWeight(.semibold)
.frame(maxWidth: .infinity).padding(10)
)
}
}
.accentColor(AllInColors.componentBackgroundColor)
.background(isDisabled ? AllInColors.delimiterGrey.opacity(0.5):AllInColors.whiteColor)
.buttonStyle(.borderedProminent).cornerRadius(4.0)
.overlay(
RoundedRectangle(cornerRadius: 12).stroke(AllInColors.delimiterGrey, lineWidth: 1)
)
}.disabled(isDisabled)
}
}

@ -0,0 +1,112 @@
//
// ParticipationModal.swift
// AllIn
//
// Created by Lucas Delanier on 16/01/2024.
//
import SwiftUI
struct ParticipationModal: View {
@Binding private var selectedOption: Int
@Binding private var mise: String
private var description: String
var participationAddedCallback: (() -> Void)?
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 {
VStack(alignment: .leading){
HStack{
Spacer()
Rectangle()
.foregroundStyle(AllInColors.grey800Color)
.frame(maxWidth: 80, maxHeight: 5)
.cornerRadius(999)
Spacer()
}.padding(10)
HStack{
Text("Faites vos paris")
.font(.system(size: 18))
.foregroundColor(AllInColors.blackTitleColor)
.fontWeight(.semibold)
Spacer()
AllcoinsCounter(backgroundColor: AllInColors.purpleAccentColor, foregroundColor: AllInColors.whiteColor)
}
.padding(.leading, 15)
VStack(alignment: .leading){
Text(description)
.font(.system(size: 13))
.foregroundColor(AllInColors.grey100Color)
.fontWeight(.light)
DropDownAnswerMenu(selectedOption: $selectedOption, options: options)
TextField("",text: $mise, prompt: Text("Mise")
.foregroundColor(AllInColors.lightGrey300Color)
.font(.system(size: 14))
.fontWeight(.bold))
.padding()
.keyboardType(.numberPad)
.background(
RoundedRectangle(cornerRadius: 9)
.fill(AllInColors.lightGrey200Color)
.frame(height: 40)
)
.frame(width: .infinity, height: 40)
.foregroundColor(AllInColors.primaryTextColor)
.overlay(
RoundedRectangle(cornerRadius: 10, style: .continuous)
.stroke(AllInColors.delimiterGrey, lineWidth: 1)
)
.padding(.bottom, 5)
}
.padding(15)
Spacer()
VStack{
HStack{
Text("Gains possibles")
.font(.system(size: 13))
.foregroundColor(AllInColors.blackTitleColor)
.fontWeight(.regular)
Spacer()
Text("231")
.font(.system(size: 13))
.foregroundColor(AllInColors.blackTitleColor)
.fontWeight(.light)
}
.padding(.top, 10).padding(.bottom, 0)
Button {
participationAddedCallback?()
} label: {
Text("Miser")
.font(.system(size: 23))
.foregroundColor(AllInColors.whiteColor)
.fontWeight(.bold)
.frame(maxWidth: .infinity)
.padding(.vertical, 3)
}
.buttonStyle(.borderedProminent)
.tint(AllInColors.purpleAccentColor)
}
.padding(.horizontal, 10)
.background(AllInColors.whiteColor)
.border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
}
.background(AllInColors.underComponentBackgroundColor)
}
}

@ -11,6 +11,8 @@ struct RecapBetCard: View {
@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 showPartipated: Bool = false
var body: some View { var body: some View {
VStack(spacing: 0){ VStack(spacing: 0){
VStack(alignment: .leading,spacing: 2){ VStack(alignment: .leading,spacing: 2){
@ -103,6 +105,11 @@ struct RecapBetCard: View {
.padding(.bottom,0).border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) .padding(.bottom,0).border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
}.scaleEffect(longPressTap ? 0.97 : 1.0) }.scaleEffect(longPressTap ? 0.97 : 1.0)
.animation(.easeInOut, value: longPressTap) .animation(.easeInOut, value: longPressTap)
.onTapGesture {
showDetails.toggle()
}.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, isModalParticipated: $showPartipated,id: "1")
}
.gesture( .gesture(
LongPressGesture(minimumDuration: 0.5) LongPressGesture(minimumDuration: 0.5)
.updating($longPressTap) { value, state, _ in .updating($longPressTap) { value, state, _ in

@ -0,0 +1,36 @@
//
// ResultBanner.swift
// AllIn
//
// Created by Lucas Delanier on 15/01/2024.
//
import SwiftUI
struct ResultBanner: View {
var body: some View {
VStack{
HStack{
Image("BleueTrophyIcon").resizable().frame(maxWidth: 70, maxHeight: 60)
Text("OUI").font(.system(size: 70)).fontWeight(.bold).foregroundStyle(AllInColors.blueGrey800Color)
}.frame(height: 80)
HStack(spacing: 20){
HStack{
Image("BlueAllCoinIcon").resizable().frame(maxWidth: 12, maxHeight: 12)
Text("460").font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color)
}
HStack{
Image("BleuePersonIcon").resizable().frame(maxWidth: 15, maxHeight: 12)
Text("ImriDu43").font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color)
}
HStack{
Image("BleueTrophyIcon").resizable().frame(maxWidth: 15, maxHeight: 12)
Text("x1.2").font(.system(size: 16)).fontWeight(.semibold).foregroundStyle(AllInColors.blueGrey800Color)
}
}
}
.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/)
.padding(.vertical, 20).background(AllInColors.winBannerBackground)
.border(width: 2, edges: [.top,.bottom], color: AllInColors.blueAccentColor.opacity(0.2))
}
}

@ -8,6 +8,8 @@
import SwiftUI import SwiftUI
struct ReviewCard: View { struct ReviewCard: View {
@State var showDetails: Bool = false
@State var showPartipated: Bool = false
var amountBetted: Int var amountBetted: Int
var isAWin: Bool var isAWin: Bool
@ -36,14 +38,14 @@ struct ReviewCard: View {
HStack(){ HStack(){
Spacer() Spacer()
Text(amountBetted.description) Text(amountBetted.description)
.foregroundColor(AllInColors.whiteColor) .foregroundColor(.white)
.font(.system(size: 25)) .font(.system(size: 25))
.fontWeight(.bold) .fontWeight(.bold)
Image("allcoinWhiteIcon") Image("allcoinWhiteIcon")
.resizable() .resizable()
.frame(width: 20, height: 20, alignment: .bottom) .frame(width: 20, height: 20, alignment: .bottom)
Text(isAWin ? "Gagnés!" : "Perdus!") Text(isAWin ? "Gagnés!" : "Perdus!")
.foregroundColor(AllInColors.whiteColor) .foregroundColor(.white)
.font(.system(size: 25)) .font(.system(size: 25))
.fontWeight(.bold) .fontWeight(.bold)
Spacer() Spacer()
@ -66,5 +68,10 @@ struct ReviewCard: View {
) .cornerRadius(20, corners: [.bottomLeft,.bottomRight]) ) .cornerRadius(20, corners: [.bottomLeft,.bottomRight])
.border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
} }
.onTapGesture {
showDetails.toggle()
}.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, isModalParticipated: $showPartipated, id: "1")
}
} }
} }

@ -83,3 +83,42 @@ extension View {
} }
} }
} }
struct SlideInFromBottomTransition: ViewModifier {
var yOffset: CGFloat
func body(content: Content) -> some View {
content
.offset(y: yOffset)
.animation(.easeInOut(duration: 0.3))
}
}
extension AnyTransition {
static func slideInFromBottom(yOffset: CGFloat) -> AnyTransition {
AnyTransition.modifier(
active: SlideInFromBottomTransition(yOffset: yOffset),
identity: SlideInFromBottomTransition(yOffset: 0)
)
}
}
struct SlideOutToBottomTransition: ViewModifier {
var yOffset: CGFloat
func body(content: Content) -> some View {
content
.offset(y: yOffset)
.opacity(yOffset == 0 ? 1 : 0)
.animation(.easeInOut(duration: 0.3))
}
}
extension AnyTransition {
static func slideOutToBottom(yOffset: CGFloat) -> AnyTransition {
AnyTransition.modifier(
active: SlideOutToBottomTransition(yOffset: yOffset),
identity: SlideOutToBottomTransition(yOffset: 0)
)
}
}

@ -47,7 +47,12 @@ struct AllInColors {
static let lightGrey300Color = Color("LightGrey300Color") static let lightGrey300Color = Color("LightGrey300Color")
static let componentBackgroundColor = Color("ComponentBackgroundColor") static let componentBackgroundColor = Color("ComponentBackgroundColor")
static let underComponentBackgroundColor = Color("UnderComponentBackgroundColor") static let underComponentBackgroundColor = Color("UnderComponentBackgroundColor")
static let winBannerBackground = Color("WinBannerBackground")
static let blackTitleColor = Color("BlackTitleColor")
static let bleue200 = Color("Bleue200")
static let purple200 = Color("Purple200")
static let pink200 = Color("Pink200")
static let pink100 = Color("Pink100")
// Gradients // Gradients
static let primaryGradient = LinearGradient( static let primaryGradient = LinearGradient(
gradient: Gradient(colors: [AllInColors.pinkAccentColor, AllInColors.blueAccentColor]), gradient: Gradient(colors: [AllInColors.pinkAccentColor, AllInColors.blueAccentColor]),
@ -60,4 +65,16 @@ struct AllInColors {
endPoint: .top endPoint: .top
) )
static let BlueBetGradiant = LinearGradient(
gradient: Gradient(colors: [AllInColors.bleue200, AllInColors.purple200]),
startPoint: .leading,
endPoint: .trailing
)
static let PinkBetGradiant = LinearGradient(
gradient: Gradient(colors: [AllInColors.pink100, AllInColors.pink200]),
startPoint: .leading,
endPoint: .trailing
)
} }

@ -8,5 +8,5 @@
import Foundation import Foundation
struct Config { struct Config {
static let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api" static let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/"
} }

@ -7,7 +7,6 @@
import Foundation import Foundation
import Model import Model
import ViewModel
import DependencyInjection import DependencyInjection
import Api import Api
import StubLib import StubLib
@ -34,23 +33,27 @@ class AuthService: IAuthService {
if let data = data, if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let token = json["token"] as? String { let token = json["token"] as? String {
AppStateContainer.shared.authenticationRefresh = token; AppStateContainer.shared.authenticationRefresh = token
self.initializeUser(withToken: token) { status in self.initializeUser(withToken: token) { status in
print(status)
if status != 200 { if status != 200 {
completion(status) completion(status)
AppStateContainer.shared.authenticationRefresh = nil; AppStateContainer.shared.authenticationRefresh = nil
} else { } else {
self.initManagerVM(token: token) self.initManagerVM(token: token)
completion(httpResponse.statusCode)
} }
} }
} }
} } else {
completion(httpResponse.statusCode) completion(httpResponse.statusCode)
} }
}
}.resume() }.resume()
} }
} }
func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) { func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) {
let url = URL(string: Config.allInApi + "/users/register")! let url = URL(string: Config.allInApi + "/users/register")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
@ -60,8 +63,7 @@ class AuthService: IAuthService {
let json = [ let json = [
"email": email.lowercased(), "email": email.lowercased(),
"username": username.lowercased(), "username": username.lowercased(),
"password": password, "password": password
"nbCoins": "0"
] ]
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){ if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){
@ -79,12 +81,14 @@ class AuthService: IAuthService {
AppStateContainer.shared.authenticationRefresh = nil; AppStateContainer.shared.authenticationRefresh = nil;
} else { } else {
self.initManagerVM(token: token) self.initManagerVM(token: token)
completion(httpResponse.statusCode)
} }
} }
} }
} } else {
completion(httpResponse.statusCode) completion(httpResponse.statusCode)
} }
}
}.resume() }.resume()
} }
} }
@ -119,8 +123,10 @@ class AuthService: IAuthService {
} }
private func initializeUser(withToken token: String, completion: @escaping (Int) -> ()) { private func initializeUser(withToken token: String, completion: @escaping (Int) -> ()) {
let url = URL(string: Config.allInApi + "users/token")! let url = URL(string: Config.allInApi + "users/token")!
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")
@ -144,7 +150,12 @@ class AuthService: IAuthService {
} }
private func initManagerVM(token: String) { private func initManagerVM(token: String) {
DependencyInjection.shared.addSingleton(ManagerVM.self, ManagerVM(withModel: Manager(withBetDataManager: BetApiManager(), withUserDataManager: UserApiManager(withUserToken: token)))) DependencyInjection.shared.addSingleton(Manager.self, Manager(withBetDataManager: BetApiManager(withUserToken: token), withUserDataManager: UserApiManager(withUserToken: token)))
}
public func logout() {
AppStateContainer.shared.authenticationRefresh = nil
AppStateContainer.shared.loggedState.connectedUser = false
} }
} }

@ -11,4 +11,5 @@ protocol IAuthService {
func login(login: String, password: String, completion : @escaping (Int)-> ()) func login(login: String, password: String, completion : @escaping (Int)-> ())
func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) func register(username: String, email: String, password: String, completion : @escaping (Int)-> ())
func refreshAuthentication() func refreshAuthentication()
func logout()
} }

@ -7,30 +7,23 @@
import Foundation import Foundation
import DependencyInjection import DependencyInjection
import ViewModel
import Model import Model
import Combine import Combine
class BetViewModel: ObservableObject { class BetViewModel: ObservableObject {
@Inject var manager: ManagerVM @Inject var manager: Manager
@Published private var internalBets: [Bet] = [] @Published private(set) var bets: [Bet] = []
var bets: [Bet] {
return internalBets
}
init() { init() {
getItems() getItems()
} }
func getItems() { func getItems() {
for bet in manager.bets { manager.getBets(withIndex: 0, withCount: 20) { bets in
print(bet.theme) self.bets = bets
} }
manager.$bets.assign(to: \.internalBets, on: self).store(in: &cancellables)
manager.getPublicBets()
} }
private var cancellables: Set<AnyCancellable> = [] private var cancellables: Set<AnyCancellable> = []

@ -8,11 +8,11 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
import DependencyInjection import DependencyInjection
import ViewModel import Model
class CreationBetViewModel: ObservableObject { class CreationBetViewModel: ObservableObject {
@Inject var manager: ManagerVM @Inject var manager: Manager
@Published var theme: String = "" @Published var theme: String = ""
@Published var description: String = "" @Published var description: String = ""
@Published var isPublic = true @Published var isPublic = true

@ -0,0 +1,44 @@
//
// DetailsViewModel.swift
// AllIn
//
// Created by Emre on 16/01/2024.
//
import Foundation
import SwiftUI
import DependencyInjection
import Model
class DetailsViewModel: ObservableObject {
@Inject var manager: Manager
var id: String
@Published var answer = 0
@Published var mise: String = ""
@Published var betDetail: BetDetail?
init(id: String) {
self.id = id
getItem(withId: id)
}
func getItem(withId id: String) {
manager.getBet(withId: id) { bet in
self.betDetail = bet
}
}
func addParticipate() {
if let stake = Int(mise) {
var rep: String = ""
if answer == 0 {
rep = "Yes"
} else {
rep = "No"
}
manager.addParticipation(withId: id, withAnswer: rep, andStake: stake)
}
}
}

@ -7,11 +7,11 @@
import Foundation import Foundation
import DependencyInjection import DependencyInjection
import ViewModel import Model
class FriendsViewModel: ObservableObject { class FriendsViewModel: ObservableObject {
@Inject var manager: ManagerVM @Inject var manager: Manager
init() { init() {
getItems() getItems()

@ -0,0 +1,24 @@
//
// HistoricBetViewModel.swift
// AllIn
//
// Created by Emre on 16/01/2024.
//
import Foundation
import SwiftUI
import DependencyInjection
import Model
class HistoricBetViewModel: ObservableObject {
@Inject var manager: Manager
init() {
getItems()
}
func getItems() {
}
}

@ -7,11 +7,11 @@
import Foundation import Foundation
import DependencyInjection import DependencyInjection
import ViewModel import Model
class RankingViewModel: ObservableObject { class RankingViewModel: ObservableObject {
@Inject var manager: ManagerVM @Inject var manager: Manager
init() { init() {
getItems() getItems()

@ -12,7 +12,7 @@ struct BetView: View {
@StateObject private var viewModel = BetViewModel() @StateObject private var viewModel = BetViewModel()
@Binding var showMenu: Bool @Binding var showMenu: Bool
@State private var showingSheet = false @State var showingSheet: Bool = false
var body: some View { var body: some View {
@ -31,9 +31,6 @@ struct BetView: View {
Button("Show Sheet") { Button("Show Sheet") {
showingSheet.toggle() showingSheet.toggle()
} }
.sheet(isPresented: $showingSheet) {
WinModal()
}
} }
.padding([.leading,.trailing],25) .padding([.leading,.trailing],25)
@ -57,16 +54,24 @@ struct BetView: View {
} }
} }
} }
.refreshable {
viewModel.getItems()
}
.sheet(isPresented: $showingSheet) {
WinModal()
}
Spacer() Spacer()
} }
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)
.background(AllInColors.backgroundColor) .background(AllInColors.backgroundColor)
} }
} }
struct BetView_Previews: PreviewProvider { struct BetView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
BetView(showMenu: .constant(false)) BetView(showMenu: .constant(false))
.preferredColorScheme(.dark) .preferredColorScheme(.light)
} }
} }

@ -0,0 +1,166 @@
import SwiftUI
import Model
struct DetailsView: View {
@Binding var isModalPresented: Bool
@Binding var isModalParticipated: Bool
@State var progressValue: Float = 0.2
var id: String
@StateObject private var viewModel: DetailsViewModel
var isFinished: Bool {
viewModel.betDetail?.finalAnswer == nil ? false : true
}
var isDisabled: Bool {
if let endRegisterDate = viewModel.betDetail?.bet.endRegisterDate {
let currentDate = Date()
switch currentDate.compare(endRegisterDate) {
case .orderedAscending:
return false
case .orderedDescending:
return true
case .orderedSame:
return true
}
} else {
return true
}
}
var StatusValues: (String, Color) {
if let endRegisterDate = viewModel.betDetail?.bet.endRegisterDate {
let currentDate = Date()
switch currentDate.compare(endRegisterDate) {
case .orderedAscending:
return ("En cours...", AllInColors.purpleAccentColor)
case .orderedDescending:
return ("En attente...",AllInColors.pink100)
case .orderedSame:
return ("Fin des inscriptions...",AllInColors.grey50Color)
}
} else {
return ("Statut indisponible", AllInColors.whiteColor)
}
}
init(isModalPresented: Binding<Bool>, isModalParticipated: Binding<Bool>, id: String) {
self._isModalPresented = isModalPresented
self._isModalParticipated = isModalParticipated
self.id = id
self._viewModel = StateObject(wrappedValue: DetailsViewModel(id: id))
}
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .bottom) {
VStack(alignment: .center) {
HStack{
Text(StatusValues.0)
.font(.system(size: 25))
.fontWeight(.bold).padding(.bottom, 10)
.foregroundStyle(Color.black)
.opacity(0.4)
Spacer()
Image("closeIcon")
.resizable()
.frame(maxWidth: 25, maxHeight: 25)
.onTapGesture {
isModalPresented = false
}
}
Spacer()
}
.padding(.horizontal, 15)
.background(StatusValues.1)
.transition(.slideInFromBottom(yOffset:0))
VStack(spacing: 0) {
VStack(alignment: .leading,spacing: 5){
HStack{
Spacer()
Text("proposé par " + (viewModel.betDetail?.bet.author.username ?? "Unknown").capitalized)
.font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color)
}
Text(viewModel.betDetail?.bet.theme ?? "Not loaded")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
Text(viewModel.betDetail?.bet.phrase ?? "Not loaded")
.font(.system(size: 20))
.fontWeight(.bold)
.padding(.bottom, 10)
HStack{
Text("Commence le")
.frame(maxWidth: 100)
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
TextCapsule(date: viewModel.betDetail?.bet.endRegisterDate ?? Date())
Spacer()
}.padding(.bottom, 10)
HStack{
Text("Fini le")
.frame(maxWidth: 100)
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
TextCapsule(date: viewModel.betDetail?.bet.endBetDate ?? Date())
Spacer()
}
}
.frame(width: .infinity)
.padding(.all,15).padding(.vertical, 10)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0)
if isFinished {
ResultBanner()
}
VStack(alignment: .leading, spacing: 5) {
BetLineLoading(participations: viewModel.betDetail?.participations ?? [])
.padding(.vertical,15)
Text("Liste des participants")
.font(.system(size: 18))
.foregroundStyle(AllInColors.grey100Color)
.fontWeight(.bold)
.padding(.bottom, 10)
ForEach(viewModel.betDetail?.participations ?? []) { (participation: Participation) in
ParticiationCell(participation: participation).padding(.horizontal, 10)
}
Spacer()
}
.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity)
.padding([.bottom,.trailing,.leading], 15)
.background(AllInColors.underComponentBackgroundColor)
.border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: geometry.size.height*0.98)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(15)
ParticipateButton(isOpen: $isModalPresented, isParticapatedOpen: $isModalParticipated, bet: viewModel.betDetail?.bet)
.padding(10)
}
.sheet(isPresented: $isModalParticipated) {
ParticipationModal(answer: $viewModel.answer, mise: $viewModel.mise, description: viewModel.betDetail?.bet.phrase ?? "Not loaded", participationAddedCallback: {
viewModel.addParticipate()
isModalParticipated.toggle()
})
.presentationDetents([.fraction(0.55)])
}
.edgesIgnoringSafeArea(.bottom)
}
}
}

@ -10,6 +10,7 @@ import SwiftUI
struct MainView: View { struct MainView: View {
@State var showMenu = false @State var showMenu = false
var page: String var page: String
var body: some View { var body: some View {
@ -58,6 +59,7 @@ struct MainView: View {
.frame(width: geometry.size.width*0.83) .frame(width: geometry.size.width*0.83)
.transition(.move(edge: .leading)) .transition(.move(edge: .leading))
} }
} }
.gesture(closeDrag) .gesture(closeDrag)
} }

@ -7,20 +7,28 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */; };
1209191A2B56DC6C00D0FA29 /* DropDownAnswerMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */; };
123590B42B51792000F7AEBD /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B32B51792000F7AEBD /* DetailsView.swift */; };
123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B52B5537E200F7AEBD /* ResultBanner.swift */; };
123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B72B5541BA00F7AEBD /* ParticipateButton.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 */; };
12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */; };
12C3704A2B5D5BD000CD9F0F /* ParticiationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370492B5D5BD000CD9F0F /* ParticiationCell.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 */; };
EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937D2B25C52E005D81E6 /* TopBar.swift */; }; EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937D2B25C52E005D81E6 /* TopBar.swift */; };
EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */; };
EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */; };
EC3077072B24CB840060E34D /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077062B24CB840060E34D /* SplashView.swift */; }; EC3077072B24CB840060E34D /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077062B24CB840060E34D /* SplashView.swift */; };
EC3077092B24CF7F0060E34D /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077082B24CF7F0060E34D /* Colors.swift */; }; EC3077092B24CF7F0060E34D /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077082B24CF7F0060E34D /* Colors.swift */; };
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 */; };
EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; }; EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; };
EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2D2B4EC04B00853949 /* ViewModel */; }; EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC60C5672B5A83FB00FFD6EF /* StubLib */; };
EC4F0D302B4EC05D00853949 /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2F2B4EC05D00853949 /* StubLib */; };
EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; }; EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; };
EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */; }; EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */; };
EC650A462B25D686003AFCAD /* RankingRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A452B25D686003AFCAD /* RankingRow.swift */; }; EC650A462B25D686003AFCAD /* RankingRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A452B25D686003AFCAD /* RankingRow.swift */; };
@ -96,15 +104,23 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
120919172B56D0AE00D0FA29 /* ParticipationModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipationModal.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>"; };
122278BB2B4BDEC300E632AA /* Sources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Sources; path = ../StubLib/Sources; 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>"; };
123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.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>"; };
12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetLineLoading.swift; sourceTree = "<group>"; };
12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticiationCell.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>"; };
EC01937D2B25C52E005D81E6 /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.swift; sourceTree = "<group>"; }; EC01937D2B25C52E005D81E6 /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.swift; sourceTree = "<group>"; };
EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsViewModel.swift; sourceTree = "<group>"; };
EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetViewModel.swift; sourceTree = "<group>"; };
EC3077062B24CB840060E34D /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = "<group>"; }; EC3077062B24CB840060E34D /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = "<group>"; };
EC3077082B24CF7F0060E34D /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; }; EC3077082B24CF7F0060E34D /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
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>"; };
@ -161,10 +177,9 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
EC4F0D302B4EC05D00853949 /* StubLib in Frameworks */, EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */,
EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */, EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */,
ECCD244A2B4DE8010071FA9E /* Api in Frameworks */, ECCD244A2B4DE8010071FA9E /* Api in Frameworks */,
EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -290,6 +305,7 @@
EC650A512B2794DD003AFCAD /* BetView.swift */, EC650A512B2794DD003AFCAD /* BetView.swift */,
EC7A882C2B28D8A1004F226A /* CreationBetView.swift */, EC7A882C2B28D8A1004F226A /* CreationBetView.swift */,
1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */, 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */,
123590B32B51792000F7AEBD /* DetailsView.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@ -316,6 +332,12 @@
ECA9D1C82B2D9ADA0076E0EC /* UserInfo.swift */, ECA9D1C82B2D9ADA0076E0EC /* UserInfo.swift */,
ECA9D1CA2B2DA2320076E0EC /* DropDownFriends.swift */, ECA9D1CA2B2DA2320076E0EC /* DropDownFriends.swift */,
1244EF612B4EC67000374ABF /* ReviewCard.swift */, 1244EF612B4EC67000374ABF /* ReviewCard.swift */,
123590B52B5537E200F7AEBD /* ResultBanner.swift */,
123590B72B5541BA00F7AEBD /* ParticipateButton.swift */,
120919172B56D0AE00D0FA29 /* ParticipationModal.swift */,
120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */,
12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */,
12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */,
); );
path = Components; path = Components;
sourceTree = "<group>"; sourceTree = "<group>";
@ -323,7 +345,6 @@
ECB3572D2B3CA3BD00045D41 /* Frameworks */ = { ECB3572D2B3CA3BD00045D41 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
122278BB2B4BDEC300E632AA /* Sources */,
122278B92B4BDE9500E632AA /* Package.swift */, 122278B92B4BDE9500E632AA /* Package.swift */,
122278B72B4BDE1100E632AA /* DependencyInjection.framework */, 122278B72B4BDE1100E632AA /* DependencyInjection.framework */,
ECB357302B3CA69300045D41 /* DependencyInjection.framework */, ECB357302B3CA69300045D41 /* DependencyInjection.framework */,
@ -341,6 +362,8 @@
ECB26A162B4073F100FE06B3 /* CreationBetViewModel.swift */, ECB26A162B4073F100FE06B3 /* CreationBetViewModel.swift */,
ECB26A182B40744F00FE06B3 /* RankingViewModel.swift */, ECB26A182B40744F00FE06B3 /* RankingViewModel.swift */,
ECB26A1A2B40746C00FE06B3 /* FriendsViewModel.swift */, ECB26A1A2B40746C00FE06B3 /* FriendsViewModel.swift */,
EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */,
EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */,
); );
path = ViewModels; path = ViewModels;
sourceTree = "<group>"; sourceTree = "<group>";
@ -365,8 +388,7 @@
packageProductDependencies = ( packageProductDependencies = (
ECB357342B3E13A400045D41 /* Model */, ECB357342B3E13A400045D41 /* Model */,
ECCD24492B4DE8010071FA9E /* Api */, ECCD24492B4DE8010071FA9E /* Api */,
EC4F0D2D2B4EC04B00853949 /* ViewModel */, EC60C5672B5A83FB00FFD6EF /* StubLib */,
EC4F0D2F2B4EC05D00853949 /* StubLib */,
); );
productName = AllIn; productName = AllIn;
productReference = EC6B96982B24B4CC00FC1C58 /* AllIn.app */; productReference = EC6B96982B24B4CC00FC1C58 /* AllIn.app */;
@ -492,10 +514,12 @@
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 */,
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 */,
ECB26A192B40744F00FE06B3 /* RankingViewModel.swift in Sources */, ECB26A192B40744F00FE06B3 /* RankingViewModel.swift in Sources */,
EC650A502B2793D5003AFCAD /* TextCapsule.swift in Sources */, EC650A502B2793D5003AFCAD /* TextCapsule.swift in Sources */,
EC650A482B25DCFF003AFCAD /* UsersPreview.swift in Sources */, EC650A482B25DCFF003AFCAD /* UsersPreview.swift in Sources */,
@ -518,16 +542,23 @@
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 /* ParticiationCell.swift in Sources */,
123590B82B5541BA00F7AEBD /* ParticipateButton.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 */,
1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */, 1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */,
EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */, EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */,
EC650A562B279D68003AFCAD /* WinModal.swift in Sources */, EC650A562B279D68003AFCAD /* WinModal.swift in Sources */,
EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */, EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */,
123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */,
EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */,
EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */, EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */,
12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */,
EC650A542B279545003AFCAD /* ChoiceCapsule.swift in Sources */, EC650A542B279545003AFCAD /* ChoiceCapsule.swift in Sources */,
ECB7BC6C2B2F43EE002A6654 /* AppState.swift in Sources */, ECB7BC6C2B2F43EE002A6654 /* AppState.swift in Sources */,
ECA9D1C92B2D9ADA0076E0EC /* UserInfo.swift in Sources */, ECA9D1C92B2D9ADA0076E0EC /* UserInfo.swift in Sources */,
1209191A2B56DC6C00D0FA29 /* DropDownAnswerMenu.swift in Sources */,
EC650A582B279D9D003AFCAD /* RecapBetCard.swift in Sources */, EC650A582B279D9D003AFCAD /* RecapBetCard.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -857,11 +888,7 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
EC4F0D2D2B4EC04B00853949 /* ViewModel */ = { EC60C5672B5A83FB00FFD6EF /* StubLib */ = {
isa = XCSwiftPackageProductDependency;
productName = ViewModel;
};
EC4F0D2F2B4EC05D00853949 /* StubLib */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = StubLib; productName = StubLib;
}; };

@ -10,7 +10,11 @@ import Model
public struct BetApiManager: BetDataManager { public struct BetApiManager: BetDataManager {
public init() { } public let token: String
public init(withUserToken token: String) {
self.token = token
}
public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
let url = URL(string: allInApi + "bets/gets")! let url = URL(string: allInApi + "bets/gets")!
@ -27,9 +31,8 @@ public struct BetApiManager: BetDataManager {
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 {
if let bet = FactoryApiBet().toModel(from: json) { if let bet = FactoryApiBet().toBet(from: json) {
bets.append(bet) bets.append(bet)
print(bet.theme)
} }
} }
print(httpResponse.statusCode) print(httpResponse.statusCode)
@ -46,4 +49,31 @@ public struct BetApiManager: BetDataManager {
return [] return []
} }
public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) {
let url = URL(string: allInApi + "betdetail/get/" + id)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print ("ALLIN : get bet with id :" + id)
do {
if let httpResponse = response as? HTTPURLResponse, let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
if let betDetail = FactoryApiBet().toBetDetail(from: json) {
completion(betDetail)
}
print(httpResponse.statusCode)
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
}
} }

@ -10,23 +10,37 @@ import Model
public class FactoryApiBet: FactoryBet { public class FactoryApiBet: FactoryBet {
func formatZonedDateTime(dateTime: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
formatter.timeZone = TimeZone.current
return formatter.string(from: dateTime)
}
public func toResponse(bet: Bet) -> [String: Any] { public func toResponse(bet: Bet) -> [String: Any] {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let json: [String: Any] = [ let json: [String: Any] = [
"theme": bet.theme, "theme": bet.theme,
"sentenceBet": bet.phrase, "sentenceBet": bet.phrase,
"endRegistration": dateFormatter.string(from: bet.endRegisterDate), "endRegistration": formatZonedDateTime(dateTime: bet.endRegisterDate),
"endBet": dateFormatter.string(from: bet.endBetDate), "endBet": formatZonedDateTime(dateTime: bet.endBetDate),
"isPrivate": String(bet.isPublic), "isPrivate": String(bet.isPublic),
"response": [], "response": ["Yes","No"],
] ]
return json return json
} }
public func toModel(from json: [String: Any]) -> Bet? { public func fromJsonDateString(_ dateString: String) -> Date? {
guard let theme = json["theme"] as? String, let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let date = formatter.date(from: dateString)
return date
}
public func toBet(from json: [String: Any]) -> Bet? {
guard let id = json["id"] as? String,
let theme = json["theme"] as? String,
let phrase = json["sentenceBet"] as? String, let phrase = json["sentenceBet"] as? String,
let endRegisterDateString = json["endRegistration"] as? String, let endRegisterDateString = json["endRegistration"] as? String,
let endBetDateString = json["endBet"] as? String, let endBetDateString = json["endBet"] as? String,
@ -35,28 +49,55 @@ public class FactoryApiBet: FactoryBet {
return nil return nil
} }
let dateFormatter = DateFormatter() guard let endRegisterDate = fromJsonDateString(endRegisterDateString),
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" let endBetDate = fromJsonDateString(endBetDateString) else {
guard let endRegisterDate = dateFormatter.date(from: endRegisterDateString),
let endBetDate = dateFormatter.date(from: endBetDateString) else {
return nil return nil
} }
return toModel(theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, creator: User(username: createdBy, email: createdBy, nbCoins: 0, friends: []), type: 0) return toBet(id: id, theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, status: .FINISHED, creator: User(username: createdBy, email: createdBy, nbCoins: 0, friends: []), type: 0)
} }
public func toModel(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet { public func toBet(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: User, type: Int) -> Bet {
switch type { switch type {
case 0: case 0:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) return BinaryBet(id: id, 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, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "") return MatchBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "")
case 2: case 2:
return CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) return CustomBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
default: default:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) return BinaryBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
}
}
public func toBetDetail(from json: [String: Any]) -> BetDetail? {
guard let betJson = json["bet"] as? [String: Any],
let bet = self.toBet(from: betJson) else {
return nil
}
var participations: [Participation] = []
if let participationsJson = json["participations"] as? [[String: Any]], !participationsJson.isEmpty {
for participationJson in participationsJson {
if let participation = self.toParticipate(from: participationJson) {
participations.append(participation)
}
}
}
return BetDetail(bet: bet, answers: [], participations: participations)
}
public func toParticipate(from json: [String: Any]) -> Participation? {
guard let id = json["id"] as? String,
let betId = json["betId"] as? String,
let username = json["username"] as? String,
let answer = json["answer"] as? String,
let stake = json["stake"] as? Int else {
return nil
} }
return Participation(id: id, stake: stake, date: Date(), response: answer, user: User(username: username, email: "Email", nbCoins: 0, friends: []), betId: betId)
} }
} }

@ -8,7 +8,7 @@
import Foundation import Foundation
import Model import Model
let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api" let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/"
public struct UserApiManager: UserDataManager { public struct UserApiManager: UserDataManager {
@ -24,22 +24,18 @@ public struct UserApiManager: UserDataManager {
public func addBet(bet: Bet) { public func addBet(bet: Bet) {
print(token)
let url = URL(string: allInApi + "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")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var json = FactoryApiBet().toResponse(bet: bet) let json = FactoryApiBet().toResponse(bet: bet)
json["createdBy"] = token
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){ if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){
URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in
print ("ALLIN : Add BET") print ("ALLIN : Add BET")
if let httpResponse = response as? HTTPURLResponse { if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 201 {
}
print(httpResponse.statusCode) print(httpResponse.statusCode)
} }
}.resume() }.resume()
@ -49,4 +45,31 @@ public struct UserApiManager: UserDataManager {
public func getFriends() -> [User] { public func getFriends() -> [User] {
fatalError("Not implemented yet") fatalError("Not implemented yet")
} }
public func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
fatalError("Not implemented yet")
}
public func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int) {
let url = URL(string: allInApi + "participations/add")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let json: [String: Any] = [
"betId": id,
"answer": answer,
"stake": stake
]
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){
URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in
print ("ALLIN : Add Participation")
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
}
}.resume()
}
}
} }

@ -0,0 +1,43 @@
//
// AnswerDetail.swift
//
//
// Created by Emre on 19/01/2024.
//
import Foundation
/// A class representing detailed information about a specific answer option for a bet.
public class AnswerDetail: ObservableObject {
/// The response or outcome associated with this answer.
public private(set) var response: String
/// The total amount of stakes placed on this answer.
public private(set) var totalStakes: Int
/// The total number of participants who selected this answer.
public private(set) var totalParticipants: Int
/// The highest stake placed on this answer.
public private(set) var highestStake: Int
/// The odds associated with this answer.
public private(set) var odds: Float
/// Custom Constructor
///
/// - Parameters:
/// - response: The response or outcome associated with this answer.
/// - totalStakes: The total amount of stakes placed on this answer.
/// - totalParticipants: The total number of participants who selected this answer.
/// - highestStake: The highest stake placed on this answer.
/// - odds: The odds associated with this answer.
public init(response: String, totalStakes: Int, totalParticipants: Int, highestStake: Int, odds: Float) {
self.response = response
self.totalStakes = totalStakes
self.totalParticipants = totalParticipants
self.highestStake = highestStake
self.odds = odds
}
}

@ -11,7 +11,7 @@ import Foundation
public class Bet: ObservableObject, Identifiable { public class Bet: ObservableObject, Identifiable {
/// The id for the bet. /// The id for the bet.
public var id = UUID() public private(set) var id: String
/// The theme or topic of the bet. /// The theme or topic of the bet.
public private(set) var theme: String public private(set) var theme: String
@ -25,12 +25,11 @@ public class Bet: ObservableObject, Identifiable {
/// The deadline for the actual betting to take place. /// The deadline for the actual betting to take place.
public private(set) var endBetDate: Date public private(set) var endBetDate: Date
/// The total stakes or amount involved in the bet.
public private(set) var totalStakes: Int
/// Indicates whether the bet is public or private. /// Indicates whether the bet is public or private.
public private(set) var isPublic: Bool public private(set) var isPublic: Bool
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: [User] public private(set) var invited: [User]
@ -40,27 +39,57 @@ public class Bet: ObservableObject, Identifiable {
/// List of users who have registered for the bet. /// List of users who have registered for the bet.
public private(set) var registered: [User] public private(set) var registered: [User]
/// Custom Constructor /// Custom Constructor
/// ///
/// - Parameters: /// - Parameters:
/// - id: The id for the bet.
/// - theme: The theme or topic of the bet. /// - theme: The theme or topic of the bet.
/// - phrase: The specific phrase or question related to the bet. /// - phrase: The specific phrase or question related to the bet.
/// - endRegisterDate: The deadline for users to register for the bet. /// - endRegisterDate: The deadline for users to register for the bet.
/// - endBetDate: The deadline for the actual betting to take place. /// - endBetDate: The deadline for the actual betting to take place.
/// - totalStakes: The total stakes or amount involved in the bet.
/// - isPublic: Indicates whether the bet is public or private. /// - isPublic: Indicates whether the bet is public or private.
/// - 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.
/// - registered: List of users who have registered for the bet. /// - registered: List of users who have registered for the bet.
public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User]) { public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: User, registered: [User]) {
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.totalStakes = totalStakes
self.isPublic = isPublic self.isPublic = isPublic
self.status = status
self.invited = invited self.invited = invited
self.author = author self.author = author
self.registered = registered self.registered = registered
} }
/// Custom Constructor without Id
///
/// - Parameters:
/// - theme: The theme or topic of the bet.
/// - phrase: The specific phrase or question related to the bet.
/// - endRegisterDate: The deadline for users to register for the bet.
/// - endBetDate: The deadline for the actual betting to take place.
/// - isPublic: Indicates whether the bet is public or private.
/// - invited: List of users who are invited to participate in the bet.
/// - author: The user who created the bet.
/// - 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: User, registered: [User]) {
self.id = UUID().uuidString
self.theme = theme
self.phrase = phrase
self.endRegisterDate = endRegisterDate
self.endBetDate = endBetDate
self.isPublic = isPublic
self.status = status
self.invited = invited
self.author = author
self.registered = registered
}
public func addRegistered(newUser: User){
self.registered.append(newUser)
}
} }

@ -10,4 +10,5 @@ import Foundation
public protocol BetDataManager { public protocol BetDataManager {
func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void)
func getUsers(username: String) -> [User] func getUsers(username: String) -> [User]
func getBet(withId id: String, completion: @escaping (BetDetail) -> Void)
} }

@ -0,0 +1,51 @@
//
// BetDetail.swift
//
//
// Created by Emre on 19/01/2024.
//
import Foundation
/// A class representing detailed information about a specific bet, including answers and user participations.
public class BetDetail: ObservableObject {
/// The main bet information.
public private(set) var bet: Bet
/// Details about the answers available for the bet.
public private(set) var answers: [AnswerDetail]
/// List of user participations in the bet.
public private(set) var participations: [Participation]
public private(set) var finalAnswer: String?
/// Custom Constructor
///
/// - Parameters:
/// - bet: The main bet information.
/// - answers: Details about the answers available for the bet.
/// - participations: List of user participations in the bet.
/// - userParticipation: The user's own participation in the bet.
public init(bet: Bet, answers: [AnswerDetail], participations: [Participation], finalAnswer: String? = nil) {
self.bet = bet
self.answers = answers
self.participations = participations
self.finalAnswer = finalAnswer
}
public func updateFinalAnswer(newFinalAnswer: String) {
self.finalAnswer = newFinalAnswer
}
public func addParticipation(newParticipation: Participation){
if !self.bet.registered.contains(where: { existingUser in
return existingUser.email == newParticipation.user.email
}) {
self.bet.addRegistered(newUser: newParticipation.user)
}
self.participations.append(newParticipation)
}
}

@ -10,19 +10,4 @@ import Foundation
/// A subclass of Bet that represents a binary bet, where participants make a choice between two possible outcomes. /// A subclass of Bet that represents a binary bet, where participants make a choice between two possible outcomes.
public class BinaryBet: Bet { public class BinaryBet: Bet {
// Custom Constructor
///
/// - Parameters:
/// - theme: The theme or topic of the binary bet.
/// - phrase: The specific phrase or question related to the binary bet.
/// - endRegisterDate: The deadline for users to register for the binary bet.
/// - endBetDate: The deadline for the actual betting to take place for the binary bet.
/// - totalStakes: The total stakes or amount involved in the binary bet.
/// - isPublic: Indicates whether the binary bet is public or private.
/// - invited: List of users who are invited to participate in the binary bet.
/// - author: The user who created the binary bet.
/// - registered: List of users who have registered for the binary bet.
public override init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User]) {
super.init(theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, totalStakes: totalStakes, isPublic: isPublic, invited: invited, author: author, registered: registered)
}
} }

@ -1,33 +0,0 @@
//
// BinaryParticipation.swift
//
//
// Created by Emre on 28/12/2023.
//
import Foundation
/// Enum to represent the possible answers for a binary participation.
public enum YesNo {
case yes
case no
}
/// A subclass of Participation that represents a binary participation (yes/no) in a bet.
public class BinaryParticipation: Participation {
/// The answer for the binary participation (yes or no).
public var answer: YesNo
/// Custom Constructor
///
/// - Parameters:
/// - coinAmount: The amount of coins involved in the binary participation.
/// - date: The date and time when the binary participation occurred.
/// - user: The user who participated in the binary bet.
/// - bet: The binary bet in which the user participated.
/// - answer: The answer for the binary participation (yes or no).
public init(coinAmount: Int, date: Date, user: User, bet: Bet, answer: YesNo) {
self.answer = answer
super.init(coinAmount: coinAmount, date: date, user: user, bet: bet)
}
}

@ -1,27 +0,0 @@
//
// CustomParticipation.swift
//
//
// Created by Emre on 28/12/2023.
//
import Foundation
/// A subclass of Participation that represents a custom participation in a bet.
public class CustomParticipation: Participation {
/// The user's response to the custom bet.
public var answer: CustomBetResponse
/// Custom Constructor
///
/// - Parameters:
/// - coinAmount: The amount of coins involved in the custom participation.
/// - date: The date and time when the custom participation occurred.
/// - user: The user who participated in the custom bet.
/// - bet: The custom bet in which the user participated.
/// - answer: The user's response to the custom bet.
public init(coinAmount: Int, date: Date, user: User, bet: Bet, answer: CustomBetResponse) {
self.answer = answer
super.init(coinAmount: coinAmount, date: date, user: user, bet: bet)
}
}

@ -9,6 +9,7 @@ import Foundation
public protocol FactoryBet { public protocol FactoryBet {
func toResponse(bet: Bet) -> [String: Any] func toResponse(bet: Bet) -> [String: Any]
func toModel(from json: [String: Any]) -> Bet? func toBet(from json: [String: Any]) -> Bet?
func toModel(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet func toBetDetail(from json: [String: Any]) -> BetDetail?
func toBet(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: User, type: Int) -> Bet
} }

@ -0,0 +1,12 @@
//
// File.swift
//
//
// Created by étudiant on 23/01/2024.
//
import Foundation
public enum BetStatus {
case WAITING, IN_PROGRESS, FINISHED
}

@ -16,8 +16,8 @@ public struct Manager {
self.userDataManager = userDataManager self.userDataManager = userDataManager
} }
public func addBet(bet: Bet) { public func addBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User) {
userDataManager.addBet(bet: bet) userDataManager.addBet(bet: BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: .IN_PROGRESS, invited: [], author: creator, registered: []))
} }
public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
@ -25,4 +25,20 @@ public struct Manager {
completion(bets) completion(bets)
} }
} }
public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) {
betDataManager.getBet(withId: id) { bet in
completion(bet)
}
}
public func getHistoricBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
userDataManager.getOldBets(withIndex: index, withCount: count) { bets in
completion(bets)
}
}
public func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int) {
userDataManager.addParticipation(withId: id, withAnswer: answer, andStake: stake)
}
} }

@ -18,6 +18,7 @@ public class MatchBet: Bet {
/// Custom Constructor /// Custom Constructor
/// ///
/// - Parameters: /// - Parameters:
/// - id: The id for the bet.
/// - theme: The theme or topic of the match bet. /// - theme: The theme or topic of the match bet.
/// - phrase: The specific phrase or question related to the match bet. /// - phrase: The specific phrase or question related to the match bet.
/// - endRegisterDate: The deadline for users to register for the match bet. /// - endRegisterDate: The deadline for users to register for the match bet.
@ -29,9 +30,29 @@ public class MatchBet: Bet {
/// - registered: List of users who have registered for 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, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User], nameTeam1: String, nameTeam2: String) { public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: User, 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, totalStakes: totalStakes, isPublic: isPublic, invited: invited, author: author, registered: registered) 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
///
/// - Parameters:
/// - theme: The theme or topic of the match bet.
/// - phrase: The specific phrase or question related to the match bet.
/// - endRegisterDate: The deadline for users to register for the match bet.
/// - endBetDate: The deadline for the actual betting to take place for the match bet.
/// - totalStakes: The total stakes or amount involved in the match bet.
/// - isPublic: Indicates whether the match bet is public or private.
/// - invited: List of users who are invited to participate in 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.
/// - nameTeam2: The name of the second team involved in the match.
public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: User, registered: [User], nameTeam1: String, nameTeam2: String) {
self.nameTeam1 = nameTeam1
self.nameTeam2 = nameTeam2
super.init(theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPublic: isPublic, status: status, invited: invited, author: author, registered: registered)
} }
} }

@ -1,32 +0,0 @@
//
// MatchParticipation.swift
//
//
// Created by Emre on 28/12/2023.
//
import Foundation
/// A subclass of Participation that represents a user's participation in a match bet.
public class MatchParticipation: Participation {
/// The points earned by the user for the first team in the match.
public var pointsTeam1: Int
/// The points earned by the user for the second team in the match.
public var pointsTeam2: Int
/// Custom Constructor
///
/// - Parameters:
/// - coinAmount: The amount of coins involved in the match participation.
/// - date: The date and time when the match participation occurred.
/// - user: The user who participated in the match bet.
/// - bet: The match bet in which the user participated.
/// - pointsTeam1: The points earned by the user for the first team in the match.
/// - pointsTeam2: The points earned by the user for the second team in the match.
public init(coinAmount: Int, date: Date, user: User, bet: Bet, pointsTeam1: Int, pointsTeam2: Int) {
self.pointsTeam1 = pointsTeam1
self.pointsTeam2 = pointsTeam2
super.init(coinAmount: coinAmount, date: date, user: user, bet: bet)
}
}

@ -7,31 +7,39 @@
import Foundation import Foundation
/// A class representing a user's participation in a bet, including the amount of coins, date, user, and the associated bet. /// A class representing a user's participation in a bet.
public class Participation: ObservableObject { public class Participation: ObservableObject, Identifiable {
/// The amount of coins involved in the participation.
var coinAmount: Int public let id: String
/// The amount of stake in the bet.
public private(set) var stake: Int
/// The date and time when the participation occurred. /// The date and time when the participation occurred.
var date: Date public private(set) var date: Date
/// The response or outcome of the participation.
public private(set) var response: String
/// The user who participated in the bet. /// The user who participated in the bet.
var user: User public private(set) var user: User
/// The bet in which the user participated. /// The unique identifier of the bet.
var bet: Bet public private(set) var betId: String
/// Custom Constructor /// Custom Constructor
/// ///
/// - Parameters: /// - Parameters:
/// - coinAmount: The amount of coins involved in the participation. /// - stake: The amount of stake in the bet.
/// - date: The date and time when the participation occurred. /// - date: The date and time when the participation occurred.
/// - response: The response or outcome of the participation.
/// - user: The user who participated in the bet. /// - user: The user who participated in the bet.
/// - bet: The bet in which the user participated. /// - betId: The unique identifier of the bet.
init(coinAmount: Int, date: Date, user: User, bet: Bet) { public init(id: String, stake: Int, date: Date, response: String, user: User, betId: String) {
self.coinAmount = coinAmount self.id = id
self.stake = stake
self.date = date self.date = date
self.response = response
self.user = user self.user = user
self.bet = bet self.betId = betId
} }
} }

@ -8,10 +8,10 @@
import Foundation import Foundation
public struct User { public struct User {
public var username: String public private(set) var username: String
public var email: String public private(set) var email: String
public var nbCoins: Int public private(set) var nbCoins: Int
public var friends: [User] public private(set) var friends: [User]
public init(username: String, email: String, nbCoins: Int, friends: [User]) { public init(username: String, email: String, nbCoins: Int, friends: [User]) {
self.username = username self.username = username

@ -11,4 +11,6 @@ public protocol UserDataManager {
func getBets(withIndex index: Int, withCount count: Int) -> [Bet] func getBets(withIndex index: Int, withCount count: Int) -> [Bet]
func addBet(bet: Bet) func addBet(bet: Bet)
func getFriends() -> [User] func getFriends() -> [User]
func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void)
func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int)
} }

@ -17,9 +17,15 @@ public struct BetStubManager: BetDataManager {
} }
public func getUsers(username: String) -> [User] { public func getUsers(username: String) -> [User] {
return Stub.shared.users return []
.filter { user in }
user.username.contains(username)
public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) {
if let betDetail = Stub.shared.betsDetail.first(where: { $0.bet.id == id }) {
completion(betDetail)
} else {
print("BetDetail with ID \(id) not found.")
} }
} }

@ -12,6 +12,7 @@ struct Stub {
static var shared = Stub() static var shared = Stub()
public var bets: [Bet] = [] public var bets: [Bet] = []
public var betsDetail: [BetDetail] = []
public var users: [User] = [] public var users: [User] = []
public init() { public init() {
@ -34,10 +35,10 @@ struct Stub {
let bet1 = BinaryBet( let bet1 = BinaryBet(
theme: "Football - Finale de la Ligue des Champions", theme: "Football - Finale de la Ligue des Champions",
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),
totalStakes: 100,
isPublic: true, isPublic: true,
status: .IN_PROGRESS,
invited: [], invited: [],
author: user1, author: user1,
registered: [user2] registered: [user2]
@ -49,8 +50,8 @@ 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),
totalStakes: 150,
isPublic: false, isPublic: false,
status: .IN_PROGRESS,
invited: [user3], invited: [user3],
author: user1, author: user1,
registered: [user2] registered: [user2]
@ -62,8 +63,8 @@ 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),
totalStakes: 75,
isPublic: true, isPublic: true,
status: .FINISHED,
invited: [], invited: [],
author: user1, author: user1,
registered: [user2, user1, user3] registered: [user2, user1, user3]
@ -75,17 +76,28 @@ 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),
totalStakes: 120,
isPublic: false, isPublic: false,
status: .FINISHED,
invited: [user1], invited: [user1],
author: user2, author: user2,
registered: [user3] registered: [user3]
) )
self.bets.append(bet4) self.bets.append(bet4)
for bet in bets {
let betDetail = BetDetail(bet: bet, answers: [], participations: [])
self.betsDetail.append(betDetail)
}
self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 120, date: Date(), response: "OUI", user: user1, betId: "1"))
self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 20, date: Date(), response: "NON", user: user2, betId: "2"))
self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 320, date: Date(), response: "OUI", user: user3, betId: "3"))
self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 320, date: Date(), response: "OUI", user: user3, betId: "3"))
} }
public mutating func add(bet: Bet) { public mutating func add(bet: Bet) {
self.bets.append(bet) let newBetDetail = BetDetail(bet: bet, answers: [], participations: [], finalAnswer: "test")
self.betsDetail.append(newBetDetail)
} }
} }

@ -1,38 +0,0 @@
//
// UserStubManager.swift
//
//
// Created by Emre on 31/12/2023.
//
import Foundation
import Model
public struct UserStubManager: UserDataManager {
private var username: String
public init(username: String) {
self.username = username
}
public func getBets(withIndex index: Int, withCount count: Int) -> [Bet] {
return Stub.shared.bets.filter { bet in
bet.registered.contains { user in
user.username == self.username
}
}
}
public func addBet(bet: Bet) {
Stub.shared.add(bet: bet)
}
public func getFriends() -> [User] {
return Stub.shared.users.filter { user in
user.friends.contains { friend in
friend.username == self.username
}
}
}
}

@ -1,29 +0,0 @@
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "ViewModel",
platforms: [
.iOS(.v13)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "ViewModel",
targets: ["ViewModel"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(name: "Model", path: "../Model")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "ViewModel",
dependencies: ["Model"]),
]
)

@ -1,3 +0,0 @@
# ViewModel
A description of this package.

@ -1,29 +0,0 @@
//
// ManagerVM.swift
//
//
// Created by Emre on 30/12/2023.
//
import Foundation
import Model
public class ManagerVM: ObservableObject {
@Published var model: Manager
@Published public var bets: [Bet] = []
public init(withModel model: Manager) {
self.model = model
}
public func getPublicBets() {
model.getBets(withIndex: 0, withCount: 20) { bets in
self.bets = bets
}
}
public func addBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User) {
model.addBet(bet: BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []))
}
}
Loading…
Cancel
Save