diff --git a/Sources/AllIn.xcworkspace/contents.xcworkspacedata b/Sources/AllIn.xcworkspace/contents.xcworkspacedata index 50d956e..74c136d 100644 --- a/Sources/AllIn.xcworkspace/contents.xcworkspacedata +++ b/Sources/AllIn.xcworkspace/contents.xcworkspacedata @@ -2,16 +2,13 @@ - - + location = "group:StubLib"> + location = "group:Api"> + location = "group:AllInApp/AllInApp.xcodeproj"> diff --git a/Sources/AllInApp/AllIn/AllInApp.swift b/Sources/AllInApp/AllIn/AllInApp.swift index f79fa97..374a309 100644 --- a/Sources/AllInApp/AllIn/AllInApp.swift +++ b/Sources/AllInApp/AllIn/AllInApp.swift @@ -8,7 +8,6 @@ import SwiftUI import DependencyInjection import Model -import ViewModel @main struct AllInApp: App { diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BlackTitleColor.colorset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/BlackTitleColor.colorset/Contents.json new file mode 100644 index 0000000..0e54db2 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/BlackTitleColor.colorset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/Bleue200.colorset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/Bleue200.colorset/Contents.json new file mode 100644 index 0000000..0286b3d --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/Bleue200.colorset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BleueBadge.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/BleueBadge.imageset/Contents.json new file mode 100644 index 0000000..446d6be --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/BleueBadge.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BleueBadge.imageset/Vector.png b/Sources/AllInApp/AllIn/Assets.xcassets/BleueBadge.imageset/Vector.png new file mode 100644 index 0000000..2114e9d Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/BleueBadge.imageset/Vector.png differ diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BleueCoin.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/BleueCoin.imageset/Contents.json new file mode 100644 index 0000000..67a98bf --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/BleueCoin.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BleueCoin.imageset/Group 107 (1).png b/Sources/AllInApp/AllIn/Assets.xcassets/BleueCoin.imageset/Group 107 (1).png new file mode 100644 index 0000000..d982a56 Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/BleueCoin.imageset/Group 107 (1).png differ diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BleuePersonIcon.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/BleuePersonIcon.imageset/Contents.json new file mode 100644 index 0000000..af28cdf --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/BleuePersonIcon.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BleuePersonIcon.imageset/Group 179.png b/Sources/AllInApp/AllIn/Assets.xcassets/BleuePersonIcon.imageset/Group 179.png new file mode 100644 index 0000000..f8c171f Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/BleuePersonIcon.imageset/Group 179.png differ diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BleueTrophyIcon.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/BleueTrophyIcon.imageset/Contents.json new file mode 100644 index 0000000..329d213 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/BleueTrophyIcon.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BleueTrophyIcon.imageset/Group 210.png b/Sources/AllInApp/AllIn/Assets.xcassets/BleueTrophyIcon.imageset/Group 210.png new file mode 100644 index 0000000..97f9e72 Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/BleueTrophyIcon.imageset/Group 210.png differ diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BlueAllCoinIcon.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/BlueAllCoinIcon.imageset/Contents.json new file mode 100644 index 0000000..67a98bf --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/BlueAllCoinIcon.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/BlueAllCoinIcon.imageset/Group 107 (1).png b/Sources/AllInApp/AllIn/Assets.xcassets/BlueAllCoinIcon.imageset/Group 107 (1).png new file mode 100644 index 0000000..d982a56 Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/BlueAllCoinIcon.imageset/Group 107 (1).png differ diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/Grey100Color.colorset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/Grey100Color.colorset/Contents.json index cf9f629..c165084 100644 --- a/Sources/AllInApp/AllIn/Assets.xcassets/Grey100Color.colorset/Contents.json +++ b/Sources/AllInApp/AllIn/Assets.xcassets/Grey100Color.colorset/Contents.json @@ -20,7 +20,7 @@ } ], "color" : { - "color-space" : "srgb", + "color-space" : "display-p3", "components" : { "alpha" : "1.000", "blue" : "0x45", diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/Image.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/Image.imageset/Contents.json new file mode 100644 index 0000000..a19a549 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/Image.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/LoadingHeart.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/LoadingHeart.imageset/Contents.json new file mode 100644 index 0000000..063d4f3 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/LoadingHeart.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/LoadingHeart.imageset/Group 280.png b/Sources/AllInApp/AllIn/Assets.xcassets/LoadingHeart.imageset/Group 280.png new file mode 100644 index 0000000..956a97a Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/LoadingHeart.imageset/Group 280.png differ diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/Pink100.colorset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/Pink100.colorset/Contents.json new file mode 100644 index 0000000..3492dff --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/Pink100.colorset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/Pink200.colorset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/Pink200.colorset/Contents.json new file mode 100644 index 0000000..c0ba743 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/Pink200.colorset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/PinkBadge.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/PinkBadge.imageset/Contents.json new file mode 100644 index 0000000..b0b4a62 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/PinkBadge.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/PinkBadge.imageset/Vector (1).png b/Sources/AllInApp/AllIn/Assets.xcassets/PinkBadge.imageset/Vector (1).png new file mode 100644 index 0000000..c6c1d71 Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/PinkBadge.imageset/Vector (1).png differ diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/Purple200.colorset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/Purple200.colorset/Contents.json new file mode 100644 index 0000000..8beecea --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/Purple200.colorset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/PurpleAllCoin.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/PurpleAllCoin.imageset/Contents.json new file mode 100644 index 0000000..1904c47 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/PurpleAllCoin.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/PurpleAllCoin.imageset/Vector (3).png b/Sources/AllInApp/AllIn/Assets.xcassets/PurpleAllCoin.imageset/Vector (3).png new file mode 100644 index 0000000..2ae155a Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/PurpleAllCoin.imageset/Vector (3).png differ diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/WinBannerBackground.colorset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/WinBannerBackground.colorset/Contents.json new file mode 100644 index 0000000..9e04041 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/WinBannerBackground.colorset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Contents.json new file mode 100644 index 0000000..4250f63 --- /dev/null +++ b/Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Contents.json @@ -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 + } +} diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Exclude (1).png b/Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Exclude (1).png new file mode 100644 index 0000000..7103253 Binary files /dev/null and b/Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Exclude (1).png differ diff --git a/Sources/AllInApp/AllIn/Components/AllcoinsCounter.swift b/Sources/AllInApp/AllIn/Components/AllcoinsCounter.swift index eb21bd1..8d2a444 100644 --- a/Sources/AllInApp/AllIn/Components/AllcoinsCounter.swift +++ b/Sources/AllInApp/AllIn/Components/AllcoinsCounter.swift @@ -8,6 +8,8 @@ import SwiftUI struct AllcoinsCounter: View { + var backgroundColor: Color = .white + var foregroundColor: Color = AllInColors.primaryColor var body: some View { HStack(alignment: .center) { Image("allcoinIcon") @@ -15,10 +17,10 @@ struct AllcoinsCounter: View { .frame(width: 17, height: 17, alignment: .leading) Text(String(AppStateContainer.shared.user?.nbCoins ?? 0)) .fontWeight(.black) - .foregroundColor(AllInColors.primaryColor) + .foregroundColor(foregroundColor) } .frame(width: 90, height: 40) - .background(Color.white) + .background(backgroundColor) .cornerRadius(9999, corners: [.topLeft, .bottomLeft]) } diff --git a/Sources/AllInApp/AllIn/Components/BetCard.swift b/Sources/AllInApp/AllIn/Components/BetCard.swift index 9a37c5f..4e4073d 100644 --- a/Sources/AllInApp/AllIn/Components/BetCard.swift +++ b/Sources/AllInApp/AllIn/Components/BetCard.swift @@ -11,22 +11,29 @@ import Model struct BetCard: View { var bet: Bet - + @State var showDetails: Bool = false + @State var showParticipate: Bool = false + var body: some View { VStack(spacing: 0){ VStack(alignment: .leading,spacing: 2){ HStack{ 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.phrase).font(.system(size: 20)).fontWeight(.bold) + Text(bet.theme) + .font(.system(size: 15)) + .foregroundColor(AllInColors.grey800Color) + Text(bet.phrase) + .font(.system(size: 20)) + .fontWeight(.bold) HStack{ Text("Commence le").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) TextCapsule(date: bet.endRegisterDate) Spacer() - } } .frame(width: .infinity) @@ -37,35 +44,15 @@ struct BetCard: View { HStack{ Spacer() 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() }.padding(0) - Button { - - } 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) - + ParticipateButton(isOpen: $showDetails, isParticapatedOpen: $showParticipate, bet: bet) + .padding(.top, 5) } .frame(width: .infinity) .padding(.all,8) @@ -73,20 +60,26 @@ struct BetCard: View { .cornerRadius(20, corners: [.bottomLeft,.bottomRight]) .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) } + .onTapGesture { + showDetails.toggle() + } + .fullScreenCover(isPresented: $showDetails) { + DetailsView(isModalPresented: $showDetails, isModalParticipated: $showParticipate,id: bet.id) + } } } struct BetCard_Previews: PreviewProvider { static var previews: some View { BetCard(bet: BinaryBet(theme: "Football - Finale de la Ligue des Champions", - phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", - endRegisterDate: Date().addingTimeInterval(86400), - endBetDate: Date().addingTimeInterval(172800), - totalStakes: 100, - isPublic: true, - invited: [], - author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []), - registered: [])) - .preferredColorScheme(.dark) + phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", + endRegisterDate: Date().addingTimeInterval(86400), + endBetDate: Date().addingTimeInterval(172800), + isPublic: true, + status: .FINISHED, + invited: [], + author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []), + registered: [])) + .preferredColorScheme(.dark) } } diff --git a/Sources/AllInApp/AllIn/Components/BetLineLoading.swift b/Sources/AllInApp/AllIn/Components/BetLineLoading.swift new file mode 100644 index 0000000..5d841af --- /dev/null +++ b/Sources/AllInApp/AllIn/Components/BetLineLoading.swift @@ -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) + } +} + + diff --git a/Sources/AllInApp/AllIn/Components/DropDownAnswerMenu.swift b/Sources/AllInApp/AllIn/Components/DropDownAnswerMenu.swift new file mode 100644 index 0000000..b3c3c99 --- /dev/null +++ b/Sources/AllInApp/AllIn/Components/DropDownAnswerMenu.swift @@ -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.. Void)? + + init(answer: Binding, mise: Binding, 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) + } +} diff --git a/Sources/AllInApp/AllIn/Components/RecapBetCard.swift b/Sources/AllInApp/AllIn/Components/RecapBetCard.swift index df1957e..b788b52 100644 --- a/Sources/AllInApp/AllIn/Components/RecapBetCard.swift +++ b/Sources/AllInApp/AllIn/Components/RecapBetCard.swift @@ -11,6 +11,8 @@ struct RecapBetCard: View { @GestureState private var longPressTap = false @State private var isPressed = false + @State var showDetails: Bool = false + @State var showPartipated: Bool = false var body: some View { VStack(spacing: 0){ VStack(alignment: .leading,spacing: 2){ @@ -103,6 +105,11 @@ struct RecapBetCard: View { .padding(.bottom,0).border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) }.scaleEffect(longPressTap ? 0.97 : 1.0) .animation(.easeInOut, value: longPressTap) + .onTapGesture { + showDetails.toggle() + }.fullScreenCover(isPresented: $showDetails) { + DetailsView(isModalPresented: $showDetails, isModalParticipated: $showPartipated,id: "1") + } .gesture( LongPressGesture(minimumDuration: 0.5) .updating($longPressTap) { value, state, _ in diff --git a/Sources/AllInApp/AllIn/Components/ResultBanner.swift b/Sources/AllInApp/AllIn/Components/ResultBanner.swift new file mode 100644 index 0000000..441542f --- /dev/null +++ b/Sources/AllInApp/AllIn/Components/ResultBanner.swift @@ -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)) + } +} diff --git a/Sources/AllInApp/AllIn/Components/ReviewCard.swift b/Sources/AllInApp/AllIn/Components/ReviewCard.swift index 7b4754b..1730ff8 100644 --- a/Sources/AllInApp/AllIn/Components/ReviewCard.swift +++ b/Sources/AllInApp/AllIn/Components/ReviewCard.swift @@ -8,6 +8,8 @@ import SwiftUI struct ReviewCard: View { + @State var showDetails: Bool = false + @State var showPartipated: Bool = false var amountBetted: Int var isAWin: Bool @@ -36,14 +38,14 @@ struct ReviewCard: View { HStack(){ Spacer() Text(amountBetted.description) - .foregroundColor(AllInColors.whiteColor) + .foregroundColor(.white) .font(.system(size: 25)) .fontWeight(.bold) Image("allcoinWhiteIcon") .resizable() .frame(width: 20, height: 20, alignment: .bottom) Text(isAWin ? "Gagnés!" : "Perdus!") - .foregroundColor(AllInColors.whiteColor) + .foregroundColor(.white) .font(.system(size: 25)) .fontWeight(.bold) Spacer() @@ -66,5 +68,10 @@ struct ReviewCard: View { ) .cornerRadius(20, corners: [.bottomLeft,.bottomRight]) .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) } + .onTapGesture { + showDetails.toggle() + }.fullScreenCover(isPresented: $showDetails) { + DetailsView(isModalPresented: $showDetails, isModalParticipated: $showPartipated, id: "1") + } } } diff --git a/Sources/AllInApp/AllIn/Extensions/Extensions.swift b/Sources/AllInApp/AllIn/Extensions/Extensions.swift index 74732e0..a79953c 100644 --- a/Sources/AllInApp/AllIn/Extensions/Extensions.swift +++ b/Sources/AllInApp/AllIn/Extensions/Extensions.swift @@ -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) + ) + } +} diff --git a/Sources/AllInApp/AllIn/Ressources/Colors.swift b/Sources/AllInApp/AllIn/Ressources/Colors.swift index 2f53a3e..ae60939 100644 --- a/Sources/AllInApp/AllIn/Ressources/Colors.swift +++ b/Sources/AllInApp/AllIn/Ressources/Colors.swift @@ -47,7 +47,12 @@ struct AllInColors { static let lightGrey300Color = Color("LightGrey300Color") static let componentBackgroundColor = Color("ComponentBackgroundColor") 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 static let primaryGradient = LinearGradient( gradient: Gradient(colors: [AllInColors.pinkAccentColor, AllInColors.blueAccentColor]), @@ -60,4 +65,16 @@ struct AllInColors { 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 + ) + } diff --git a/Sources/AllInApp/AllIn/Ressources/Config.swift b/Sources/AllInApp/AllIn/Ressources/Config.swift index e235a9a..d734b64 100644 --- a/Sources/AllInApp/AllIn/Ressources/Config.swift +++ b/Sources/AllInApp/AllIn/Ressources/Config.swift @@ -8,5 +8,5 @@ import Foundation struct Config { - static let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api" + static let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/" } diff --git a/Sources/AllInApp/AllIn/Services/AuthService.swift b/Sources/AllInApp/AllIn/Services/AuthService.swift index 62a99ec..700fd21 100644 --- a/Sources/AllInApp/AllIn/Services/AuthService.swift +++ b/Sources/AllInApp/AllIn/Services/AuthService.swift @@ -7,49 +7,52 @@ import Foundation import Model -import ViewModel import DependencyInjection import Api import StubLib class AuthService: IAuthService { - public func login(login: String, password: String, completion : @escaping (Int)-> ()) { + public func login(login: String, password: String, completion: @escaping (Int) -> ()) { let url = URL(string: Config.allInApi + "users/login")! var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") - + let json = [ "login": login.lowercased(), "password": password, ] - - 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 - print ("ALLIN : Process LOGIN") + print("ALLIN: Process LOGIN") if let httpResponse = response as? HTTPURLResponse { if httpResponse.statusCode == 200 { if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let token = json["token"] as? String { - AppStateContainer.shared.authenticationRefresh = token; + AppStateContainer.shared.authenticationRefresh = token self.initializeUser(withToken: token) { status in + print(status) if status != 200 { completion(status) - AppStateContainer.shared.authenticationRefresh = nil; + AppStateContainer.shared.authenticationRefresh = nil } else { self.initManagerVM(token: token) + completion(httpResponse.statusCode) } } } + } else { + completion(httpResponse.statusCode) } - completion(httpResponse.statusCode) } }.resume() } } + func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) { let url = URL(string: Config.allInApi + "/users/register")! @@ -60,8 +63,7 @@ class AuthService: IAuthService { let json = [ "email": email.lowercased(), "username": username.lowercased(), - "password": password, - "nbCoins": "0" + "password": password ] if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){ @@ -79,11 +81,13 @@ class AuthService: IAuthService { AppStateContainer.shared.authenticationRefresh = nil; } else { self.initManagerVM(token: token) + completion(httpResponse.statusCode) } } } + } else { + completion(httpResponse.statusCode) } - completion(httpResponse.statusCode) } }.resume() } @@ -119,12 +123,14 @@ class AuthService: IAuthService { } private func initializeUser(withToken token: String, completion: @escaping (Int) -> ()) { + let url = URL(string: Config.allInApi + "users/token")! 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, let httpResponse = response as? HTTPURLResponse { @@ -144,7 +150,12 @@ class AuthService: IAuthService { } 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 } } diff --git a/Sources/AllInApp/AllIn/Services/IAuthService.swift b/Sources/AllInApp/AllIn/Services/IAuthService.swift index cafd070..57c7050 100644 --- a/Sources/AllInApp/AllIn/Services/IAuthService.swift +++ b/Sources/AllInApp/AllIn/Services/IAuthService.swift @@ -11,4 +11,5 @@ protocol IAuthService { func login(login: String, password: String, completion : @escaping (Int)-> ()) func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) func refreshAuthentication() + func logout() } diff --git a/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift index 6a6dd6c..e378534 100644 --- a/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift @@ -7,30 +7,23 @@ import Foundation import DependencyInjection -import ViewModel import Model import Combine class BetViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager - @Published private var internalBets: [Bet] = [] - - var bets: [Bet] { - return internalBets - } + @Published private(set) var bets: [Bet] = [] init() { getItems() } func getItems() { - for bet in manager.bets { - print(bet.theme) + manager.getBets(withIndex: 0, withCount: 20) { bets in + self.bets = bets } - manager.$bets.assign(to: \.internalBets, on: self).store(in: &cancellables) - manager.getPublicBets() } private var cancellables: Set = [] diff --git a/Sources/AllInApp/AllIn/ViewModels/CreationBetViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/CreationBetViewModel.swift index 4adb521..bc7b7b0 100644 --- a/Sources/AllInApp/AllIn/ViewModels/CreationBetViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/CreationBetViewModel.swift @@ -8,11 +8,11 @@ import Foundation import SwiftUI import DependencyInjection -import ViewModel +import Model class CreationBetViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager @Published var theme: String = "" @Published var description: String = "" @Published var isPublic = true diff --git a/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift new file mode 100644 index 0000000..3615836 --- /dev/null +++ b/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift @@ -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) + } + } +} diff --git a/Sources/AllInApp/AllIn/ViewModels/FriendsViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/FriendsViewModel.swift index a98dfbf..294ab23 100644 --- a/Sources/AllInApp/AllIn/ViewModels/FriendsViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/FriendsViewModel.swift @@ -7,11 +7,11 @@ import Foundation import DependencyInjection -import ViewModel +import Model class FriendsViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager init() { getItems() diff --git a/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift new file mode 100644 index 0000000..480c7a1 --- /dev/null +++ b/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift @@ -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() { + + } +} diff --git a/Sources/AllInApp/AllIn/ViewModels/RankingViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/RankingViewModel.swift index d9bfcbd..e321f91 100644 --- a/Sources/AllInApp/AllIn/ViewModels/RankingViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/RankingViewModel.swift @@ -7,11 +7,11 @@ import Foundation import DependencyInjection -import ViewModel +import Model class RankingViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager init() { getItems() diff --git a/Sources/AllInApp/AllIn/Views/BetView.swift b/Sources/AllInApp/AllIn/Views/BetView.swift index bc21e48..9f28940 100644 --- a/Sources/AllInApp/AllIn/Views/BetView.swift +++ b/Sources/AllInApp/AllIn/Views/BetView.swift @@ -12,7 +12,7 @@ struct BetView: View { @StateObject private var viewModel = BetViewModel() @Binding var showMenu: Bool - @State private var showingSheet = false + @State var showingSheet: Bool = false var body: some View { @@ -31,9 +31,6 @@ struct BetView: View { Button("Show Sheet") { showingSheet.toggle() } - .sheet(isPresented: $showingSheet) { - WinModal() - } } .padding([.leading,.trailing],25) @@ -57,16 +54,24 @@ struct BetView: View { } } } + .refreshable { + viewModel.getItems() + } + .sheet(isPresented: $showingSheet) { + WinModal() + } Spacer() } .edgesIgnoringSafeArea(.bottom) .background(AllInColors.backgroundColor) + } } + struct BetView_Previews: PreviewProvider { static var previews: some View { BetView(showMenu: .constant(false)) - .preferredColorScheme(.dark) + .preferredColorScheme(.light) } } diff --git a/Sources/AllInApp/AllIn/Views/DetailsView.swift b/Sources/AllInApp/AllIn/Views/DetailsView.swift new file mode 100644 index 0000000..2bd3322 --- /dev/null +++ b/Sources/AllInApp/AllIn/Views/DetailsView.swift @@ -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, isModalParticipated: Binding, 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) + } + } +} diff --git a/Sources/AllInApp/AllIn/Views/MainView.swift b/Sources/AllInApp/AllIn/Views/MainView.swift index 790873f..9b7900a 100644 --- a/Sources/AllInApp/AllIn/Views/MainView.swift +++ b/Sources/AllInApp/AllIn/Views/MainView.swift @@ -10,6 +10,7 @@ import SwiftUI struct MainView: View { @State var showMenu = false + var page: String var body: some View { @@ -58,6 +59,7 @@ struct MainView: View { .frame(width: geometry.size.width*0.83) .transition(.move(edge: .leading)) } + } .gesture(closeDrag) } diff --git a/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj b/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj index bde5765..3fbc216 100644 --- a/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj +++ b/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj @@ -7,20 +7,28 @@ objects = { /* 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 */; }; 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 */; }; EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; }; EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.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 */; }; EC3077092B24CF7F0060E34D /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077082B24CF7F0060E34D /* Colors.swift */; }; EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770A2B24D9160060E34D /* WelcomeView.swift */; }; EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770C2B24DB7A0060E34D /* Extensions.swift */; }; EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770E2B24FCB00060E34D /* RegisterView.swift */; }; EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; }; - EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2D2B4EC04B00853949 /* ViewModel */; }; - EC4F0D302B4EC05D00853949 /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2F2B4EC05D00853949 /* StubLib */; }; + EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC60C5672B5A83FB00FFD6EF /* StubLib */; }; EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; }; EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */; }; EC650A462B25D686003AFCAD /* RankingRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A452B25D686003AFCAD /* RankingRow.swift */; }; @@ -96,15 +104,23 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipationModal.swift; sourceTree = ""; }; + 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownAnswerMenu.swift; sourceTree = ""; }; 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 = ""; }; - 122278BB2B4BDEC300E632AA /* Sources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Sources; path = ../StubLib/Sources; sourceTree = ""; }; + 123590B32B51792000F7AEBD /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = ""; }; + 123590B52B5537E200F7AEBD /* ResultBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultBanner.swift; sourceTree = ""; }; + 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.swift; sourceTree = ""; }; 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetView.swift; sourceTree = ""; }; 1244EF612B4EC67000374ABF /* ReviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewCard.swift; sourceTree = ""; }; + 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetLineLoading.swift; sourceTree = ""; }; + 12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticiationCell.swift; sourceTree = ""; }; EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCapsule.swift; sourceTree = ""; }; EC0193792B25C12B005D81E6 /* BetCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetCard.swift; sourceTree = ""; }; EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCounter.swift; sourceTree = ""; }; EC01937D2B25C52E005D81E6 /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.swift; sourceTree = ""; }; + EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsViewModel.swift; sourceTree = ""; }; + EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetViewModel.swift; sourceTree = ""; }; EC3077062B24CB840060E34D /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; EC3077082B24CF7F0060E34D /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; EC30770A2B24D9160060E34D /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; @@ -161,10 +177,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EC4F0D302B4EC05D00853949 /* StubLib in Frameworks */, + EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */, EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */, ECCD244A2B4DE8010071FA9E /* Api in Frameworks */, - EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -290,6 +305,7 @@ EC650A512B2794DD003AFCAD /* BetView.swift */, EC7A882C2B28D8A1004F226A /* CreationBetView.swift */, 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */, + 123590B32B51792000F7AEBD /* DetailsView.swift */, ); path = Views; sourceTree = ""; @@ -316,6 +332,12 @@ ECA9D1C82B2D9ADA0076E0EC /* UserInfo.swift */, ECA9D1CA2B2DA2320076E0EC /* DropDownFriends.swift */, 1244EF612B4EC67000374ABF /* ReviewCard.swift */, + 123590B52B5537E200F7AEBD /* ResultBanner.swift */, + 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */, + 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */, + 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */, + 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */, + 12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */, ); path = Components; sourceTree = ""; @@ -323,7 +345,6 @@ ECB3572D2B3CA3BD00045D41 /* Frameworks */ = { isa = PBXGroup; children = ( - 122278BB2B4BDEC300E632AA /* Sources */, 122278B92B4BDE9500E632AA /* Package.swift */, 122278B72B4BDE1100E632AA /* DependencyInjection.framework */, ECB357302B3CA69300045D41 /* DependencyInjection.framework */, @@ -341,6 +362,8 @@ ECB26A162B4073F100FE06B3 /* CreationBetViewModel.swift */, ECB26A182B40744F00FE06B3 /* RankingViewModel.swift */, ECB26A1A2B40746C00FE06B3 /* FriendsViewModel.swift */, + EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */, + EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -365,8 +388,7 @@ packageProductDependencies = ( ECB357342B3E13A400045D41 /* Model */, ECCD24492B4DE8010071FA9E /* Api */, - EC4F0D2D2B4EC04B00853949 /* ViewModel */, - EC4F0D2F2B4EC05D00853949 /* StubLib */, + EC60C5672B5A83FB00FFD6EF /* StubLib */, ); productName = AllIn; productReference = EC6B96982B24B4CC00FC1C58 /* AllIn.app */; @@ -492,10 +514,12 @@ EC6B969E2B24B4CC00FC1C58 /* ContentView.swift in Sources */, EC89F7BD2B250D66003821CE /* LoginView.swift in Sources */, EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */, + 120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */, ECB26A132B406A9400FE06B3 /* BetViewModel.swift in Sources */, EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */, EC650A522B2794DD003AFCAD /* BetView.swift in Sources */, EC6B969C2B24B4CC00FC1C58 /* AllInApp.swift in Sources */, + 123590B42B51792000F7AEBD /* DetailsView.swift in Sources */, ECB26A192B40744F00FE06B3 /* RankingViewModel.swift in Sources */, EC650A502B2793D5003AFCAD /* TextCapsule.swift in Sources */, EC650A482B25DCFF003AFCAD /* UsersPreview.swift in Sources */, @@ -518,16 +542,23 @@ EC3077072B24CB840060E34D /* SplashView.swift in Sources */, EC01937E2B25C52E005D81E6 /* TopBar.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 */, ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */, 1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */, EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */, EC650A562B279D68003AFCAD /* WinModal.swift in Sources */, EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */, + 123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */, + EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */, EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */, + 12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */, EC650A542B279545003AFCAD /* ChoiceCapsule.swift in Sources */, ECB7BC6C2B2F43EE002A6654 /* AppState.swift in Sources */, ECA9D1C92B2D9ADA0076E0EC /* UserInfo.swift in Sources */, + 1209191A2B56DC6C00D0FA29 /* DropDownAnswerMenu.swift in Sources */, EC650A582B279D9D003AFCAD /* RecapBetCard.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -857,11 +888,7 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - EC4F0D2D2B4EC04B00853949 /* ViewModel */ = { - isa = XCSwiftPackageProductDependency; - productName = ViewModel; - }; - EC4F0D2F2B4EC05D00853949 /* StubLib */ = { + EC60C5672B5A83FB00FFD6EF /* StubLib */ = { isa = XCSwiftPackageProductDependency; productName = StubLib; }; diff --git a/Sources/Api/Sources/Api/BetApiManager.swift b/Sources/Api/Sources/Api/BetApiManager.swift index 10225a3..380d832 100644 --- a/Sources/Api/Sources/Api/BetApiManager.swift +++ b/Sources/Api/Sources/Api/BetApiManager.swift @@ -10,7 +10,11 @@ import Model 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) { let url = URL(string: allInApi + "bets/gets")! @@ -27,9 +31,8 @@ public struct BetApiManager: BetDataManager { do { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { for json in jsonArray { - if let bet = FactoryApiBet().toModel(from: json) { + if let bet = FactoryApiBet().toBet(from: json) { bets.append(bet) - print(bet.theme) } } print(httpResponse.statusCode) @@ -46,4 +49,31 @@ public struct BetApiManager: BetDataManager { 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() + + } + } diff --git a/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift b/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift index 8c29b11..555d852 100644 --- a/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift +++ b/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift @@ -10,23 +10,37 @@ import Model 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] { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" let json: [String: Any] = [ "theme": bet.theme, "sentenceBet": bet.phrase, - "endRegistration": dateFormatter.string(from: bet.endRegisterDate), - "endBet": dateFormatter.string(from: bet.endBetDate), + "endRegistration": formatZonedDateTime(dateTime: bet.endRegisterDate), + "endBet": formatZonedDateTime(dateTime: bet.endBetDate), "isPrivate": String(bet.isPublic), - "response": [], + "response": ["Yes","No"], ] return json } - public func toModel(from json: [String: Any]) -> Bet? { - guard let theme = json["theme"] as? String, + public func fromJsonDateString(_ dateString: String) -> Date? { + 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 endRegisterDateString = json["endRegistration"] as? String, let endBetDateString = json["endBet"] as? String, @@ -35,28 +49,55 @@ public class FactoryApiBet: FactoryBet { return nil } - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" - - guard let endRegisterDate = dateFormatter.date(from: endRegisterDateString), - let endBetDate = dateFormatter.date(from: endBetDateString) else { + guard let endRegisterDate = fromJsonDateString(endRegisterDateString), + let endBetDate = fromJsonDateString(endBetDateString) else { 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 { 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: - 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: - 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: - 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) } } diff --git a/Sources/Api/Sources/Api/UserApiManager.swift b/Sources/Api/Sources/Api/UserApiManager.swift index 6330e6e..cea22c2 100644 --- a/Sources/Api/Sources/Api/UserApiManager.swift +++ b/Sources/Api/Sources/Api/UserApiManager.swift @@ -8,7 +8,7 @@ import Foundation 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 { @@ -24,22 +24,18 @@ public struct UserApiManager: UserDataManager { public func addBet(bet: Bet) { - print(token) let url = URL(string: allInApi + "bets/add")! var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") + + let json = FactoryApiBet().toResponse(bet: bet) - var json = FactoryApiBet().toResponse(bet: bet) - json["createdBy"] = token - if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){ URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in print ("ALLIN : Add BET") if let httpResponse = response as? HTTPURLResponse { - if httpResponse.statusCode == 201 { - - } print(httpResponse.statusCode) } }.resume() @@ -49,4 +45,31 @@ public struct UserApiManager: UserDataManager { public func getFriends() -> [User] { 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() + } + } } diff --git a/Sources/Model/Sources/Model/AnswerDetail.swift b/Sources/Model/Sources/Model/AnswerDetail.swift new file mode 100644 index 0000000..6474788 --- /dev/null +++ b/Sources/Model/Sources/Model/AnswerDetail.swift @@ -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 + } +} diff --git a/Sources/Model/Sources/Model/Bet.swift b/Sources/Model/Sources/Model/Bet.swift index fca14b5..f733cd4 100644 --- a/Sources/Model/Sources/Model/Bet.swift +++ b/Sources/Model/Sources/Model/Bet.swift @@ -11,7 +11,7 @@ import Foundation public class Bet: ObservableObject, Identifiable { /// The id for the bet. - public var id = UUID() + public private(set) var id: String /// The theme or topic of the bet. public private(set) var theme: String @@ -25,12 +25,11 @@ public class Bet: ObservableObject, Identifiable { /// The deadline for the actual betting to take place. 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. public private(set) var isPublic: Bool + public private(set) var status: BetStatus + /// List of users who are invited to participate in the bet. public private(set) var invited: [User] @@ -39,28 +38,58 @@ public class Bet: ObservableObject, Identifiable { /// List of users who have registered for the bet. public private(set) var registered: [User] + /// Custom Constructor /// /// - Parameters: + /// - id: The id for the bet. /// - 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. - /// - totalStakes: The total stakes or amount involved in the bet. /// - 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, 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.phrase = phrase self.endRegisterDate = endRegisterDate self.endBetDate = endBetDate - self.totalStakes = totalStakes self.isPublic = isPublic + self.status = status self.invited = invited self.author = author 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) + } } diff --git a/Sources/Model/Sources/Model/BetDataManager.swift b/Sources/Model/Sources/Model/BetDataManager.swift index 24a769c..6fede4a 100644 --- a/Sources/Model/Sources/Model/BetDataManager.swift +++ b/Sources/Model/Sources/Model/BetDataManager.swift @@ -10,4 +10,5 @@ import Foundation public protocol BetDataManager { func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) func getUsers(username: String) -> [User] + func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) } diff --git a/Sources/Model/Sources/Model/BetDetail.swift b/Sources/Model/Sources/Model/BetDetail.swift new file mode 100644 index 0000000..2f647f5 --- /dev/null +++ b/Sources/Model/Sources/Model/BetDetail.swift @@ -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) + } +} diff --git a/Sources/Model/Sources/Model/BinaryBet.swift b/Sources/Model/Sources/Model/BinaryBet.swift index 8767849..fafd7be 100644 --- a/Sources/Model/Sources/Model/BinaryBet.swift +++ b/Sources/Model/Sources/Model/BinaryBet.swift @@ -10,19 +10,4 @@ import Foundation /// A subclass of Bet that represents a binary bet, where participants make a choice between two possible outcomes. 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) - } } diff --git a/Sources/Model/Sources/Model/BinaryParticipation.swift b/Sources/Model/Sources/Model/BinaryParticipation.swift deleted file mode 100644 index 5a02622..0000000 --- a/Sources/Model/Sources/Model/BinaryParticipation.swift +++ /dev/null @@ -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) - } -} diff --git a/Sources/Model/Sources/Model/CustomParticipation.swift b/Sources/Model/Sources/Model/CustomParticipation.swift deleted file mode 100644 index 9956aa9..0000000 --- a/Sources/Model/Sources/Model/CustomParticipation.swift +++ /dev/null @@ -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) - } -} diff --git a/Sources/Model/Sources/Model/Factory/FactoryBet.swift b/Sources/Model/Sources/Model/Factory/FactoryBet.swift index c692035..be18215 100644 --- a/Sources/Model/Sources/Model/Factory/FactoryBet.swift +++ b/Sources/Model/Sources/Model/Factory/FactoryBet.swift @@ -9,6 +9,7 @@ import Foundation public protocol FactoryBet { func toResponse(bet: Bet) -> [String: Any] - func toModel(from json: [String: Any]) -> Bet? - func toModel(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet + func toBet(from json: [String: Any]) -> 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 } diff --git a/Sources/Model/Sources/Model/File.swift b/Sources/Model/Sources/Model/File.swift new file mode 100644 index 0000000..a44b593 --- /dev/null +++ b/Sources/Model/Sources/Model/File.swift @@ -0,0 +1,12 @@ +// +// File.swift +// +// +// Created by étudiant on 23/01/2024. +// + +import Foundation + +public enum BetStatus { + case WAITING, IN_PROGRESS, FINISHED +} diff --git a/Sources/Model/Sources/Model/Manager.swift b/Sources/Model/Sources/Model/Manager.swift index 224e021..cc4e25e 100644 --- a/Sources/Model/Sources/Model/Manager.swift +++ b/Sources/Model/Sources/Model/Manager.swift @@ -16,8 +16,8 @@ public struct Manager { self.userDataManager = userDataManager } - public func addBet(bet: Bet) { - userDataManager.addBet(bet: bet) + public func addBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User) { + 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) { @@ -25,4 +25,20 @@ public struct Manager { 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) + } } diff --git a/Sources/Model/Sources/Model/MatchBet.swift b/Sources/Model/Sources/Model/MatchBet.swift index cddcc4e..a6100c1 100644 --- a/Sources/Model/Sources/Model/MatchBet.swift +++ b/Sources/Model/Sources/Model/MatchBet.swift @@ -18,6 +18,7 @@ public class MatchBet: Bet { /// Custom Constructor /// /// - Parameters: + /// - id: The id for the bet. /// - 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. @@ -29,9 +30,29 @@ public class MatchBet: 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, 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.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) } } diff --git a/Sources/Model/Sources/Model/MatchParticipation.swift b/Sources/Model/Sources/Model/MatchParticipation.swift deleted file mode 100644 index 68b47ba..0000000 --- a/Sources/Model/Sources/Model/MatchParticipation.swift +++ /dev/null @@ -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) - } -} diff --git a/Sources/Model/Sources/Model/Participation.swift b/Sources/Model/Sources/Model/Participation.swift index 6ccd9be..c435ff9 100644 --- a/Sources/Model/Sources/Model/Participation.swift +++ b/Sources/Model/Sources/Model/Participation.swift @@ -1,37 +1,45 @@ // // Participation.swift -// +// // // Created by Emre on 28/12/2023. // import Foundation -/// A class representing a user's participation in a bet, including the amount of coins, date, user, and the associated bet. -public class Participation: ObservableObject { - /// The amount of coins involved in the participation. - var coinAmount: Int +/// A class representing a user's participation in a bet. +public class Participation: ObservableObject, Identifiable { + + 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. - 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. - var user: User + public private(set) var user: User - /// The bet in which the user participated. - var bet: Bet + /// The unique identifier of the bet. + public private(set) var betId: String /// Custom Constructor /// /// - 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. + /// - response: The response or outcome of the participation. /// - user: The user who participated in the bet. - /// - bet: The bet in which the user participated. - init(coinAmount: Int, date: Date, user: User, bet: Bet) { - self.coinAmount = coinAmount + /// - betId: The unique identifier of the bet. + public init(id: String, stake: Int, date: Date, response: String, user: User, betId: String) { + self.id = id + self.stake = stake self.date = date + self.response = response self.user = user - self.bet = bet + self.betId = betId } } diff --git a/Sources/Model/Sources/Model/User.swift b/Sources/Model/Sources/Model/User.swift index 784902f..385d6ee 100644 --- a/Sources/Model/Sources/Model/User.swift +++ b/Sources/Model/Sources/Model/User.swift @@ -8,10 +8,10 @@ import Foundation public struct User { - public var username: String - public var email: String - public var nbCoins: Int - public var friends: [User] + public private(set) var username: String + public private(set) var email: String + public private(set) var nbCoins: Int + public private(set) var friends: [User] public init(username: String, email: String, nbCoins: Int, friends: [User]) { self.username = username diff --git a/Sources/Model/Sources/Model/UserDataManager.swift b/Sources/Model/Sources/Model/UserDataManager.swift index 584add7..87eb2a6 100644 --- a/Sources/Model/Sources/Model/UserDataManager.swift +++ b/Sources/Model/Sources/Model/UserDataManager.swift @@ -11,4 +11,6 @@ public protocol UserDataManager { func getBets(withIndex index: Int, withCount count: Int) -> [Bet] func addBet(bet: Bet) 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) } diff --git a/Sources/ViewModel/.gitignore b/Sources/StubLib/.gitignore similarity index 100% rename from Sources/ViewModel/.gitignore rename to Sources/StubLib/.gitignore diff --git a/Sources/StubLib/Sources/StubLib/BetStubManager.swift b/Sources/StubLib/Sources/StubLib/BetStubManager.swift index bfacf3f..7bb801f 100644 --- a/Sources/StubLib/Sources/StubLib/BetStubManager.swift +++ b/Sources/StubLib/Sources/StubLib/BetStubManager.swift @@ -1,6 +1,6 @@ // // BetStubManager.swift -// +// // // Created by Emre on 31/12/2023. // @@ -17,10 +17,16 @@ public struct BetStubManager: BetDataManager { } public func getUsers(username: String) -> [User] { - return Stub.shared.users - .filter { user in - user.username.contains(username) - } + return [] + } + + 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.") + } } } diff --git a/Sources/StubLib/Sources/StubLib/Stub.swift b/Sources/StubLib/Sources/StubLib/Stub.swift index fe9e225..5371b6c 100644 --- a/Sources/StubLib/Sources/StubLib/Stub.swift +++ b/Sources/StubLib/Sources/StubLib/Stub.swift @@ -1,6 +1,6 @@ // // Stub.swift -// +// // // Created by Emre on 01/01/2024. // @@ -12,6 +12,7 @@ struct Stub { static var shared = Stub() public var bets: [Bet] = [] + public var betsDetail: [BetDetail] = [] public var users: [User] = [] public init() { @@ -34,10 +35,10 @@ struct Stub { let bet1 = BinaryBet( theme: "Football - Finale de la Ligue des Champions", 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), - totalStakes: 100, isPublic: true, + status: .IN_PROGRESS, invited: [], author: user1, registered: [user2] @@ -49,8 +50,8 @@ struct Stub { phrase: "Le plat préféré du jury sera une recette végétarienne.", endRegisterDate: Date().addingTimeInterval(172800), endBetDate: Date().addingTimeInterval(259200), - totalStakes: 150, isPublic: false, + status: .IN_PROGRESS, invited: [user3], author: user1, 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 ?", endRegisterDate: Date().addingTimeInterval(259200), endBetDate: Date().addingTimeInterval(345600), - totalStakes: 75, isPublic: true, + status: .FINISHED, invited: [], author: user1, registered: [user2, user1, user3] @@ -75,17 +76,28 @@ struct Stub { phrase: "Le film favori des critiques remportera-t-il le prix du meilleur film ?", endRegisterDate: Date().addingTimeInterval(345600), endBetDate: Date().addingTimeInterval(432000), - totalStakes: 120, isPublic: false, + status: .FINISHED, invited: [user1], author: user2, registered: [user3] ) 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) { - self.bets.append(bet) + let newBetDetail = BetDetail(bet: bet, answers: [], participations: [], finalAnswer: "test") + self.betsDetail.append(newBetDetail) } } diff --git a/Sources/StubLib/Sources/StubLib/UserStubManager.swift b/Sources/StubLib/Sources/StubLib/UserStubManager.swift deleted file mode 100644 index a2f8b07..0000000 --- a/Sources/StubLib/Sources/StubLib/UserStubManager.swift +++ /dev/null @@ -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 - } - } - } -} diff --git a/Sources/ViewModel/Package.swift b/Sources/ViewModel/Package.swift deleted file mode 100644 index 67fd2cf..0000000 --- a/Sources/ViewModel/Package.swift +++ /dev/null @@ -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"]), - ] -) diff --git a/Sources/ViewModel/README.md b/Sources/ViewModel/README.md deleted file mode 100644 index 74e3704..0000000 --- a/Sources/ViewModel/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# ViewModel - -A description of this package. diff --git a/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift b/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift deleted file mode 100644 index 673750b..0000000 --- a/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift +++ /dev/null @@ -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: [])) - } -}