Compare commits

..

No commits in common. 'master' and 'V4' have entirely different histories.
master ... V4

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

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

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array/>
</dict>
</plist>

@ -13,7 +13,6 @@ import Model
struct AllInApp: App { struct AllInApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@Environment(\.scenePhase) var phase
let DI = DependencyInjection.shared let DI = DependencyInjection.shared
init() { init() {
@ -23,17 +22,6 @@ struct AllInApp: App {
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
ContentView() ContentView()
.onAppear {
AppStateContainer.shared.notificationState.scheduleNotifications()
}
.onChange(of: phase) { newPhase in
switch newPhase {
case .background, .inactive:
UIApplication.shared.shortcutItems = QuickAction.allShortcutItems
default:
break
}
}
} }
} }
} }

@ -0,0 +1,41 @@
//
// AppDelegate.swift
// AllIn
//
// Created by Emre on 17/12/2023.
//
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}

@ -12,10 +12,9 @@ class AppStateContainer: ObservableObject {
static let shared = AppStateContainer() static let shared = AppStateContainer()
let loggedState: LoggedState = LoggedState() let loggedState: LoggedState = LoggedState()
var onlineStatus: OnlineStatus = OnlineStatus() var onlineStatus: OnlineStatus = OnlineStatus()
var notificationState: NotificationService = NotificationService()
@Published var user: User? @Published var user: User?
@AppStorage("authenticationRefresh", store: UserDefaults(suiteName: "group.alldev.AllIn")!) var authenticationRefresh: String? @AppStorage("authenticationRefresh") var authenticationRefresh: String?
} }
class LoggedState: ObservableObject { class LoggedState: ObservableObject {

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

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

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

@ -15,13 +15,13 @@ struct AllcoinsCounter: View {
var body: some View { var body: some View {
HStack(alignment: .center) { HStack(alignment: .center) {
Text(String(appStateContainer.user!.nbCoins))
.contentTransition(.numericText())
.fontWeight(.black)
.foregroundColor(foregroundColor)
Image("allcoinIcon") Image("allcoinIcon")
.resizable() .resizable()
.frame(width: 17, height: 17, alignment: .leading) .frame(width: 17, height: 17, alignment: .leading)
Text(String(appStateContainer.user?.nbCoins ?? 0))
.contentTransition(.numericText())
.fontWeight(.black)
.foregroundColor(foregroundColor)
} }
.frame(width: 90, height: 40) .frame(width: 90, height: 40)
.background(backgroundColor) .background(backgroundColor)

@ -13,15 +13,16 @@ struct BetCard: View {
var bet: Bet var bet: Bet
@State var showDetails: Bool = false @State var showDetails: Bool = false
@State var showParticipate: Bool = false @State var showParticipate: Bool = false
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
VStack(alignment: .leading,spacing: 2){ VStack(alignment: .leading,spacing: 2){
HStack{ HStack{
Spacer() Spacer()
Text("bet_proposed_by_format \(bet.author.capitalized)") Text("proposé par " + bet.author.username.capitalized)
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
} }
Text(bet.theme) Text(bet.theme)
.font(.system(size: 15)) .font(.system(size: 15))
@ -30,7 +31,7 @@ struct BetCard: View {
.font(.system(size: 20)) .font(.system(size: 20))
.fontWeight(.bold) .fontWeight(.bold)
HStack{ HStack{
Text("bet_starting") Text("Commence le")
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
TextCapsule(date: bet.endRegisterDate) TextCapsule(date: bet.endRegisterDate)
@ -44,8 +45,8 @@ struct BetCard: View {
VStack(alignment: .leading,spacing: 2){ VStack(alignment: .leading,spacing: 2){
HStack{ HStack{
Spacer() Spacer()
UsersPreview(users: []) UsersPreview()
Text("bet_players_waiting_format \(bet.invited.count.description)") Text(bet.registered.count.description + " joueurs en attente")
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
.fontWeight(.medium) .fontWeight(.medium)
@ -62,11 +63,12 @@ struct BetCard: View {
.cornerRadius(20, corners: [.bottomLeft,.bottomRight]) .cornerRadius(20, corners: [.bottomLeft,.bottomRight])
.border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
} }
.onTapGesture { .onTapGesture {
showDetails.toggle() showDetails.toggle()
} }
.fullScreenCover(isPresented: $showDetails) { .fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, isModalParticipated: $showParticipate, id: bet.id) DetailsView(isModalPresented: $showDetails, isModalParticipated: $showParticipate,id: bet.id)
} }
} }
} }
@ -77,10 +79,11 @@ struct BetCard_Previews: PreviewProvider {
phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.",
endRegisterDate: Date().addingTimeInterval(86400), endRegisterDate: Date().addingTimeInterval(86400),
endBetDate: Date().addingTimeInterval(172800), endBetDate: Date().addingTimeInterval(172800),
isPrivate: false, isPublic: true,
status: .inProgress, status: .inProgress,
invited: [], invited: [],
author: "Imri")) author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []),
registered: []))
.preferredColorScheme(.dark) .preferredColorScheme(.dark)
} }
} }

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

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

@ -6,39 +6,22 @@
// //
import SwiftUI import SwiftUI
import Model
struct ChoiceCapsule: View { struct ChoiceCapsule: View {
let filter: BetFilter
@State var pressed = false
@ObservedObject var viewModel: BetViewModel
var label: String { @State var pressed = false
switch filter {
case .isPublic:
return String(localized: "bet_public")
case .isInvitation:
return String(localized: "bet_invitation")
case .inProgress:
return String(localized: "bet_current")
case .isFinished:
return String(localized: "bet_finished")
default:
return "NaN"
}
}
var body: some View { var body: some View {
Group { Group {
if(pressed) { if(pressed) {
Text(label) Text("En cours")
.textStyle(weight: .semibold, color: .white, size: 15) .textStyle(weight: .semibold, color: .white, size: 15)
.padding([.leading,.trailing],13.8) .padding([.leading,.trailing],13.8)
.padding([.top,.bottom], 7) .padding([.top,.bottom], 7)
.background(AllInColors.lightPurpleColor) .background(AllInColors.lightPurpleColor)
.clipShape(Capsule()) .clipShape(Capsule())
} else { } else {
Text(label) Text("En cours")
.textStyle(weight: .regular, color: AllInColors.grey800Color, size: 15) .textStyle(weight: .regular, color: AllInColors.grey800Color, size: 15)
.padding([.leading,.trailing], 15) .padding([.leading,.trailing], 15)
.padding([.top,.bottom], 7) .padding([.top,.bottom], 7)
@ -52,12 +35,13 @@ struct ChoiceCapsule: View {
} }
.onTapGesture() { .onTapGesture() {
pressed.toggle() pressed.toggle()
if(pressed) {
viewModel.filters.insert(filter)
} else {
viewModel.filters.remove(filter)
}
} }
} }
} }
struct ChoiceCapsule_Previews: PreviewProvider {
static var previews: some View {
ChoiceCapsule()
}
}

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

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

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

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

@ -1,27 +0,0 @@
//
// EmptyInfo.swift
// AllIn
//
// Created by Lucas Delanier on 29/05/2024.
//
import SwiftUI
struct EmptyInfo: View {
let emoji: String
let title: String
let explain: String
var body: some View {
VStack{
Text(emoji).font(.system(size: 120))
Text(title).textStyle(weight: .bold, color: AllInColors.primaryTextColor , size: 15)
explain.isEmpty ? nil : Text(explain).textStyle(weight: .light, color: .gray, size: 12)
}.opacity(0.55).padding(.horizontal, 20).multilineTextAlignment(.center)
}
}
struct EmptyInfo_Previews: PreviewProvider {
static var previews: some View {
EmptyInfo(emoji:"👥", title: "Vous navez pas encore damis", explain: "Ajoutez les depuis cet écran")
}
}

@ -6,54 +6,38 @@
// //
import SwiftUI import SwiftUI
import Model
struct Friend: View { struct Friend: View {
var user: User var image: String
let isRequest: Bool var pseudo: String
@ObservedObject var viewModel: FriendsViewModel
var StatusValues: (String, Color, Color) {
switch user.friendStatus {
case .friend:
return isRequest ? (String(localized: "generic_decline"), AllInColors.grey400Color, AllInColors.componentBackgroundColor) : (String(localized: "generic_delete"), AllInColors.grey400Color, AllInColors.componentBackgroundColor)
case .notFriend:
return isRequest ? (String(localized: "generic_acccept"), .white, AllInColors.lightPurpleColor) : (String(localized: "generic_add"), .white, AllInColors.lightPurpleColor)
case .requested:
return (String(localized: "friends_request_sent"), AllInColors.grey400Color, AllInColors.componentBackgroundColor)
default:
return ("NaN", AllInColors.grey400Color, AllInColors.componentBackgroundColor)
}
}
var body: some View { var body: some View {
HStack{ HStack{
UserPicture(picture: user.image,username: user.username, size: 45) AsyncImage(url: URL(string: image))
Text(user.username) .frame(width: 50, height: 50)
.cornerRadius(180)
.scaledToFit()
Text(pseudo)
.fontWeight(.medium) .fontWeight(.medium)
.padding(.leading, 5) .padding(.leading, 5)
.font(.system(size: 18)) .font(.system(size: 18))
.lineLimit(1) .lineLimit(1)
Spacer() Spacer()
Button(StatusValues.0) { Button("Supprimer") {}
viewModel.toggleFriendStatus(for: user, isRequest: isRequest) .frame(width: 90, height: 30)
} .foregroundColor(AllInColors.grey400Color)
.minimumScaleFactor(0.3) .font(.system(size: 14))
.lineLimit(2) .background(AllInColors.componentBackgroundColor)
.frame(width: 90, height: 30) .cornerRadius(5)
.foregroundColor(StatusValues.1)
.font(.system(size: 14))
.background(StatusValues.2)
.cornerRadius(5)
if(isRequest){
Button{
viewModel.declineRequest(username: user.username)
}label: {
Image(systemName: "xmark").foregroundColor(.gray)
}.padding([.leading], 25)
}
} }
.padding([.trailing,.leading], 25) .padding([.trailing,.leading], 25)
} }
} }
struct Friend_Previews: PreviewProvider {
static var previews: some View {
Friend(image: "https://picsum.photos/536/354", pseudo: "Lucas")
}
}

@ -12,21 +12,17 @@ struct Menu: View {
@Inject var authService: IAuthService @Inject var authService: IAuthService
let parameters: [(String, String, String, String)] = [
("videoGameImage", String(localized: "drawer_create_a_bet"), String(localized: "drawer_create_a_bet_subtitle"), "CreationBet"),
("globeImage", String(localized: "drawer_public_bets"), String(localized: "drawer_public_bets_subtitle"), "Bet"),
("moneyImage", String(localized: "drawer_current_bets"), String(localized: "drawer_current_bets_subtitle"), "Current"),
("eyesImage", String(localized: "drawer_bet_history"), String(localized: "drawer_bet_history_subtitle"),"Historic"),
("friendsImage", String(localized: "drawer_friends"), String(localized: "drawer_friends_subtitle"), "Friends"),
("rankingImage", String(localized: "drawer_ranking"), String(localized: "drawer_ranking_subtitle"), "Ranking"),
]
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
HStack() { HStack() {
Spacer() Spacer()
VStack(){ VStack(){
UserPicture(picture: AppStateContainer.shared.user?.image, username: (AppStateContainer.shared.user?.username)!,size: 100) Image("defaultUserImage")
.resizable()
.scaledToFit()
.frame(width: 100, height: 100)
.cornerRadius(180)
Text(AppStateContainer.shared.user?.username.capitalized ?? "") Text(AppStateContainer.shared.user?.username.capitalized ?? "")
.fontWeight(.medium) .fontWeight(.medium)
.font(.system(size: 17)) .font(.system(size: 17))
@ -39,31 +35,31 @@ struct Menu: View {
HStack(spacing: 30) { HStack(spacing: 30) {
Spacer() Spacer()
VStack(){ VStack(){
Text(AppStateContainer.shared.user?.bestWin ?? 0, format: .number) Text("114")
.fontWeight(.heavy) .fontWeight(.heavy)
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(.white) .foregroundColor(.white)
Text(String(localized: "drawer_bets")) Text("Bets")
.fontWeight(.regular) .fontWeight(.regular)
.font(.system(size: 12)) .font(.system(size: 12))
.foregroundColor(AllInColors.grey600Color) .foregroundColor(AllInColors.grey600Color)
} }
VStack(){ VStack(){
Text(AppStateContainer.shared.user!.bestWin, format: .number) Text("343")
.fontWeight(.heavy) .fontWeight(.heavy)
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(.white) .foregroundColor(.white)
Text(String(localized: "drawer_best_win")) Text("Meilleur gain")
.fontWeight(.regular) .fontWeight(.regular)
.font(.system(size: 12)) .font(.system(size: 12))
.foregroundColor(AllInColors.grey600Color) .foregroundColor(AllInColors.grey600Color)
} }
VStack(){ VStack(){
Text(AppStateContainer.shared.user!.nbFriends, format: .number) Text("5")
.fontWeight(.heavy) .fontWeight(.heavy)
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundColor(.white) .foregroundColor(.white)
Text(String(localized: "drawer_nb_friends")) Text("Amis")
.fontWeight(.regular) .fontWeight(.regular)
.font(.system(size: 12)) .font(.system(size: 12))
.foregroundColor(AllInColors.grey600Color) .foregroundColor(AllInColors.grey600Color)
@ -72,40 +68,64 @@ struct Menu: View {
} }
.padding(.bottom, 15) .padding(.bottom, 15)
ForEach(0..<parameters.count, id: \.self) { index in NavigationLink(destination: MainView(page: "CreationBet").navigationBarBackButtonHidden(true))
NavigationLink(destination: MainView(page: parameters[index].3).navigationBarBackButtonHidden(true)) { {
ParameterMenu(image: parameters[index].0, title: parameters[index].1, description: parameters[index].2) ParameterMenu(image: "videoGameImage", title: "CREER UN BET", description: "Créez un nouveau BET et faites participer vos amis.")
.padding([.leading, .trailing], 13) .padding([.leading,.trailing], 13)
}
NavigationLink(destination: MainView(page: "Historic").navigationBarBackButtonHidden(true))
{
ParameterMenu(image: "eyesImage", title: "HISTORIQUE DES BETS", description: "Consultez vos paris en cours et terminés.")
.padding([.leading,.trailing], 13)
}
NavigationLink(destination: MainView(page: "Friends").navigationBarBackButtonHidden(true))
{
ParameterMenu(image: "friendsImage", title: "AMIS", description: "Défiez vos porches en les ajoutant en amis.")
.padding([.leading,.trailing], 13)
}
VStack {
NavigationLink(destination: MainView(page: "Bet").navigationBarBackButtonHidden(true))
{
ParameterMenu(image: "moneyImage", title: "BET EN COURS", description: "Gérez vos bets et récompensez les gagnants.")
.padding([.leading,.trailing], 13)
}
NavigationLink(destination: MainView(page: "Ranking").navigationBarBackButtonHidden(true))
{
ParameterMenu(image: "rankingImage", title: "CLASSEMENT", description: "Consultez votre classement parmis vos amis.")
.padding([.leading,.trailing], 13)
} }
} }
NavigationLink(destination: MainView(page: "Current").navigationBarBackButtonHidden(true))
{
ParameterMenu(image: "eyesImage", title: "BETS EN COURS", description: "Consultez vos paris en cours.")
.padding([.leading,.trailing], 13)
}
HStack { HStack {
Spacer() Spacer()
Button { Button {
authService.logout() authService.logout()
} label: { } label: {
Text("generic_logout") Text("Deconnexion")
.foregroundColor(.white) .foregroundColor(.white)
} }
Spacer() Spacer()
} }
Spacer() Spacer()
NavigationLink(destination: MainView(page: "Profile") Image("gearIcon")
.navigationBarBackButtonHidden(true)) .resizable()
{ .frame(width: 30, height: 30)
Image("gearIcon") .padding([.leading,.bottom], 20)
.resizable()
.frame(width: 30, height: 30)
.padding([.leading,.bottom], 20)
}
} }
.frame(maxWidth: .infinity,alignment: .leading) .frame(maxWidth: .infinity,alignment: .leading)
.background(AllInColors.primaryColor) .background(AllInColors.primaryColor)
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)
.onAppear {
authService.refreshAuthentication()
}
} }
} }

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

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

@ -15,8 +15,6 @@ struct ParticipateButton: View {
var bet: Bet? var bet: Bet?
var isDisabled: Bool { var isDisabled: Bool {
guard bet?.author != AppStateContainer.shared.user?.username else { return true }
if let betType = bet?.status { if let betType = bet?.status {
switch betType { switch betType {
case .inProgress: case .inProgress:
@ -34,7 +32,7 @@ struct ParticipateButton: View {
isOpen = true isOpen = true
isParticapatedOpen = true isParticapatedOpen = true
} label: { } label: {
Text("bet_participate") Text("Participer")
.font(.system(size: 27)) .font(.system(size: 27))
.fontWeight(.semibold) .fontWeight(.semibold)
.frame(maxWidth: .infinity).padding(10) .frame(maxWidth: .infinity).padding(10)
@ -44,7 +42,7 @@ struct ParticipateButton: View {
case true: case true:
AllInColors.grey700Color.frame(width: 170) AllInColors.grey700Color.frame(width: 170)
.mask( .mask(
Text("bet_participate") Text("Participer")
.font(.system(size: 27)) .font(.system(size: 27))
.fontWeight(.semibold) .fontWeight(.semibold)
.frame(maxWidth: .infinity).padding(10) .frame(maxWidth: .infinity).padding(10)
@ -52,7 +50,7 @@ struct ParticipateButton: View {
case false: case false:
AllInColors.primaryGradient.frame(width: 170) AllInColors.primaryGradient.frame(width: 170)
.mask( .mask(
Text("bet_participate") Text("Participer")
.font(.system(size: 27)) .font(.system(size: 27))
.fontWeight(.semibold) .fontWeight(.semibold)
.frame(maxWidth: .infinity).padding(10) .frame(maxWidth: .infinity).padding(10)

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

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

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

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

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

@ -6,14 +6,8 @@
// //
import SwiftUI import SwiftUI
import Model
struct TrendingBetCard: View { struct TrendingBetCard: View {
var bet: Bet
@State var showDetails: Bool = false
@State var showParticipate: Bool = false
var body: some View { var body: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
HStack { HStack {
@ -21,12 +15,12 @@ struct TrendingBetCard: View {
.resizable() .resizable()
.frame(width: 15, height: 15, alignment: .leading) .frame(width: 15, height: 15, alignment: .leading)
Text("bet_popular") Text("Populaire")
.textStyle(weight: .medium, color: AllInColors.pinkAccentColor, size: 17) .textStyle(weight: .medium, color: AllInColors.pinkAccentColor, size: 17)
} }
.padding([.leading, .top], 10) .padding([.leading, .top], 10)
Text(bet.theme) Text("Emre va réussir son TP de CI/CD mercredi?")
.textStyle(weight: .heavy, color: .white, size: 17) .textStyle(weight: .heavy, color: .white, size: 17)
.frame(height: 47) .frame(height: 47)
.multilineTextAlignment(.leading) .multilineTextAlignment(.leading)
@ -39,7 +33,7 @@ struct TrendingBetCard: View {
Text("12") Text("12")
.textStyle(weight: .bold, color: AllInColors.pinkAccentColor, size: 14) .textStyle(weight: .bold, color: AllInColors.pinkAccentColor, size: 14)
Text("bet_players_format") Text("joueurs")
.textStyle(weight: .regular, color: .white, size: 14) .textStyle(weight: .regular, color: .white, size: 14)
.padding([.leading], 2) .padding([.leading], 2)
@ -47,7 +41,7 @@ struct TrendingBetCard: View {
.textStyle(weight: .bold, color: AllInColors.pinkAccentColor, size: 14) .textStyle(weight: .bold, color: AllInColors.pinkAccentColor, size: 14)
.padding([.leading], 10) .padding([.leading], 10)
Text("bet_points_at_stake_format") Text("points misés")
.textStyle(weight: .regular, color: .white, size: 14) .textStyle(weight: .regular, color: .white, size: 14)
.padding([.leading], 2) .padding([.leading], 2)
} }
@ -62,24 +56,11 @@ struct TrendingBetCard: View {
.stroke(AllInColors.primaryGradient, lineWidth: 5) .stroke(AllInColors.primaryGradient, lineWidth: 5)
) )
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous)) .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
.onTapGesture {
showDetails.toggle()
}
.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, isModalParticipated: $showParticipate, id: bet.id)
}
} }
} }
struct TrendingBetCard_Previews: PreviewProvider { struct TrendingBetCard_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
TrendingBetCard(bet: BinaryBet(theme: "Football - Finale de la Ligue des Champions", TrendingBetCard()
phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.",
endRegisterDate: Date().addingTimeInterval(86400),
endBetDate: Date().addingTimeInterval(172800),
isPrivate: true,
status: .inProgress,
invited: [],
author: "Imri"))
} }
} }

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

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

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

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

@ -21,11 +21,7 @@ struct ContentView: View {
VStack { VStack {
if loggedState.connectedUser { if loggedState.connectedUser {
NavigationView { NavigationView {
if let name = QuickAction.selectedAction?.userInfo?["name"] as? String { MainView(page: "Bet")
MainView(page: name)
} else {
MainView(page: "Bet")
}
} }
.navigationViewStyle(StackNavigationViewStyle()) .navigationViewStyle(StackNavigationViewStyle())
} else { } else {

@ -1,25 +0,0 @@
//
// Delegates.swift
// AllIn
//
// Created by Emre on 22/02/2024.
//
import UIKit
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
if let selectedAction = options.shortcutItem {
QuickAction.selectedAction = selectedAction
}
let sceneConfiguration = UISceneConfiguration(name: "Quick Action Scene", sessionRole: connectingSceneSession.role)
sceneConfiguration.delegateClass = QuickActionSceneDelegate.self
return sceneConfiguration
}
}
class QuickActionSceneDelegate: UIResponder, UIWindowSceneDelegate {
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
QuickAction.selectedAction = shortcutItem
}
}

@ -1,44 +0,0 @@
//
// QuickAction.swift
// AllIn
//
// Created by Emre on 22/02/2024.
//
import UIKit
enum QuickAction {
static var selectedAction: UIApplicationShortcutItem?
static var homeuserInfo: [String : NSSecureCoding] {
["name" : "Bet" as NSSecureCoding]
}
static var createuserInfo: [String : NSSecureCoding] {
["name" : "CreationBet" as NSSecureCoding]
}
static var frienduserInfo: [String : NSSecureCoding] {
["name" : "Friends" as NSSecureCoding]
}
static var rankuserInfo: [String : NSSecureCoding] {
["name" : "Ranking" as NSSecureCoding]
}
static var allShortcutItems: [UIApplicationShortcutItem] = {
var shortcuts: [UIApplicationShortcutItem] = []
if AppStateContainer.shared.loggedState.connectedUser {
shortcuts.append(UIApplicationShortcutItem(type: "home", localizedTitle: "Coins : " + String(AppStateContainer.shared.user?.nbCoins ?? 0), localizedSubtitle: "", icon: UIApplicationShortcutIcon(templateImageName: "allCoinBlackIcon"), userInfo: homeuserInfo))
}
shortcuts.append(contentsOf: [
UIApplicationShortcutItem(type: "create", localizedTitle: "Créer un pari", localizedSubtitle: "", icon: UIApplicationShortcutIcon(systemImageName: "pencil.circle"), userInfo: createuserInfo),
UIApplicationShortcutItem(type: "friend", localizedTitle: "Voir mes amis", localizedSubtitle: "", icon: UIApplicationShortcutIcon(systemImageName: "person.2.square.stack"), userInfo: frienduserInfo),
UIApplicationShortcutItem(type: "ranking", localizedTitle: "Classement", localizedSubtitle: "Où en suis-je ?", icon: UIApplicationShortcutIcon(systemImageName: "rosette"), userInfo: rankuserInfo)
])
return shortcuts
}()
}

@ -35,9 +35,6 @@ struct AllInColors {
static let pink200 = Color("Pink200") static let pink200 = Color("Pink200")
static let pink100 = Color("Pink100") static let pink100 = Color("Pink100")
// Profile
static let secondaryTextColor = Color("SecondaryTextColor")
// Others // Others
static let backgroundColor = Color("BackgroundColor") static let backgroundColor = Color("BackgroundColor")
static let darkBlueColor = Color("DarkBlueColor") static let darkBlueColor = Color("DarkBlueColor")
@ -77,12 +74,6 @@ struct AllInColors {
endPoint: .trailing endPoint: .trailing
) )
static let BlueBetLineGradiant = LinearGradient(
gradient: Gradient(colors: [AllInColors.blue200, AllInColors.blueAccentColor]),
startPoint: .leading,
endPoint: .trailing
)
static let PinkBetGradiant = LinearGradient( static let PinkBetGradiant = LinearGradient(
gradient: Gradient(colors: [AllInColors.pink100, AllInColors.pink200]), gradient: Gradient(colors: [AllInColors.pink100, AllInColors.pink200]),
startPoint: .leading, startPoint: .leading,

@ -1,194 +0,0 @@
/*
Localizable.strings
AllInApp
Created by Emre on 15/05/2024.
*/
/// Core
"generic_username" = "Username";
"generic_email" = "Email";
"generic_password" = "Password";
"generic_login" = "Login";
"generic_logout" = "Logout";
"generic_already_have_account" = "Already have an account ?";
"generic_register" = "Register";
"generic_validate" = "Validate";
"generic_ok" = "OK";
"generic_error" = "Error";
"generic_in_waiting" = "In waiting";
"generic_search" = "Search";
"generic_add" = "Add";
"generic_acccept"="Accept";
"generic_decline"="Decline";
"generic_delete" = "Delete";
"generic_stake" = "Stake";
"network_error_text" = "Make sure to be properly connected to the network then try again.";
/// Bet type
"bet_type_binary" = "Yes / No";
"bet_type_match" = "Sport match";
"bet_type_custom" = "Custom answers";
/// Field error
"field_error_mandatory" = "This field is mandatory.";
"field_error_not_identical" = "The fields are not identical.";
"field_error_bad_email" = "Please enter a valid email.";
/// Drawer
"drawer_bets" = "Bets";
"drawer_best_win" = "Best win";
"drawer_nb_friends" = "Friends";
"drawer_friends" = "FRIENDS";
"drawer_friends_subtitle" = "Challenge your folks by adding them as friends.";
"drawer_public_bets" = "PARTICIPATE";
"drawer_public_bets_subtitle" = "Browse the most popular bets of the moment.";
"drawer_create_a_bet" = "NEW BET";
"drawer_create_a_bet_subtitle" = "Create a net bet and get your friends participating.";
"drawer_bet_history" = "HISTORY";
"drawer_bet_history_subtitle" = "View your current and finished bets.";
"drawer_current_bets" = "MY PARTICIPATIONS";
"drawer_current_bets_subtitle" = "Manage your bets and reward the winners.";
"drawer_ranking" = "RANKING";
"drawer_ranking_subtitle" = "Check your ranking among your friends.";
/// Welcome Page
"welcome_title" = "Welcome to,";
"welcome_subtitle" = "Collect your Allcoins and come bet with your friend to prove who\'s best.";
"welcome_join" = "Join";
/// Register Page
"register_hello" = "Hello,";
"register_hello %@" = "Hello %@,";
"register_title" = "We need this!";
"register_subtitle" = "Don\'t worry it\'s fast.";
"register_error_title" = "Error saving";
"register_error_content" = "Registration failed. Try Again.";
"register_confirm_password" = "Confirm password";
"register_already_used" = "Email or nickname already used.";
/// Login Page
"login_title" = "Welcome back !";
"login_subtitle" = "We missed you.";
"login_error_title" = "Connection error";
"login_error_content" = "Failed to login. Please try again.";
"login_no_account" = "Don't have an account ?";
"login_forgot_password" = "Forgot password ?";
"login_bad_credentials" = "Incorrect login or password.";
/// Bet Creation Page
"bet_creation_theme_tooltip" = "Usually a common name describing the overall theme of the bet for reference..";
"bet_creation_phrase_tooltip" = "Generally the question the participants will answer to.";
"bet_creation_register_tooltip" = "After this date, nobody will be able to register anymore.";
"bet_creation_bet_end_tooltip" = "After this date, the result will be announced.";
"bet_creation_privacy_tooltip" = "Determines who will be able to see the bet.";
"bet_creation_question" = "Question";
"bet_creation_answer" = "Answer";
"bet_creation_publish" = "Publish the bet";
"bet_creation_theme" = "Theme";
"bet_creation_theme_placeholder" = "Studies, sports, party…";
"bet_creation_bet_phrase" = "Bet phrase";
"bet_creation_bet_phrase_placeholder" = "Will David be missing this Monday in class ?";
"bet_creation_end_registration_date" = "Registration end date";
"bet_creation_end_bet_date" = "Bet end date";
"bet_creation_bet_privacy" = "Bet privacy";
"bet_creation_friends_available_format" = "friends available";
"bet_creation_public_bottom_text_1" = "Your BET will be visible by all the users.";
"bet_creation_public_bottom_text_2" = "Everyone will be able to join the BET.";
"bet_creation_private_bottom_text_1" = "Your BET will only be visible by your friends.";
"bet_creation_private_bottom_text_2" = "Only your friends will be able to join the BET.";
"bet_creation_bottom_text_3" = "You can invite friends at any moment during the registration period.";
"bet_creation_yes_no_bottom_text_1" = "The participants will have to respond with either YES or NO.";
"bet_creation_yes_no_bottom_text_2" = "No other answer will be accepted.";
"bet_creation_custom_bottom_text_1" = "You are going to fill in the different answers available in this bet.";
"bet_creation_custom_bottom_text_2" = "Be careful to be clear and avoid any uncertainties";
"bet_creation_error" = "Error while creating the bet.";
"bet_creation_success_message" = "Bet created !";
"bet_creation_response_title" = "Response title";
"bet_creation_max_answers %lld" = "%lld more max.";
"bet_creation_error_past_date" = "The registration end date must be later than the current date.";
"bet_creation_error_date_order" = "The betting end date must be later than the registration end date.";
/// Bet page
"bet_popular" = "Popular";
"bet_public" = "Public";
"bet_private" = "Private";
"bet_invitation" = "Invitation";
"bet_current" = "Current";
"bet_finished" = "Finished";
"bet_starting" = "Starting on";
"bet_started" = "Started on";
"bet_ends" = "Ends on";
"bet_ended" = "Ended on";
"bet_participate" = "Participate";
"bet_proposed_by_format %@" = "Proposed by %@";
"bet_proposed_by_format" = "Proposed by";
"bet_players_waiting_format %@" = "%@ players waiting";
"bet_players_format" = "players";
"bet_points_at_stake_format" = "points at stake";
/// Bet status
"bet_status_finished" = "Finished !";
"bet_status_in_progress" = "In progress…";
"bet_status_waiting" = "Waiting…";
"bet_status_unavailable" = "Status unavailable";
"bet_status_cancelled" = "Cancelled";
"bet_status_place_your_bets" = "Place your bets";
"bet_status_participants_list" = "Participants";
"bet_status_details_drawer" = "Details";
"participation_possible_winnings" = "Possible winnings";
"bet_status_stake" = "Gambled";
/// Bet history
"bet_history_current_title" = "Current";
"bet_history_title" = "History";
/// Bet confirmation
"bet_confirmation_text" = "This bet has now ended. You may now distribute the winnings by selecting the right answer.";
"bet_confirmation_choose_response" = "Please select the final answer :";
/// Ranking
"ranking_title" = "Ranking";
/// Friends
"friends_title" = "Friends";
"friends_request_sent" = "Request sent";
"friends_request"= "Friends Request";
/// Daily reward
"daily_reward_title" = "Daily reward";
"daily_reward_subtitle" = "Your daily reward is unlocked every day at 00:00 UTC and allows you to get between 10 and 150 Allcoins.";
/// Notification
"notification_title_end_bet_date" = "Who will be the winners?";
"notification_subtitle_end_bet_date %@" = "The %@ bet has reached its deadline. Go to the app to enter the winning answer.";
/// Empty Views
"empty_ranking_title" = "It's a bit empty around here";
"empty_ranking_explain" = "Add some friends to display them in the leaderboard";
"empty_bets_title"= "No bet matches your search";
"empty_friends_title" = "You don't have any friends yet";
"empty_friends_explain" = "Add them from this screen";
/// Error Messages
"error_title" = "Error: Failed to Load Content.";
"error_message" = "The content you are trying to load could not be retrieved. Please check your internet connection and try again";

@ -1,194 +0,0 @@
/*
Localizable.strings
AllInApp
Created by Emre on 15/05/2024.
*/
/// Core
"generic_username" = "Pseudo";
"generic_email" = "Email";
"generic_password" = "Mot de passe";
"generic_login" = "Se connecter";
"generic_logout" = "Déconnexion";
"generic_already_have_account" = "Tu as déjà un compte ?";
"generic_register" = "S'inscrire";
"generic_validate" = "Valider";
"generic_ok" = "OK";
"generic_error" = "Erreur";
"generic_in_waiting" = "En attente";
"generic_search" = "Rechercher";
"generic_add" = "Ajouter";
"generic_acccept"="Accepter";
"generic_decline"="Decliner";
"generic_delete" = "Supprimer";
"generic_stake" = "Mise";
"network_error_text" = "Assurez-vous d\'être bien connecté au réseau puis réessayez.";
/// Bet type
"bet_type_binary" = "Oui / Non";
"bet_type_match" = "Match sportif";
"bet_type_custom" = "Réponses personnalisées";
/// Field error
"field_error_mandatory" = "Ce champ est obligatoire.";
"field_error_not_identical" = "Les champs ne sont pas identiques.";
"field_error_bad_email" = "Veuillez saisir un email valide.";
/// Drawer
"drawer_bets" = "Bets";
"drawer_best_win" = "Meilleur gain";
"drawer_nb_friends" = "Amis";
"drawer_friends" = "AMIS";
"drawer_friends_subtitle" = "Défiez vos proches en les ajoutant en amis.";
"drawer_public_bets" = "PARTICIPER";
"drawer_public_bets_subtitle" = "Parcourez les bets les plus populaires du moment.";
"drawer_create_a_bet" = "NOUVEAU BET";
"drawer_create_a_bet_subtitle" = "Créez un nouveau bet et faites participer vos amis.";
"drawer_bet_history" = "HISTORIQUE";
"drawer_bet_history_subtitle" = "Consultez vos paris en cours et terminés.";
"drawer_current_bets" = "MES PARTICIPATIONS";
"drawer_current_bets_subtitle" = "Gérez vos bets et récompensez les gagnants.";
"drawer_ranking" = "CLASSEMENT";
"drawer_ranking_subtitle" = "Consultez votre classement parmis vos amis.";
/// Welcome Page
"welcome_title" = "Bienvenue sur,";
"welcome_subtitle" = "Récupère tes Allcoins et viens parier avec tes amis pour prouver qui est le meilleur.";
"welcome_join" = "Rejoindre";
/// Register Page
"register_hello" = "Bonjour";
"register_hello %@" = "Bonjour %@,";
"register_title" = "On a besoins de ça!";
"register_subtitle" = "Promis c\'est rapide.";
"register_error_title" = "Erreur lors de l'enregistrement";
"register_error_content" = "L'enregistrement a échoué. Veuillez réessayer.";
"register_confirm_password" = "Confirmation du mot de passe";
"register_already_used" = "Email ou pseudo déjà utilisé.";
/// Login Page
"login_title" = "Te revoilà !";
"login_subtitle" = "Bon retour parmis nous tu nous as manqué !";
"login_error_title" = "Erreur de connexion";
"login_error_content" = "La connexion a échoué. Veuillez réessayer.";
"login_no_account" = "Pas encore inscrit ?";
"login_forgot_password" = "Mot de passe oublié ?";
"login_bad_credentials" = "Login ou mot de passe incorrects.";
/// Bet Creation Page
"bet_creation_theme_tooltip" = "Généralement un nom commun décrivant le thème global du pari pour servir de référence.";
"bet_creation_phrase_tooltip" = "Généralement la question à laquelle les participants devront répondre.";
"bet_creation_register_tooltip" = "Après cette date, plus personne ne pourra s\'inscrire.";
"bet_creation_bet_end_tooltip" = "Après cette date, les résultats seront annoncés.";
"bet_creation_privacy_tooltip" = "Détermine qui pourra voir le bet.";
"bet_creation_question" = "Question";
"bet_creation_answer" = "Réponse";
"bet_creation_publish" = "Publier le bet";
"bet_creation_theme" = "Thème";
"bet_creation_theme_placeholder" = "Études, sport, soirée…";
"bet_creation_bet_phrase" = "Phrase du BET";
"bet_creation_bet_phrase_placeholder" = "David sera-il absent lundi matin en cours ?";
"bet_creation_end_registration_date" = "Date de fin des inscriptions";
"bet_creation_end_bet_date" = "Date de fin du BET";
"bet_creation_bet_privacy" = "Confidentialité du bet";
"bet_creation_friends_available_format" = "amis disponibles";
"bet_creation_public_bottom_text_1" = "Votre BET sera visible par tous les utilisateurs.";
"bet_creation_public_bottom_text_2" = "Tout le monde pourra rejoindre le BET.";
"bet_creation_private_bottom_text_1" = "Votre BET sera visible uniquement par vos amis.";
"bet_creation_private_bottom_text_2" = "Seulement vos amis pourront rejoindre le BET.";
"bet_creation_bottom_text_3" = "Vous pourrez inviter des amis à tout moment pendant la période dinscription.";
"bet_creation_yes_no_bottom_text_1" = "Les utilisateurs devront répondre au pari avec OUI ou NON.";
"bet_creation_yes_no_bottom_text_2" = "Aucune autre réponse ne sera acceptée.";
"bet_creation_custom_bottom_text_1" = "Vous allez renseigner les différentes réponses disponibles dans ce pari.";
"bet_creation_custom_bottom_text_2" = "Faites attention a etre claire et éviter toutes incertitudes";
"bet_creation_error" = "Erreur lors de la création du bet.";
"bet_creation_success_message" = "Bet créé !";
"bet_creation_response_title" = "Intitulé de réponse";
"bet_creation_max_answers %lld" = "encore %lld max.";
"bet_creation_error_past_date" = "La date de fin des inscriptions doit être ultérieure à la date actuelle.";
"bet_creation_error_date_order" = "La date de fin des paris doit être ultérieure à la date de fin des inscriptions.";
/// Bet page
"bet_popular" = "Populaire";
"bet_public" = "Public";
"bet_private" = "Privé";
"bet_invitation" = "Invitation";
"bet_current" = "En cours";
"bet_finished" = "Terminés";
"bet_starting" = "Commence le";
"bet_started" = "A commencé le";
"bet_ends" = "Prend fin le";
"bet_ended" = "A pris fin le";
"bet_participate" = "Participer";
"bet_proposed_by_format %@" = "Proposé par %@";
"bet_proposed_by_format" = "Proposé par";
"bet_players_waiting_format %@" = "%@ joueurs en attente";
"bet_players_format" = "joueurs";
"bet_points_at_stake_format" = "points en jeu";
/// Bet status
"bet_status_finished" = "Terminé !";
"bet_status_in_progress" = "En cours…";
"bet_status_waiting" = "En attente…";
"bet_status_unavailable" = "Statut indisponible";
"bet_status_cancelled" = "Annulé";
"bet_status_place_your_bets" = "Faites vos paris";
"bet_status_participants_list" = "Liste des participants";
"bet_status_details_drawer" = "Détails";
"participation_possible_winnings" = "Gains possibles";
"bet_status_stake" = "Pariés";
/// Bet history
"bet_history_current_title" = "En cours";
"bet_history_title" = "Historique";
/// Bet confirmation
"bet_confirmation_text" = "Ce bet est arrivé à la date de fin. Vous devez à présent distribuer les gains en validant le pari gagnant.";
"bet_confirmation_choose_response" = "Veuillez choisir la réponse finale :";
/// Ranking
"ranking_title" = "Classement";
/// Friends
"friends_title" = "Amis";
"friends_request_sent" = "Requête envoyée";
"friends_request"= "Requêtes d'amis";
/// Daily reward
"daily_reward_title" = "Récompense quotidienne";
"daily_reward_subtitle" = "Votre récompense quotidienne est débloquée tous les jours à 00:00 UTC et vous permets dobtenir entre 10 et 150 Allcoins.";
/// Notification
"notification_title_end_bet_date" = "Qui seront les vainqueurs ?";
"notification_subtitle_end_bet_date %@" = "Le pari %@ a atteint sa date limite. Rendez-vous dans l'application pour renseigner la réponse gagnante.";
/// Empty Views
"empty_ranking_title" = "Cest un peu vide par ici";
"empty_ranking_explain" = "Ajoutez des amis pour les afficher dans le classement";
"empty_bets_title"= "Aucun Bet ne correspond à votre recherche";
"empty_friends_title" = "Vous navez pas encore damis";
"empty_friends_explain" = "Ajoutez les depuis cet écran";
/// Error Messages
"error_title" = "Erreur : Échec du chargement du contenu.";
"error_message" = "Le contenu que vous essayez de charger n'a pas pu être récupéré. Veuillez vérifier votre connexion internet et réessayer.";

@ -10,7 +10,6 @@ import Model
import DependencyInjection import DependencyInjection
import Api import Api
import StubLib import StubLib
import WidgetKit
class AuthService: IAuthService { class AuthService: IAuthService {
@ -20,12 +19,12 @@ class AuthService: IAuthService {
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let json = [ let json = [
"login": login.lowercased(), "login": login.lowercased(),
"password": password, "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 URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in
print("ALLIN: Process LOGIN") print("ALLIN: Process LOGIN")
@ -53,10 +52,10 @@ class AuthService: IAuthService {
}.resume() }.resume()
} }
} }
func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) { func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) {
let url = URL(string: Config.allInApi + "users/register")! let url = URL(string: Config.allInApi + "/users/register")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
@ -100,7 +99,7 @@ class AuthService: IAuthService {
guard let token = AppStateContainer.shared.authenticationRefresh else { guard let token = AppStateContainer.shared.authenticationRefresh else {
return return
} }
let url = URL(string: Config.allInApi + "users/token")! let url = URL(string: Config.allInApi + "users/token")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -110,11 +109,13 @@ class AuthService: IAuthService {
URLSession.shared.dataTask(with: request) { data, response, error in URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data, if let data = data,
let httpResponse = response as? HTTPURLResponse { let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200, let user = try? JSONDecoder().decode(User.self, from: data) { if httpResponse.statusCode == 200 {
AppStateContainer.shared.user = user if let userJson = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
AppStateContainer.shared.loggedState.connectedUser = true let user = User.mapUser(from: userJson) {
WidgetCenter.shared.reloadAllTimelines() AppStateContainer.shared.user = user
self.initManagerVM(token: token) AppStateContainer.shared.loggedState.connectedUser = true
self.initManagerVM(token: token)
}
} else { } else {
AppStateContainer.shared.authenticationRefresh = nil AppStateContainer.shared.authenticationRefresh = nil
} }
@ -130,14 +131,16 @@ class AuthService: IAuthService {
request.httpMethod = "GET" request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, response, error in URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data, if let data = data,
let httpResponse = response as? HTTPURLResponse { let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200, let user = try? JSONDecoder().decode(User.self, from: data) { if httpResponse.statusCode == 200 {
AppStateContainer.shared.user = user if let userJson = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
WidgetCenter.shared.reloadAllTimelines() let user = User.mapUser(from: userJson) {
completion(httpResponse.statusCode) completion(httpResponse.statusCode)
AppStateContainer.shared.user = user
}
} else { } else {
completion(httpResponse.statusCode) completion(httpResponse.statusCode)
} }
@ -148,14 +151,12 @@ class AuthService: IAuthService {
} }
private func initManagerVM(token: String) { private func initManagerVM(token: String) {
DependencyInjection.shared.addSingleton(Manager.self, Manager(withBetDataManager: BetApiManager(withUserToken: token, andApiUrl: Config.allInApi), withUserDataManager: UserApiManager(withUserToken: token, andApiUrl: Config.allInApi))) DependencyInjection.shared.addSingleton(Manager.self, Manager(withBetDataManager: BetApiManager(withUserToken: token), withUserDataManager: UserApiManager(withUserToken: token)))
} }
public func logout() { public func logout() {
AppStateContainer.shared.authenticationRefresh = nil AppStateContainer.shared.authenticationRefresh = nil
AppStateContainer.shared.loggedState.connectedUser = false AppStateContainer.shared.loggedState.connectedUser = false
AppStateContainer.shared.notificationState.removeAllNotifications()
WidgetCenter.shared.reloadAllTimelines()
} }
} }

@ -1,50 +0,0 @@
//
// NotificationService.swift
// AllIn
//
// Created by Emre on 22/02/2024.
//
import UserNotifications
struct NotificationItem {
var title: String
var content: String
var interval: TimeInterval
}
class NotificationService: ObservableObject {
@Published var notifications: [NotificationItem] = []
func scheduleNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
print("Permission for notifications granted.")
} else {
print("Permission for notifications denied.")
}
}
}
func loadNotifications() {
for notification in notifications {
scheduleNotification(with: notification)
}
}
func removeAllNotifications() {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
}
func scheduleNotification(with item: NotificationItem) {
let content = UNMutableNotificationContent()
content.title = item.title
content.body = item.content
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: item.interval, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
}
}

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

@ -13,62 +13,25 @@ import Combine
class BetViewModel: ObservableObject { class BetViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Inject var authService: IAuthService
@Published var popularBet: Bet?
@Published private(set) var bets: [Bet] = [] @Published private(set) var bets: [Bet] = []
@Published var betsOver: [BetDetail] = [] @Published var betsOver: [BetDetail] = []
@Published var betsWon: [BetResultDetail] = [] @Published var showingSheet: Bool = false
@Published var showingSheetOver: Bool = false
@Published var showingSheetWon: Bool = false
@Published var filters: Set<BetFilter> = [] {
didSet {
getItems()
}
}
init() { init() {
getItems() getItems()
getPopularBet()
getBetsOver()
getBetsWon()
} }
func getItems() { func getItems() {
manager.getBets(withIndex: 0, withCount: 20, filters: Array(filters)) { bets in manager.getBets(withIndex: 0, withCount: 20) { bets in
DispatchQueue.main.async { self.bets = bets
self.bets = bets
}
} }
}
func getBetsOver() {
manager.getBetsOver() { bets in manager.getBetsOver() { bets in
DispatchQueue.main.async { self.betsOver = bets
self.betsOver = bets if !self.betsOver.isEmpty {
if !self.betsOver.isEmpty { self.showingSheet = true
self.showingSheetOver = true
}
}
}
}
func getBetsWon() {
manager.getBetsWon() { bets in
DispatchQueue.main.async {
self.betsWon = bets
if !self.betsWon.isEmpty {
self.showingSheetWon = true
self.authService.refreshAuthentication()
}
}
}
}
func getPopularBet() {
manager.getPopularBet() { bet in
DispatchQueue.main.async {
self.popularBet = bet
} }
print(bets)
} }
} }
} }

@ -15,127 +15,73 @@ class CreationBetViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Published var theme: String = "" @Published var theme: String = ""
@Published var description: String = "" @Published var description: String = ""
@Published var isPrivate = false { @Published var isPublic = true
didSet {
invited.removeAll()
}
}
@Published var endRegisterDate = Date() @Published var endRegisterDate = Date()
@Published var endBetDate = Date() @Published var endBetDate = Date()
@Published var betAdded = false @Published var betAdded = false
@Published var selectedTypeBet = 0 { @Published var selectedOption = 0
didSet {
values.removeAll()
groupedItems.removeAll()
response = ""
}
}
@Published var values: [String] = []
@Published var invited: Set<String> = []
@Published var themeFieldError: String? @Published var themeFieldError: String?
@Published var descriptionFieldError: String? @Published var descriptionFieldError: String?
@Published var endRegisterDateFieldError: String? @Published var endRegisterDateFieldError: String?
@Published var endBetDateFieldError: String? @Published var endBetDateFieldError: String?
@Published var responsesFieldError: String?
@Published var errorMessage: String? @Published var errorMessage: String?
@Published var showErrorMessage = false @Published var showErrorMessage = false
@Published var friends: [User] = []
let options: [(Int, String, String)] = [
(0, "questionMarkIcon", String(localized: "bet_type_binary")),
(1, "footballIcon", String(localized: "bet_type_match")),
(2, "paintbrushIcon", String(localized: "bet_type_custom"))
]
@Published var response = ""
@Published var groupedItems: [[String]] = [[String]] ()
init() {
getFriends()
}
func getFriends() {
manager.getFriends() { friends in
DispatchQueue.main.async {
self.friends = friends
}
}
}
func create() { func create() {
guard checkAndSetError(forTheme: true, forDescription: true, forEndRegisterDate: true, forEndBetDate: true, forResponse: true) else { guard checkAndSetError(forTheme: true, forDescription: true, forEndRegisterDate: true, forEndBetDate: true) else {
return return
} }
resetAllFieldErrors() resetAllFieldErrors()
if let user = AppStateContainer.shared.user { if let user = AppStateContainer.shared.user {
manager.addBet(bet: toBet(theme: theme, description: description, endRegister: endRegisterDate, endBet: endBetDate, isPrivate: isPrivate, status: .inProgress, creator: user.username, invited: Array(invited), type: selectedTypeBet)) { statusCode in manager.addBet(bet: toBet(theme: theme, description: description, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, status: .inProgress, creator: user, type: selectedOption)) { statusCode in
print(statusCode)
switch statusCode { switch statusCode {
case 201: case 201:
self.betAdded = true self.betAdded = true
let notificationItem = NotificationItem(title: String(localized: "notification_title_end_bet_date"), content: String(localized: "notification_subtitle_end_bet_date \(self.theme)"), interval: self.endBetDate.timeIntervalSinceNow)
AppStateContainer.shared.notificationState.scheduleNotification(with: notificationItem)
default: default:
self.setErrorMessage(errorMessage: String(localized: "network_error_text")) self.setErrorMessage(errorMessage: "Problème de connexion. Veuillez réessayer ultérieurement.")
} }
} }
} }
} }
func checkAndSetError(forTheme checkTheme: Bool, forDescription checkDescription: Bool, forEndRegisterDate checkEndRegisterDate: Bool, forEndBetDate checkEndBetDate: Bool, forResponse checkResponse: Bool) -> Bool { func checkAndSetError(forTheme checkTheme: Bool, forDescription checkDescription: Bool, forEndRegisterDate checkEndRegisterDate: Bool, forEndBetDate checkEndBetDate: Bool) -> Bool {
var newThemeFieldError: String? var newThemeFieldError: String?
var newDescriptionFieldError: String? var newDescriptionFieldError: String?
var newEndRegisterDateFieldError: String? var newEndRegisterDateFieldError: String?
var newEndBetDateFieldError: String? var newEndBetDateFieldError: String?
var newResponsesFieldError: String?
var hasError = false var hasError = false
// Theme // Theme
if checkTheme, theme.isEmpty { if checkTheme, theme.isEmpty {
newThemeFieldError = String(localized: "field_error_mandatory") newThemeFieldError = "Veuillez saisir le thème."
hasError = true hasError = true
} }
// Description // Description
if checkDescription, description.isEmpty { if checkDescription, description.isEmpty {
newDescriptionFieldError = String(localized: "field_error_mandatory") newDescriptionFieldError = "Veuillez saisir la description."
hasError = true hasError = true
} }
// End Register Date // End Register Date
if checkEndRegisterDate, endRegisterDate < Date() { if checkEndRegisterDate, endRegisterDate < Date() {
newEndRegisterDateFieldError = String(localized: "bet_creation_error_past_date") newEndRegisterDateFieldError = "La date de fin des inscriptions doit être ultérieure à la date actuelle."
hasError = true hasError = true
} }
// End Bet Date // End Bet Date
if checkEndBetDate, endBetDate < endRegisterDate { if checkEndBetDate, endBetDate < endRegisterDate {
newEndBetDateFieldError = String(localized: "bet_creation_error_date_order") newEndBetDateFieldError = "La date de fin des paris doit être ultérieure à la date de fin des inscriptions."
hasError = true hasError = true
} }
if checkResponse, selectedTypeBet == 2 {
if values.count < 2 {
newResponsesFieldError = "Il doit y'avoir 2 réponses minimum"
hasError = true
} else {
let uniqueValues = Set(values)
if uniqueValues.count != values.count {
newResponsesFieldError = "Les réponses doivent être uniques"
hasError = true
}
}
}
if !hasError { if !hasError {
// No error // No error
return true return true
@ -146,7 +92,6 @@ class CreationBetViewModel: ObservableObject {
descriptionFieldError = newDescriptionFieldError descriptionFieldError = newDescriptionFieldError
endRegisterDateFieldError = newEndRegisterDateFieldError endRegisterDateFieldError = newEndRegisterDateFieldError
endBetDateFieldError = newEndBetDateFieldError endBetDateFieldError = newEndBetDateFieldError
responsesFieldError = newResponsesFieldError
} }
return false return false
} }
@ -157,7 +102,6 @@ class CreationBetViewModel: ObservableObject {
descriptionFieldError = nil descriptionFieldError = nil
endRegisterDateFieldError = nil endRegisterDateFieldError = nil
endBetDateFieldError = nil endBetDateFieldError = nil
responsesFieldError = nil
} }
} }
@ -166,20 +110,16 @@ class CreationBetViewModel: ObservableObject {
self.errorMessage = errorMessage self.errorMessage = errorMessage
} }
func toBet(theme: String, description: String, endRegister: Date, endBet: Date, isPrivate: Bool, status: BetStatus, creator: String, invited: [String], type: Int) -> Bet { func toBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: User, type: Int) -> Bet {
switch type { switch type {
case 0: case 0:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator) return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
case 1: case 1:
return MatchBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator, nameTeam1: "", nameTeam2: "") return MatchBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "")
case 2: case 2:
var bet = CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator) return CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
for answer in values {
bet.addCustomResponse(answer)
}
return bet
default: default:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator) return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
} }
} }
} }

@ -12,7 +12,7 @@ import Model
class CurrentBetViewModel: ObservableObject { class CurrentBetViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Published private(set) var bets: [BetDetail] = [] @Published private(set) var bets: [BetDetail] = []
init() { init() {
@ -21,8 +21,9 @@ class CurrentBetViewModel: ObservableObject {
func getItems() { func getItems() {
manager.getCurrentBets(withIndex: 0, withCount: 20) { bets in manager.getCurrentBets(withIndex: 0, withCount: 20) { bets in
DispatchQueue.main.async { for bet in bets {
self.bets = bets let betDetail = BetDetail(bet: bet, answers: [AnswerDetail(response: "OUI", totalStakes: 120, totalParticipants: 2, highestStake: 200, odds: 1.2), AnswerDetail(response: "NON", totalStakes: 120, totalParticipants: 2, highestStake: 200, odds: 1.2)], participations: [])
self.bets.append(betDetail)
} }
} }
} }

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

@ -13,101 +13,23 @@ class FriendsViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Published private(set) var users: [User] = []
@Published private(set) var requests: [User] = []
@Published var text: String = "" {
didSet {
if text.isEmpty {
getItems()
} else {
search()
}
}
}
init() { init() {
getItems() getItems()
getRequests()
}
func getItems() {
manager.getFriends() { friends in
DispatchQueue.main.async {
self.users = friends
}
}
} }
func getRequests() { func getItems ( ) {
manager.getRequests() { friends in
DispatchQueue.main.async {
self.requests = friends
}
}
} }
func search() { func deleteItem(indexSet: IndexSet) {
guard text.allSatisfy({ $0.isLetter || $0.isNumber }) else {
return
}
manager.getUsers(withName: text) { users in
self.users = users
}
} }
func toggleFriendStatus(for user: User, isRequest: Bool) { func moveltem(from: IndexSet, to: Int) {
let targetList = isRequest ? requests : users
guard let index = targetList.firstIndex(where: { $0.username == user.username }) else { return }
var updatedUser = targetList[index]
if isRequest {
if updatedUser.friendStatus == .requested {
updatedUser.friendStatus = .notFriend
deleteItem(username: user.username)
} else {
updatedUser.friendStatus = .friend
addItem(username: user.username)
}
requests.remove(at: index)
} else {
switch updatedUser.friendStatus {
case .friend:
updatedUser.friendStatus = .notFriend
deleteItem(username: user.username)
case .notFriend:
updatedUser.friendStatus = .requested
addItem(username: user.username)
case .requested:
updatedUser.friendStatus = .notFriend
deleteItem(username: user.username)
default:
break
}
users[index] = updatedUser
}
} }
func declineRequest(username: String){ func addItem(title: String) {
guard let index = requests.firstIndex(where: { $0.username == username }) else { return }
manager.removeFriend(withUsername: username) { statusCode in
}
requests.remove(at: index)
}
func deleteItem(username: String) {
manager.removeFriend(withUsername: username) { statusCode in
}
}
func addItem(username: String) {
manager.addFriend(withUsername: username) { statusCode in
}
} }
} }

@ -6,22 +6,19 @@
// //
import Foundation import Foundation
import SwiftUI
import DependencyInjection import DependencyInjection
import Model import Model
class HistoricBetViewModel: ObservableObject { class HistoricBetViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Published private(set) var bets: [BetResultDetail] = []
init() { init() {
getItems() getItems()
} }
func getItems() { func getItems() {
manager.getHistoricBets(withIndex: 0, withCount: 20) { bets in
self.bets = bets
}
} }
} }

@ -36,10 +36,10 @@ class LoginViewModel: ObservableObject {
self.onLoginSuccess() self.onLoginSuccess()
case 404: case 404:
AppStateContainer.shared.loggedState.connectedUser = false AppStateContainer.shared.loggedState.connectedUser = false
self.setErrorMessage(errorMessage: String(localized: "login_bad_credentials")) self.setErrorMessage(errorMessage: "Login ou mot de passe incorrects.")
default: default:
AppStateContainer.shared.loggedState.connectedUser = false AppStateContainer.shared.loggedState.connectedUser = false
self.setErrorMessage(errorMessage: String(localized: "login_error_content")) self.setErrorMessage(errorMessage: "La connexion a échoué. Veuillez réessayer.")
} }
} }
} }
@ -55,13 +55,13 @@ class LoginViewModel: ObservableObject {
// Login // Login
if checkLogin, loginIdentifier.isEmpty { if checkLogin, loginIdentifier.isEmpty {
newLoginIdentifierFieldError = String(localized: "field_error_mandatory") newLoginIdentifierFieldError = "Veuillez saisir votre identifiant."
hasError = true hasError = true
} }
// Password // Password
if checkPassword, loginPassword.isEmpty { if checkPassword, loginPassword.isEmpty {
newLoginPasswordFieldError = String(localized: "field_error_mandatory") newLoginPasswordFieldError = "Veuillez saisir votre mot de passe."
hasError = true hasError = true
} }

@ -13,19 +13,23 @@ class RankingViewModel: ObservableObject {
@Inject var manager: Manager @Inject var manager: Manager
@Published private(set) var friends: [User] = []
init() { init() {
getItems() getItems()
} }
func getItems() { func getItems ( ) {
manager.getFriends() { users in
var friends = users }
friends.append(AppStateContainer.shared.user!)
DispatchQueue.main.async { func deleteItem(indexSet: IndexSet) {
self.friends = friends.sorted(by: { $0.nbCoins > $1.nbCoins })
} }
}
func moveltem(from: IndexSet, to: Int) {
}
func addItem(title: String) {
} }
} }

@ -40,10 +40,10 @@ class RegisterViewModel: ObservableObject {
self.onRegisterSuccess() self.onRegisterSuccess()
case 409: case 409:
AppStateContainer.shared.loggedState.connectedUser = false AppStateContainer.shared.loggedState.connectedUser = false
self.setErrorMessage(errorMessage: String(localized: "register_already_used")) self.setErrorMessage(errorMessage: "Email ou pseudo déjà utilisé.")
default: default:
AppStateContainer.shared.loggedState.connectedUser = false AppStateContainer.shared.loggedState.connectedUser = false
self.setErrorMessage(errorMessage: String(localized: "register_error_content")) self.setErrorMessage(errorMessage: "La connexion a échoué. Veuillez réessayer.")
} }
} }
} }
@ -61,33 +61,35 @@ class RegisterViewModel: ObservableObject {
// Username // Username
if checkUsername, registerUsername.isEmpty { if checkUsername, registerUsername.isEmpty {
newRegisterUsernameFieldError = String(localized: "field_error_mandatory") newRegisterUsernameFieldError = "Veuillez saisir votre pseudo."
hasError = true hasError = true
} }
// Email // Email
if checkEmail, registerEmail.isEmpty { if checkEmail, registerEmail.isEmpty {
newRegisterEmailFieldError = String(localized: "field_error_mandatory") newRegisterEmailFieldError = "Veuillez saisir votre email."
hasError = true hasError = true
} else if checkEmail, isValidEmail(email: registerEmail) { }
newRegisterEmailFieldError = String(localized: "field_error_bad_email")
if checkEmail, isValidEmail(email: registerEmail) {
newRegisterEmailFieldError = "Veuillez saisir un email valide."
hasError = true hasError = true
} }
// Password // Password
if checkPassword, registerPassword.isEmpty { if checkPassword, registerPassword.isEmpty {
newRegisterPasswordFieldError = String(localized: "field_error_mandatory") newRegisterPasswordFieldError = "Veuillez saisir votre mot de passe."
hasError = true hasError = true
} }
// Confirm password // Confirm password
if checkConfirmPassword, registerConfirmPassword.isEmpty { if checkConfirmPassword, registerConfirmPassword.isEmpty {
newRegisterConfirmPasswordFieldError = String(localized: "field_error_mandatory") newRegisterConfirmPasswordFieldError = "Veuillez confirmer votre mot de passe."
hasError = true hasError = true
} }
if checkConfirmPassword, registerConfirmPassword != registerPassword { if checkConfirmPassword, registerConfirmPassword != registerPassword {
newRegisterConfirmPasswordFieldError = String(localized: "field_error_not_identical") newRegisterConfirmPasswordFieldError = "Les mots de passe ne sont pas identiques."
hasError = true hasError = true
} }
@ -102,7 +104,6 @@ class RegisterViewModel: ObservableObject {
registerPasswordFieldError = newRegisterPasswordFieldError registerPasswordFieldError = newRegisterPasswordFieldError
registerConfirmPasswordFieldError = newRegisterConfirmPasswordFieldError registerConfirmPasswordFieldError = newRegisterConfirmPasswordFieldError
} }
return false return false
} }

@ -15,10 +15,10 @@ struct BetEndingValidationView: View {
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@StateObject private var viewModel: BetEndingValidationViewModel @StateObject private var viewModel: BetEndingValidationViewModel
var betDetail: BetDetail var bet: BetDetail
init(bet: BetDetail) { init(bet: BetDetail) {
self.betDetail = bet self.bet = bet
self._viewModel = StateObject(wrappedValue: BetEndingValidationViewModel(id: bet.bet.id)) self._viewModel = StateObject(wrappedValue: BetEndingValidationViewModel(id: bet.bet.id))
} }
@ -48,23 +48,21 @@ struct BetEndingValidationView: View {
dismiss() dismiss()
} }
} }
ReviewCard(bet: betDetail.bet, amount: 0, isWin: false) ReviewCard(betDetail: bet, amountBetted: 0, isAWin: false)
.padding(.top, 20) .padding(.top, 20)
.padding(.bottom, 10) .padding(.bottom, 10)
Text("bet_confirmation_text") Text("Ce bet est arrivé à la date de fin. Vous devez à présent distribuer les gains en validant le pari gagnant.")
.textStyle(weight: .regular, color: AllInColors.grey800Color, size: 13) .textStyle(weight: .regular, color: AllInColors.grey800Color, size: 13)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
Text("Veuillez choisir la réponse finale:")
Text("bet_confirmation_choose_response")
.font(.system(size: 17)) .font(.system(size: 17))
.foregroundStyle(.white) .foregroundStyle(.white)
.fontWeight(.bold) .fontWeight(.bold)
.padding(.top, 30) .padding(.top, 30)
.padding(.bottom, 10) .padding(.bottom, 10)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
VStack(spacing: 14){ VStack(spacing: 14){
ForEach(betDetail.answers) { answer in ForEach(bet.answers, id: \.self) { answer in
ChoiceFinalAnswerCell(selected : answer.response == viewModel.selectedAnswer, answer: answer).onTapGesture { ChoiceFinalAnswerCell(selected : answer.response == viewModel.selectedAnswer, answer: answer).onTapGesture {
if(viewModel.selectedAnswer == answer.response){ if(viewModel.selectedAnswer == answer.response){
viewModel.selectedAnswer = nil viewModel.selectedAnswer = nil
@ -78,9 +76,8 @@ struct BetEndingValidationView: View {
Spacer() Spacer()
Button { Button {
dismiss() dismiss()
viewModel.post()
} label: { } label: {
Text("generic_validate") Text("Valider")
.font(.system(size: 23)) .font(.system(size: 23))
.foregroundColor(.white) .foregroundColor(.white)
.fontWeight(.bold) .fontWeight(.bold)

@ -18,23 +18,14 @@ struct BetView: View {
VStack(alignment: .center, spacing: 0) { VStack(alignment: .center, spacing: 0) {
TopBar(showMenu: self.$showMenu) TopBar(showMenu: self.$showMenu)
ScrollView(showsIndicators: false) { ScrollView(showsIndicators: false) {
LazyVStack(alignment: .center, spacing: 0, pinnedViews: [.sectionHeaders]) { LazyVStack(alignment: .leading, spacing: 0, pinnedViews: [.sectionHeaders]) {
if let bet = viewModel.popularBet { TrendingBetCard().padding(.top,25).padding([.leading,.trailing],25)
TrendingBetCard(bet: bet)
.padding(.top,25)
.padding([.leading,.trailing],25)
}
Section { Section {
VStack(spacing: 20){ VStack(spacing: 20){
if(viewModel.bets.isEmpty){ ForEach(viewModel.bets, id: \.id) { (bet: Bet) in
EmptyInfo(emoji:"🎮", title: String(localized: "empty_bets_title"), explain: "") BetCard(bet: bet)
}
else{
ForEach(viewModel.bets, id: \.id) { (bet: Bet) in
BetCard(bet: bet)
}
} }
} }
.padding([.leading,.trailing],25) .padding([.leading,.trailing],25)
@ -44,10 +35,13 @@ struct BetView: View {
AllInColors.fadeInGradiantCard AllInColors.fadeInGradiantCard
ScrollView(.horizontal,showsIndicators: false){ ScrollView(.horizontal,showsIndicators: false){
HStack{ HStack{
ChoiceCapsule(filter: .isPublic, viewModel: viewModel) ChoiceCapsule()
ChoiceCapsule(filter: .isInvitation, viewModel: viewModel) ChoiceCapsule()
ChoiceCapsule(filter: .inProgress, viewModel: viewModel) ChoiceCapsule()
ChoiceCapsule(filter: .isFinished, viewModel: viewModel) ChoiceCapsule()
ChoiceCapsule()
ChoiceCapsule()
ChoiceCapsule()
} }
.padding(.leading,25) .padding(.leading,25)
.padding([.top,.bottom],15) .padding([.top,.bottom],15)
@ -59,25 +53,26 @@ struct BetView: View {
.refreshable { .refreshable {
viewModel.getItems() viewModel.getItems()
} }
.sheet(isPresented: $viewModel.showingSheetOver, onDismiss: { .sheet(isPresented: $viewModel.showingSheet, onDismiss: {
viewModel.betsOver.removeFirst() viewModel.betsOver.removeFirst()
viewModel.showingSheetOver = !viewModel.betsOver.isEmpty viewModel.showingSheet = !viewModel.betsOver.isEmpty
}) { }) {
if let firstBetDetail = viewModel.betsOver.first { if let firstBetDetail = viewModel.betsOver.first {
BetEndingValidationView(bet: firstBetDetail) BetEndingValidationView(bet: firstBetDetail)
} }
} }
.sheet(isPresented: $viewModel.showingSheetWon, onDismiss: {
viewModel.betsWon.removeFirst()
viewModel.showingSheetWon = !viewModel.betsWon.isEmpty
}) {
if let firstBetResultDetail = viewModel.betsWon.first {
WinModal(betResult: firstBetResultDetail)
}
}
Spacer() Spacer()
} }
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)
.background(AllInColors.backgroundColor) .background(AllInColors.backgroundColor)
}
}
struct BetView_Previews: PreviewProvider {
static var previews: some View {
BetView(showMenu: .constant(false))
.preferredColorScheme(.light)
} }
} }

@ -28,6 +28,17 @@ struct CreationBetView: View {
}() }()
let screenWidth = UIScreen.main.bounds.width let screenWidth = UIScreen.main.bounds.width
@State private var response = ""
@State private var values: [String] = []
let options: [(Int, String, String)] = [
(0, "questionMarkIcon", "Oui / Non"),
(1, "footballIcon", "Pari sportif"),
(2, "paintbrushIcon", "Réponses personnalisées")
]
@State var groupedItems: [[String]] = [[String]] ()
private func updateGroupedItems() { private func updateGroupedItems() {
var updatedGroupedItems: [[String]] = [[String]] () var updatedGroupedItems: [[String]] = [[String]] ()
@ -35,7 +46,7 @@ struct CreationBetView: View {
var width: CGFloat = 0 var width: CGFloat = 0
var dynamicWidthLimit: CGFloat var dynamicWidthLimit: CGFloat
for value in viewModel.values { for value in values {
let label = UILabel() let label = UILabel()
label.text = value label.text = value
label.sizeToFit() label.sizeToFit()
@ -54,7 +65,7 @@ struct CreationBetView: View {
} }
updatedGroupedItems.append(tempItems) updatedGroupedItems.append(tempItems)
viewModel.groupedItems = updatedGroupedItems groupedItems = updatedGroupedItems
} }
var body: some View { var body: some View {
@ -70,7 +81,7 @@ struct CreationBetView: View {
VStack(spacing: 5) { VStack(spacing: 5) {
VStack() { VStack() {
HStack(spacing: 5) { HStack(spacing: 5) {
Text("bet_creation_theme") Text("Thème")
.textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17) .textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17)
Image("questionMarkGreyIcon") Image("questionMarkGreyIcon")
@ -80,7 +91,7 @@ struct CreationBetView: View {
showTitlePopover.toggle() showTitlePopover.toggle()
} }
.allInPopover(isPresented: $showTitlePopover, paddingHorizontal: 20) { .allInPopover(isPresented: $showTitlePopover, paddingHorizontal: 20) {
String(localized: "bet_creation_theme_tooltip") "Généralement un nom commun décrivant le thème global du pari pour servir de référence."
} }
Spacer() Spacer()
@ -93,11 +104,10 @@ struct CreationBetView: View {
Text(themeError) Text(themeError)
.textStyle(weight: .bold, color: .red, size: 10) .textStyle(weight: .bold, color: .red, size: 10)
} }
TextField("", text: $viewModel.theme, prompt: Text("bet_creation_theme_placeholder") TextField("", text: $viewModel.theme, prompt: Text("Études, sport, soirée...")
.foregroundColor(AllInColors.lightGrey300Color) .foregroundColor(AllInColors.lightGrey300Color)
.font(.system(size: 14)) .font(.system(size: 14))
.fontWeight(.light)) .fontWeight(.light))
.autocorrectionDisabled(true)
.padding() .padding()
.background( .background(
RoundedRectangle(cornerRadius: 9) RoundedRectangle(cornerRadius: 9)
@ -115,14 +125,14 @@ struct CreationBetView: View {
} }
HStack(spacing: 5) { HStack(spacing: 5) {
Text("bet_creation_bet_phrase") Text("Phrase du BET")
.textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17) .textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17)
Image("questionMarkGreyIcon") Image("questionMarkGreyIcon")
.resizable() .resizable()
.frame(width: 14, height: 14) .frame(width: 14, height: 14)
.allInPopover(isPresented: $showDescriptionPopover, paddingHorizontal: 10) { .allInPopover(isPresented: $showDescriptionPopover, paddingHorizontal: 10) {
String(localized: "bet_creation_phrase_tooltip") "Court descriptif du pari, souvent une question ouverte ou fermée."
} }
Spacer() Spacer()
@ -131,17 +141,14 @@ struct CreationBetView: View {
.padding(.leading, 10) .padding(.leading, 10)
VStack { VStack {
if let descriptionError = $viewModel.descriptionFieldError.wrappedValue { if let descriptionError = $viewModel.descriptionFieldError.wrappedValue {
Text(descriptionError) Text(descriptionError)
.textStyle(weight: .bold, color: .red, size: 10) .textStyle(weight: .bold, color: .red, size: 10)
} }
TextField("", text: $viewModel.description, prompt: Text("David sera absent Lundi matin en cours ?")
TextField("", text: $viewModel.description, prompt: Text("bet_creation_bet_phrase_placeholder")
.foregroundColor(AllInColors.lightGrey300Color) .foregroundColor(AllInColors.lightGrey300Color)
.font(.system(size: 14)) .font(.system(size: 14))
.fontWeight(.light), axis: .vertical) .fontWeight(.light), axis: .vertical)
.autocorrectionDisabled(true)
.lineLimit(4, reservesSpace: true) .lineLimit(4, reservesSpace: true)
.padding() .padding()
.background( .background(
@ -159,13 +166,13 @@ struct CreationBetView: View {
} }
HStack(spacing: 5) { HStack(spacing: 5) {
Text("bet_creation_end_registration_date") Text("Date de fin des inscriptions")
.textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17) .textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17)
Image("questionMarkGreyIcon") Image("questionMarkGreyIcon")
.resizable() .resizable()
.frame(width: 14, height: 14) .frame(width: 14, height: 14)
.allInPopover(isPresented: $showRegistrationEndDatePopover) { .allInPopover(isPresented: $showRegistrationEndDatePopover) {
String(localized: "bet_creation_register_tooltip") "Date de fin avant laquelle les joueurs peuvent s'inscrire en pariant leurs Allcoins."
} }
Spacer() Spacer()
@ -182,7 +189,7 @@ struct CreationBetView: View {
DatePicker( DatePicker(
"", "",
selection: $viewModel.endRegisterDate, selection: $viewModel.endRegisterDate,
in: Date()..., in: dateRange,
displayedComponents: [.date, .hourAndMinute] displayedComponents: [.date, .hourAndMinute]
) )
.accentColor(AllInColors.lightPurpleColor) .accentColor(AllInColors.lightPurpleColor)
@ -196,14 +203,14 @@ struct CreationBetView: View {
VStack(alignment: .leading, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
VStack() { VStack() {
HStack(spacing: 5) { HStack(spacing: 5) {
Text("bet_creation_end_bet_date") Text("Date de fin du BET")
.textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17) .textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17)
Image("questionMarkGreyIcon") Image("questionMarkGreyIcon")
.resizable() .resizable()
.frame(width: 14, height: 14) .frame(width: 14, height: 14)
.allInPopover(isPresented: $showBetEndDatePopover) { .allInPopover(isPresented: $showBetEndDatePopover) {
String(localized: "bet_creation_bet_end_tooltip") "Date des résultats où seront redistribués les Allcoins aux vainqueurs."
} }
Spacer() Spacer()
@ -220,7 +227,7 @@ struct CreationBetView: View {
DatePicker( DatePicker(
"", "",
selection: $viewModel.endBetDate, selection: $viewModel.endBetDate,
in: viewModel.endRegisterDate..., in: dateRange,
displayedComponents: [.date, .hourAndMinute] displayedComponents: [.date, .hourAndMinute]
) )
.accentColor(AllInColors.lightPurpleColor) .accentColor(AllInColors.lightPurpleColor)
@ -234,13 +241,13 @@ struct CreationBetView: View {
VStack { VStack {
HStack(spacing: 5) { HStack(spacing: 5) {
Text("bet_creation_bet_privacy") Text("Confidentialité du BET")
.textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17) .textStyle(weight: .bold, color: AllInColors.primaryTextColor, size: 17)
Image("questionMarkGreyIcon") Image("questionMarkGreyIcon")
.resizable() .resizable()
.frame(width: 14, height: 14) .frame(width: 14, height: 14)
.allInPopover(isPresented: $showConfidentialityPopover, paddingHorizontal: 15) { .allInPopover(isPresented: $showConfidentialityPopover, paddingHorizontal: 15) {
String(localized: "bet_creation_privacy_tooltip") "Option permettant d'ouvrir ou non le pari à des inconnus."
} }
Spacer() Spacer()
@ -248,15 +255,15 @@ struct CreationBetView: View {
.padding(.leading, 10) .padding(.leading, 10)
HStack(spacing: 5) { HStack(spacing: 5) {
ConfidentialityButton(image: "globe", text: String(localized: "bet_public"), selected: !viewModel.isPrivate) ConfidentialityButton(image: "globe", text: "Public", selected: viewModel.isPublic)
.onTapGesture { .onTapGesture {
viewModel.isPrivate = false viewModel.isPublic = true
} }
.padding(.trailing, 5) .padding(.trailing, 5)
ConfidentialityButton(image: "lock", text: String(localized: "bet_private"), selected: viewModel.isPrivate) ConfidentialityButton(image: "lock", text: "Privé", selected: !viewModel.isPublic)
.onTapGesture { .onTapGesture {
viewModel.isPrivate = true viewModel.isPublic = false
} }
Spacer() Spacer()
} }
@ -267,46 +274,28 @@ struct CreationBetView: View {
VStack(spacing: 10) { VStack(spacing: 10) {
if self.viewModel.isPrivate { if !self.viewModel.isPublic {
DropDownFriends(selectedItems: $viewModel.invited, friends: viewModel.friends) DropDownFriends()
.padding(.bottom, 30) .padding(.bottom, 30)
HStack() {
Spacer()
Text("bet_creation_private_bottom_text_1")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.multilineTextAlignment(.center)
Spacer()
}
HStack() {
Spacer()
Text("bet_creation_private_bottom_text_2")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.multilineTextAlignment(.center)
Spacer()
}
} else {
HStack() {
Spacer()
Text("bet_creation_public_bottom_text_1")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.multilineTextAlignment(.center)
Spacer()
}
HStack() {
Spacer()
Text("bet_creation_public_bottom_text_2")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.multilineTextAlignment(.center)
Spacer()
}
} }
HStack() { HStack() {
Spacer() Spacer()
Text("bet_creation_bottom_text_3") Text("Votre BET sera visible par tous les utilisateurs.")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.multilineTextAlignment(.center)
Spacer()
}
HStack() {
Spacer()
Text("Tout le monde pourra rejoindre le BET.")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.multilineTextAlignment(.center)
Spacer()
}
HStack() {
Spacer()
Text("Vous pourrez inviter des amis à tout moment pendant la période dinscription.")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13) .textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.padding(.leading, 35) .padding(.leading, 35)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
@ -319,13 +308,13 @@ struct CreationBetView: View {
Button(action: { Button(action: {
viewModel.create() viewModel.create()
}) { }) {
Text("bet_creation_publish") Text("Publier le bet")
.font(.system(size: 24)) .font(.system(size: 24))
.fontWeight(.bold) .fontWeight(.bold)
.overlay { .overlay {
AllInColors.primaryGradient.frame(width: 200) AllInColors.primaryGradient.frame(width: 150)
.mask( .mask(
Text("bet_creation_publish") Text("Publier le bet")
.font(.system(size: 24)) .font(.system(size: 24))
.fontWeight(.bold) .fontWeight(.bold)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -351,43 +340,37 @@ struct CreationBetView: View {
VStack(spacing: 5) { VStack(spacing: 5) {
VStack() { VStack() {
DropDownMenu(selectedOption: $viewModel.selectedTypeBet, options: viewModel.options) DropDownMenu(selectedOption: $viewModel.selectedOption, options: options)
} }
.padding([.bottom], 15) .padding([.bottom], 15)
.frame(width: 340) .frame(width: 340)
Group { Group {
switch viewModel.selectedTypeBet { switch viewModel.selectedOption {
case 0: case 0:
Text("bet_creation_yes_no_bottom_text_1") Text("Les utilisateurs devront répondre au pari avec OUI ou NON.")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13) .textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.padding([.leading, .trailing], 20) .padding([.leading, .trailing], 20)
Text("bet_creation_yes_no_bottom_text_2") Text("Aucune autre réponse ne sera acceptée.")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13) .textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
case 2: case 2:
Text("bet_creation_custom_bottom_text_1") Text("Vous allez renseigner les différentes réponses disponibles dans ce pari.")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13) .textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.padding(.leading, 13) .padding(.leading, 13)
Text("bet_creation_custom_bottom_text_2") Text("Faites attention a etre claire et éviter toutes incertitudes")
.textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13) .textStyle(weight: .bold, color: AllInColors.veryLightPurpleColor, size: 13)
.padding(.bottom, 15) .padding(.bottom, 15)
if let responseError = $viewModel.responsesFieldError.wrappedValue {
Text(responseError)
.textStyle(weight: .bold, color: .red, size: 10)
}
VStack(spacing: 5) { VStack(spacing: 5) {
HStack(spacing: 0) { HStack(spacing: 0) {
TextField("", text: $viewModel.response, prompt: Text("bet_creation_response_title") TextField("", text: $response, prompt: Text("Intitulé de réponse")
.foregroundColor(AllInColors.lightGrey200Color) .foregroundColor(AllInColors.lightGrey200Color)
.font(.system(size: 16)) .font(.system(size: 16))
.fontWeight(.medium)) .fontWeight(.medium))
.autocorrectionDisabled(true)
.padding() .padding()
.background( .background(
Rectangle() Rectangle()
@ -397,20 +380,20 @@ struct CreationBetView: View {
) )
.frame(width: 250, height: 38) .frame(width: 250, height: 38)
.foregroundColor(.black) .foregroundColor(.black)
.onChange(of: viewModel.response) { newValue in .onChange(of: response) { newValue in
if newValue.count > 20 { if newValue.count > 20 {
viewModel.response = String(newValue.prefix(20)) response = String(newValue.prefix(20))
} }
} }
Button(action: { Button(action: {
if !viewModel.response.isEmpty && viewModel.values.count < 5 { if !response.isEmpty && values.count < 5 {
viewModel.values.append(viewModel.response) values.append(response)
updateGroupedItems() updateGroupedItems()
viewModel.response = "" response = ""
} }
}) { }) {
Text("generic_add") Text("Ajouter")
.foregroundColor(.white) .foregroundColor(.white)
} }
.frame(width: 95, height: 40) .frame(width: 95, height: 40)
@ -420,12 +403,12 @@ struct CreationBetView: View {
} }
HStack { HStack {
Spacer() Spacer()
Text(String(localized: "bet_creation_max_answers \(5 - viewModel.values.count)")) Text("encore \(5 - values.count) max.")
.textStyle(weight: .regular, color: AllInColors.primaryTextColor, size: 12) .textStyle(weight: .regular, color: AllInColors.primaryTextColor, size: 12)
} }
VStack(spacing: 10) { VStack(spacing: 10) {
ForEach(viewModel.groupedItems, id: \.self) { items in ForEach(groupedItems, id: \.self) { items in
HStack { HStack {
ForEach(items, id: \.self) { text in ForEach(items, id: \.self) { text in
HStack { HStack {
@ -433,8 +416,8 @@ struct CreationBetView: View {
.foregroundColor(.white) .foregroundColor(.white)
.lineLimit(1) .lineLimit(1)
Button(action: { Button(action: {
if let index = viewModel.values.firstIndex(of: text) { if let index = values.firstIndex(of: text) {
viewModel.values.remove(at: index) values.remove(at: index)
updateGroupedItems() updateGroupedItems()
} }
}) { }) {
@ -455,7 +438,7 @@ struct CreationBetView: View {
} }
} }
default: default:
Text("generic_in_waiting") Text("En attente")
} }
} }
Spacer() Spacer()
@ -469,7 +452,7 @@ struct CreationBetView: View {
Button(action: { Button(action: {
selectedTab = 0 selectedTab = 0
}) { }) {
Text("bet_creation_question") Text("Question")
.font(.system(size: 16)) .font(.system(size: 16))
.padding() .padding()
.fontWeight(selectedTab == 0 ? .bold : .semibold) .fontWeight(selectedTab == 0 ? .bold : .semibold)
@ -479,7 +462,7 @@ struct CreationBetView: View {
Button(action: { Button(action: {
selectedTab = 1 selectedTab = 1
}) { }) {
Text("bet_creation_answer") Text("Réponses")
.font(.system(size: 16)) .font(.system(size: 16))
.padding() .padding()
.fontWeight(selectedTab == 1 ? .bold : .semibold) .fontWeight(selectedTab == 1 ? .bold : .semibold)
@ -494,7 +477,7 @@ struct CreationBetView: View {
hideKeyboard() hideKeyboard()
} }
.alert(isPresented: $viewModel.showErrorMessage) { .alert(isPresented: $viewModel.showErrorMessage) {
Alert(title: Text("bet_creation_error"), message: Text(viewModel.errorMessage ?? ""), dismissButton: .default(Text("generic_ok"))) Alert(title: Text("Erreur lors de la création d'un Bet"), message: Text(viewModel.errorMessage ?? ""), dismissButton: .default(Text("OK")))
} }
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)
.background(AllInColors.backgroundColor) .background(AllInColors.backgroundColor)

@ -7,6 +7,7 @@
import SwiftUI import SwiftUI
import Model import Model
import StubLib
struct CurrentBetView: View { struct CurrentBetView: View {
@ -19,12 +20,12 @@ struct CurrentBetView: View {
TopBar(showMenu: self.$showMenu) TopBar(showMenu: self.$showMenu)
ScrollView(showsIndicators: false) { ScrollView(showsIndicators: false) {
Text("bet_history_current_title") Text("En cours")
.textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25) .textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25)
.padding([.top],15) .padding([.top],15)
VStack(spacing: 20){ VStack(spacing: 20){
ForEach(viewModel.bets, id: \.bet.id) { (betDetail: BetDetail) in ForEach(viewModel.bets, id: \.bet.id) { (bet: BetDetail) in
ReviewCard(bet: betDetail.bet, amount: betDetail.userParticipation?.stake ?? 0, isWin: false) ReviewCard(betDetail: bet, amountBetted: 110, isAWin: false)
} }
} }
.padding([.trailing, .leading, .bottom],25) .padding([.trailing, .leading, .bottom],25)

@ -35,7 +35,7 @@ struct DailyGiftPage: View {
.edgesIgnoringSafeArea(.all) .edgesIgnoringSafeArea(.all)
VStack { VStack {
Text("daily_reward_title") Text("Récompense quotidienne")
.textStyle(weight: .bold, color: .white, size: 25) .textStyle(weight: .bold, color: .white, size: 25)
Group { Group {
@ -110,7 +110,7 @@ struct DailyGiftPage: View {
} }
} }
Text("daily_reward_subtitle") Text("Votre récompense quotidienne est débloquée tous les jours à 00:00 UTC et vous permet dobtenir entre 10 et 150 Allcoins.")
.textStyle(weight: .medium, color: .white, size: 13) .textStyle(weight: .medium, color: .white, size: 13)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.padding(.horizontal, geometry.size.width * 0.13) .padding(.horizontal, geometry.size.width * 0.13)

@ -5,26 +5,29 @@ struct DetailsView: View {
@Binding var isModalPresented: Bool @Binding var isModalPresented: Bool
@Binding var isModalParticipated: Bool @Binding var isModalParticipated: Bool
@State var progressValue: Float = 0.2
@StateObject private var viewModel: DetailsViewModel @StateObject private var viewModel: DetailsViewModel
var isFinished: Bool { var isFinished: Bool {
viewModel.betDetail?.wonParticipation == nil ? false : true viewModel.betDetail?.finalAnswer == nil ? false : true
} }
var StatusValues: (String, Color) { var StatusValues: (String, Color) {
if let betType = viewModel.betDetail?.bet.status { if let betType = viewModel.betDetail?.bet.status {
switch betType { switch betType {
case .inProgress: case .inProgress:
return (String(localized: "bet_status_in_progress"), AllInColors.darkPurpleColor) return ("En cours...", AllInColors.darkPurpleColor)
case .waiting, .closing: case .waiting:
return (String(localized: "bet_status_waiting"), AllInColors.pink100) return ("En attente...", AllInColors.pink100)
case .closing:
return ("Fin des inscriptions...", AllInColors.grey50Color)
case .finished: case .finished:
return (String(localized: "bet_status_finished"), AllInColors.grey100Color) return ("Terminé", AllInColors.grey100Color)
case .cancelled: case .cancelled:
return (String(localized: "bet_status_cancelled"), AllInColors.grey100Color) return ("Annulé", AllInColors.grey100Color)
} }
} else { } else {
return (String(localized: "bet_status_unavailable"), AllInColors.pink100) return ("Statut indisponible", AllInColors.pink100)
} }
} }
@ -57,117 +60,97 @@ struct DetailsView: View {
} }
.padding(.horizontal, 15) .padding(.horizontal, 15)
.background(StatusValues.1) .background(StatusValues.1)
if viewModel.betDetail != nil{
ScrollView { VStack(spacing: 0) {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 5) {
HStack(spacing: 3) { HStack(spacing: 3) {
Spacer() Spacer()
Text("bet_proposed_by_format") Text("proposé par")
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color)
Text((viewModel.betDetail?.bet.author ?? "Unknown").capitalized)
.font(.system(size: 10))
.fontWeight(.semibold)
.foregroundColor(AllInColors.primaryTextColor)
}
Text(viewModel.betDetail?.bet.theme ?? "Not loaded")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
Text(viewModel.betDetail?.bet.phrase ?? "Not loaded") Text((viewModel.betDetail?.bet.author.username ?? "Unknown").capitalized)
.font(.system(size: 20)) .font(.system(size: 10))
.fontWeight(.bold) .fontWeight(.semibold)
.padding(.bottom, 10) .foregroundColor(AllInColors.primaryTextColor)
HStack {
HStack { }
Spacer() Text(viewModel.betDetail?.bet.theme ?? "Not loaded")
Text("bet_starting") .font(.system(size: 15))
.font(.system(size: 15)) .foregroundColor(AllInColors.grey800Color)
.foregroundColor(AllInColors.grey800Color) Text(viewModel.betDetail?.bet.phrase ?? "Not loaded")
} .font(.system(size: 20))
.frame(width: 105) .fontWeight(.bold)
.padding(.trailing, 10) .padding(.bottom, 10)
TextCapsule(date: viewModel.betDetail?.bet.endRegisterDate ?? Date()) HStack {
Spacer()
}.padding(.bottom, 10)
HStack { HStack {
HStack {
Spacer()
Text("bet_ends")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
}
.frame(width: 105)
.padding(.trailing, 10)
TextCapsule(date: viewModel.betDetail?.bet.endBetDate ?? Date())
Spacer() Spacer()
Text("Commence le")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
} }
} .frame(width: 105)
.padding(.all, 15) .padding(.trailing, 10)
.padding(.top, 6) TextCapsule(date: viewModel.betDetail?.bet.endRegisterDate ?? Date())
.border(width: 1, edges: [.bottom], color: AllInColors.delimiterGrey) Spacer()
.background(AllInColors.componentBackgroundColor)
.cornerRadius(20, corners: [.topLeft,.topRight])
if isFinished {
ResultBanner(finalAnswer: (viewModel.betDetail?.wonParticipation)!, odds: (viewModel.betDetail?.odds)!)
}
VStack(alignment: .leading, spacing: 0) {
if let bet = viewModel.betDetail{
BetLineLoading(bet: bet).padding(.vertical, 20)
}
Text("bet_status_participants_list")
.font(.system(size: 18))
.foregroundStyle(AllInColors.grey100Color)
.fontWeight(.bold)
.padding(.bottom, 10)
ForEach(viewModel.betDetail?.participations ?? []) { participation in }.padding(.bottom, 10)
UserInfo(username: participation.username, picture: nil , value: participation.stake).padding(.horizontal, 10) HStack {
HStack {
Spacer()
Text("Prend fin le")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
} }
.padding(.bottom) .frame(width: 105)
.padding(.trailing, 10)
TextCapsule(date: viewModel.betDetail?.bet.endBetDate ?? Date())
Spacer() Spacer()
} }
.padding([.trailing,.leading], 15)
.padding(.bottom, 100)
} }
.frame(maxWidth: .infinity, maxHeight: (geometry.size.height + geometry.safeAreaInsets.bottom) - 50) .padding(.all, 15)
.background(AllInColors.underComponentBackgroundColor) .padding(.vertical, 10)
.cornerRadius(15, corners: [.topLeft, .topRight]) .background(AllInColors.componentBackgroundColor)
} .cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0)
else{
ScrollView { if isFinished {
HStack(alignment: .center){ ResultBanner()
Spacer() }
Image(systemName: "exclamationmark.triangle.fill").font(.system(size: 45)) VStack(alignment: .leading, spacing: 5) {
VStack(alignment:.leading){ BetLineLoading(participations: viewModel.betDetail?.participations ?? [])
Text("error_title").font(.system(size: 10)) .padding(.vertical,15)
Text("error_message").font(.system(size: 10)) Text("Liste des participants")
.font(.system(size: 18))
.foregroundStyle(AllInColors.grey100Color)
.fontWeight(.bold)
.padding(.bottom, 10)
ScrollView(showsIndicators: false) {
ForEach(viewModel.betDetail?.participations ?? []) { (participation: Participation) in
ParticiationCell(participation: participation).padding(.horizontal, 10)
} }
Spacer() }
}.opacity(0.6) .padding(.bottom, geometry.safeAreaInsets.bottom + 28)
.padding(.vertical, 20)
Spacer()
} }
.frame(maxWidth: .infinity, maxHeight: (geometry.size.height + geometry.safeAreaInsets.bottom) - 50) .padding([.bottom,.trailing,.leading], 15)
.background(AllInColors.underComponentBackgroundColor) .background(AllInColors.underComponentBackgroundColor)
.cornerRadius(15, corners: [.topLeft, .topRight]) .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
Spacer()
} }
.frame(maxWidth: .infinity, maxHeight: (geometry.size.height + geometry.safeAreaInsets.bottom) - 50)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(15, corners: [.topLeft, .topRight])
ParticipateButton(isOpen: $isModalPresented, isParticapatedOpen: $isModalParticipated, bet: viewModel.betDetail?.bet) ParticipateButton(isOpen: $isModalPresented, isParticapatedOpen: $isModalParticipated, bet: viewModel.betDetail?.bet)
.padding(.bottom, geometry.safeAreaInsets.bottom + 5) .padding(.bottom, geometry.safeAreaInsets.bottom + 5)
.padding(.horizontal, 10) .padding(.horizontal, 10)
} }
.sheet(isPresented: $isModalParticipated) { .sheet(isPresented: $isModalParticipated) {
ParticipationModal(selectedAnswer: $viewModel.selectedAnswer, mise: $viewModel.mise, phrase: viewModel.betDetail?.bet.phrase ?? "", answers: viewModel.betDetail?.answers ?? [], participationAddedCallback: { ParticipationModal(answer: $viewModel.answer, mise: $viewModel.mise, description: viewModel.betDetail?.bet.phrase ?? "Not loaded", participationAddedCallback: {
viewModel.addParticipate() viewModel.addParticipate()
isModalParticipated.toggle() isModalParticipated.toggle()
}, })
checkAndSetError: viewModel.checkAndSetError)
.presentationDetents([.fraction(0.55)]) .presentationDetents([.fraction(0.55)])
} }
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)

@ -9,112 +9,32 @@ import SwiftUI
struct FriendsView: View { struct FriendsView: View {
@StateObject private var viewModel = FriendsViewModel()
@Binding var showMenu: Bool @Binding var showMenu: Bool
@State private var selectedTab = 0
var body: some View { var body: some View {
VStack(alignment: .center, spacing: 0) { VStack(alignment: .center, spacing: 0) {
TopBar(showMenu: self.$showMenu) TopBar(showMenu: self.$showMenu)
TabView(selection: $selectedTab) { Text("Amis")
ScrollView(showsIndicators: false){ .textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25)
VStack{ .padding([.top,.bottom],15)
HStack {
TextField("Search...", text: $viewModel.text) ScrollView(showsIndicators: false){
.padding(7) Friend(image: "https://picsum.photos/536/354", pseudo: "Lucas")
.zIndex(200) Friend(image: "https://picsum.photos/536/354", pseudo: "Arthur")
.padding(.horizontal, 25) Friend(image: "https://picsum.photos/536/354", pseudo: "Lucase")
.background(Color(.systemGray6)) Friend(image: "https://picsum.photos/536/354", pseudo: "Rayhan")
.cornerRadius(8)
.overlay(
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.gray)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
.padding(.leading, 8)
if !viewModel.text.isEmpty {
Button(action: {
self.viewModel.text = ""
}) {
Image(systemName: "multiply.circle.fill")
.foregroundColor(.gray)
.padding(.trailing, 8)
}
}
}
)
.padding(.horizontal, 10)
}
if(viewModel.users.isEmpty){
EmptyInfo(emoji:"👥", title: String(localized: "empty_friends_title"), explain: String(localized: "empty_friends_explain")).padding(.top, 40)
}
else{
ForEach(viewModel.users, id: \.self) { friend in
Friend(user: friend, isRequest: false, viewModel: viewModel)
}
}
}
Spacer()
}
.refreshable {
viewModel.getItems()
}
.padding(.top, 50)
.tag(0)
ScrollView{
VStack(alignment: .center, spacing: 0) {
if(viewModel.requests.isEmpty){
EmptyInfo(emoji:"📬", title: "Aucune demande d'amis en attente", explain: "").padding(.top, 40)
}
else{
ScrollView(showsIndicators: false){
ForEach(viewModel.requests, id: \.self) { request in
Friend(user: request, isRequest: true, viewModel: viewModel)
}
}
.refreshable {
viewModel.getRequests()
}
.padding(.top, 25)
}
Spacer()
}
}.refreshable {
viewModel.getRequests()
}
.padding(.top, 50)
.tag(1)
} }
.overlay( .padding(.top, 25)
HStack { Spacer()
Button(action: {
selectedTab = 0
}) {
Text("friends_title")
.font(.system(size: 16))
.padding()
.fontWeight(selectedTab == 0 ? .bold : .semibold)
.foregroundColor(selectedTab == 0 ? AllInColors.primaryTextColor : .gray)
.offset(y: 0)
}
Button(action: {
selectedTab = 1
}) {
Text(String(localized: "friends_request") + (viewModel.requests.isEmpty ? "" : "(\(viewModel.requests.count.description))"))
.font(.system(size: 16))
.padding()
.fontWeight(selectedTab == 1 ? .bold : .semibold)
.foregroundColor(selectedTab == 1 ? AllInColors.primaryTextColor : .gray)
.offset(y: 0)
}
}
, alignment: .top)
.tabViewStyle(PageTabViewStyle())
} }
.edgesIgnoringSafeArea(.bottom) .edgesIgnoringSafeArea(.bottom)
.background(AllInColors.backgroundColor) .background(AllInColors.backgroundColor)
} }
} }
struct FriendsView_Previews: PreviewProvider {
static var previews: some View {
FriendsView(showMenu: .constant(false))
}
}

@ -6,11 +6,9 @@
// //
import SwiftUI import SwiftUI
import Model
struct HistoricBetView: View { struct HistoricBetView: View {
@StateObject private var viewModel = HistoricBetViewModel()
@Binding var showMenu: Bool @Binding var showMenu: Bool
@State private var showingSheet = false @State private var showingSheet = false
@ -20,13 +18,12 @@ struct HistoricBetView: View {
TopBar(showMenu: self.$showMenu) TopBar(showMenu: self.$showMenu)
ScrollView(showsIndicators: false) { ScrollView(showsIndicators: false) {
Text("bet_history_title") Text("Historique")
.textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25) .textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25)
.padding([.top],15) .padding([.top],15)
VStack(spacing: 20){ VStack(spacing: 20){
ForEach(viewModel.bets, id: \.bet.id) { (betDetail: BetResultDetail) in // ReviewCard(amountBetted: 110, isAWin: true)
ReviewCard(bet: betDetail.bet, amount: betDetail.participation.stake, isWin: betDetail.won) // ReviewCard(amountBetted: 3, isAWin: false)
}
} }
.padding([.trailing, .leading, .bottom],25) .padding([.trailing, .leading, .bottom],25)
} }

@ -25,9 +25,9 @@ struct LoginView: View {
VStack(spacing: 15) { VStack(spacing: 15) {
Spacer() Spacer()
Text("login_title") Text("Te revoilà!")
.textStyle(weight: .semibold, color: AllInColors.darkBlueColor, size: 40) .textStyle(weight: .semibold, color: AllInColors.darkBlueColor, size: 40)
Text("login_subtitle") Text("Bon retour parmis nous tu nous as manqué!")
.textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 20) .textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 20)
.frame(width: 220) .frame(width: 220)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
@ -39,7 +39,7 @@ struct LoginView: View {
Text(identifierError) Text(identifierError)
.textStyle(weight: .bold, color: .red, size: 10) .textStyle(weight: .bold, color: .red, size: 10)
} }
TextField("", text: $viewModel.loginIdentifier, prompt: Text("generic_email").foregroundColor(.gray)) TextField("", text: $viewModel.loginIdentifier, prompt: Text("Email").foregroundColor(.gray))
.padding() .padding()
.background(Color.white.cornerRadius(9)) .background(Color.white.cornerRadius(9))
.frame(width: 300) .frame(width: 300)
@ -50,7 +50,6 @@ struct LoginView: View {
) )
.autocapitalization(.none) .autocapitalization(.none)
.padding(.bottom, 8) .padding(.bottom, 8)
.autocorrectionDisabled(true)
.focused($focusedField, equals: .email) .focused($focusedField, equals: .email)
} }
@ -61,9 +60,9 @@ struct LoginView: View {
} }
Group { Group {
if isPasswordVisible { if isPasswordVisible {
SecureField("", text: $viewModel.loginPassword, prompt: Text("generic_password").foregroundColor(.gray)) SecureField("", text: $viewModel.loginPassword, prompt: Text("Mot de passe").foregroundColor(.gray))
} else { } else {
TextField("", text: $viewModel.loginPassword, prompt: Text("generic_password").foregroundColor(.gray)) TextField("", text: $viewModel.loginPassword, prompt: Text("Mot de passe").foregroundColor(.gray))
.autocapitalization(.none) .autocapitalization(.none)
} }
} }
@ -90,7 +89,7 @@ struct LoginView: View {
.focused($focusedField, equals: .password) .focused($focusedField, equals: .password)
} }
Text("login_forgot_password") Text("Mot de passe oublié?")
.textStyle(weight: .medium, color: AllInColors.darkBlueColor, size: 14) .textStyle(weight: .medium, color: AllInColors.darkBlueColor, size: 14)
.frame(alignment: .trailing) .frame(alignment: .trailing)
.padding(.bottom, 20) .padding(.bottom, 20)
@ -99,7 +98,7 @@ struct LoginView: View {
Button(action: { Button(action: {
viewModel.login() viewModel.login()
}) { }) {
Text("generic_login") Text("Se connecter")
.textStyle(weight: .bold, color: .white, size: 17) .textStyle(weight: .bold, color: .white, size: 17)
.frame(width: 300, height: 60) .frame(width: 300, height: 60)
.background(LinearGradient(gradient: .background(LinearGradient(gradient:
@ -109,12 +108,12 @@ struct LoginView: View {
} }
Spacer() Spacer()
HStack(spacing: 4) { HStack(spacing: 0) {
Text("login_no_account") Text("Pas encore inscrit? ")
.textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 16) .textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 16)
NavigationLink(destination: RegisterView().navigationBarBackButtonHidden(true)) NavigationLink(destination: RegisterView().navigationBarBackButtonHidden(true))
{ {
Text("generic_register") Text("S'inscrire")
.textStyle(weight: .semibold, color: AllInColors.darkPurpleColor, size: 16) .textStyle(weight: .semibold, color: AllInColors.darkPurpleColor, size: 16)
} }
} }
@ -128,7 +127,7 @@ struct LoginView: View {
} }
} }
.alert(isPresented: $viewModel.showErrorMessage) { .alert(isPresented: $viewModel.showErrorMessage) {
Alert(title: Text("login_error_title"), message: Text(viewModel.errorMessage ?? ""), dismissButton: .default(Text("generic_ok"))) Alert(title: Text("Erreur de connexion"), message: Text(viewModel.errorMessage ?? ""), dismissButton: .default(Text("OK")))
} }
.onSubmit { .onSubmit {
switch focusedField { switch focusedField {

@ -48,8 +48,6 @@ struct MainView: View {
CreationBetView(showMenu: self.$showMenu) CreationBetView(showMenu: self.$showMenu)
case "Current": case "Current":
CurrentBetView(showMenu: self.$showMenu) CurrentBetView(showMenu: self.$showMenu)
case "Profile":
ProfileView(showMenu: self.$showMenu)
default: default:
BetView(showMenu: self.$showMenu) BetView(showMenu: self.$showMenu)
} }
@ -60,8 +58,8 @@ struct MainView: View {
if self.showMenu { if self.showMenu {
Menu() Menu()
.transition(.move(edge: .leading))
.frame(width: geometry.size.width*0.83) .frame(width: geometry.size.width*0.83)
.transition(.move(edge: .leading))
} }
} }

@ -1,116 +0,0 @@
//
// ProfileView.swift
// AllIn
//
// Created by étudiant on 26/05/2024.
//
import SwiftUI
struct ProfileView: View {
@Binding var showMenu: Bool
let parameters: [(title: String, icon: String, backgroundColor: Color, itemColor: Color)] = [
(title: "Changer de pseudo", icon: "person", backgroundColor: AllInColors.componentBackgroundColor, itemColor: AllInColors.secondaryTextColor),
(title: "Changer le mot de passe", icon: "lock", backgroundColor: AllInColors.componentBackgroundColor, itemColor: AllInColors.secondaryTextColor),
(title: "Supprimer le compte", icon: "trash", backgroundColor: AllInColors.componentBackgroundColor, itemColor: AllInColors.secondaryTextColor),
(title: "Déconnexion", icon: "xmark", backgroundColor: AllInColors.lightPurpleColor, itemColor: .white)
]
var body: some View {
GeometryReader { geometry in
VStack(alignment: .leading, spacing: 0) {
TopBar(showMenu: self.$showMenu)
VStack(alignment: .leading) {
HStack {
Image("defaultUserImage")
.resizable()
.scaledToFit()
.frame(width: 80, height: 80)
.cornerRadius(180)
VStack(alignment: .leading, spacing: 5) {
Text("Pseudo")
.fontWeight(.bold)
.font(.system(size: 20))
HStack(spacing: 15) {
VStack(){
Text("114")
.fontWeight(.heavy)
.font(.system(size: 15))
Text(String(localized: "drawer_bets"))
.fontWeight(.regular)
.font(.system(size: 12))
.foregroundColor(AllInColors.grey600Color)
}
VStack(){
Text("343")
.fontWeight(.heavy)
.font(.system(size: 15))
Text(String(localized: "drawer_best_win"))
.fontWeight(.regular)
.font(.system(size: 12))
.foregroundColor(AllInColors.grey600Color)
}
VStack(){
Text("5")
.fontWeight(.heavy)
.font(.system(size: 15))
Text(String(localized: "drawer_nb_friends"))
.fontWeight(.regular)
.font(.system(size: 12))
.foregroundColor(AllInColors.grey600Color)
}
}
}
.padding(.leading, 10)
}
Text("Compte")
.fontWeight(.bold)
.font(.system(size: 16))
.padding(.leading, 13)
.padding(.top, 35)
VStack(spacing: 0) {
ForEach(0..<parameters.count, id: \.self) { index in
HStack {
Image(systemName: parameters[index].icon)
.foregroundColor(parameters[index].itemColor)
.padding(.leading, 13)
Text(parameters[index].title)
.font(.system(size: 14))
.fontWeight(.bold)
.foregroundColor(parameters[index].itemColor)
Spacer()
Image(systemName: "chevron.right")
.resizable()
.frame(width: 8, height: 12)
.foregroundColor(parameters[index].itemColor)
.padding(.trailing, 14)
}
.padding(.vertical, 15)
.background(parameters[index].backgroundColor)
}
}
.frame(maxWidth: .infinity)
.cornerRadius(7)
Spacer()
}
.padding(.top, geometry.size.width*0.15)
.padding(.horizontal, 20)
}
.edgesIgnoringSafeArea(.bottom).background(AllInColors.backgroundColor)
}
}
}
struct ProfileView_Previews: PreviewProvider {
static var previews: some View {
ProfileView(showMenu: .constant(false))
}
}

@ -10,130 +10,128 @@ import SwiftUI
struct RankingView: View { struct RankingView: View {
@Binding var showMenu: Bool @Binding var showMenu: Bool
@StateObject var viewModel = RankingViewModel()
var body: some View { var body: some View {
GeometryReader { geometry in GeometryReader { geometry in
VStack(alignment: .center, spacing: 0) { VStack(alignment: .center, spacing: 0) {
TopBar(showMenu: self.$showMenu) TopBar(showMenu: self.$showMenu)
Text("ranking_title") Text("Classement")
.textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25) .textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25)
.padding([.top,.bottom], 15) .padding([.top,.bottom],15)
HStack { HStack {
if viewModel.friends.indices.contains(0) { ZStack {
ZStack { VStack(spacing: 0){
VStack(spacing: 0) { Spacer()
Text("Pseudo")
.fontWeight(.bold)
.padding(.bottom, 4)
.font(.system(size: 16))
.lineLimit(1)
Divider()
.background(AllInColors.lightGrey100Color)
HStack{
Spacer()
Image("allcoinIcon")
.resizable()
.frame(width: 18, height: 18, alignment: .leading)
.padding([.top,.bottom],10)
Text(String("570"))
.textStyle(weight: .black, color: AllInColors.lightPurpleColor, size: 16)
.padding(.trailing, 18)
Spacer() Spacer()
Text(viewModel.friends[0].username)
.fontWeight(.bold)
.padding(.bottom, 4)
.font(.system(size: 16))
.lineLimit(1)
Divider()
.background(AllInColors.lightGrey100Color)
HStack {
Spacer()
Image("allcoinIcon")
.resizable()
.frame(width: 18, height: 18, alignment: .leading)
.padding([.top, .bottom], 10)
Text(String(viewModel.friends[0].nbCoins))
.textStyle(weight: .black, color: AllInColors.lightPurpleColor, size: 16)
.padding(.trailing, 18)
Spacer()
}
.frame(width: geometry.size.width * 0.43)
.background(AllInColors.underComponentBackgroundColor)
} }
.frame(width: geometry.size.width * 0.43, height: 120) .frame(width: geometry.size.width * 0.43)
.background(AllInColors.componentBackgroundColor) .background(AllInColors.underComponentBackgroundColor)
.cornerRadius(41.5, corners: .topLeft)
.cornerRadius(8, corners: .topRight)
.cornerRadius(15, corners: [.bottomLeft, .bottomRight])
UserPicture(picture: viewModel.friends[0].image, username: viewModel.friends[0].username, size: 70)
.offset(x: 0, y: -55)
Text("1")
.frame(width: 28, height: 28)
.foregroundColor(.white)
.background(AllInColors.lightPurpleColor)
.cornerRadius(30)
.font(.system(size: 18))
.fontWeight(.bold)
.offset(x: 0, y: -23)
} }
.frame(width: geometry.size.width * 0.43, height: 120)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(41.5, corners: .topLeft)
.cornerRadius(8, corners: .topRight)
.cornerRadius(15, corners: [.bottomLeft, .bottomRight])
Image("defaultUserImage")
.resizable()
.frame(width: 70, height: 70)
.scaledToFit()
.cornerRadius(180)
.offset(x: 0, y: -55)
Text("1")
.frame(width: 28, height: 28)
.foregroundColor(.white)
.background(AllInColors.lightPurpleColor)
.cornerRadius(30)
.font(.system(size: 18))
.fontWeight(.bold)
.offset(x: 0, y: -23)
} }
if viewModel.friends.indices.contains(1) { ZStack {
ZStack { VStack(spacing: 0){
VStack(spacing: 0) { Spacer()
Text("Pseudo")
.fontWeight(.bold)
.padding(.bottom, 4)
.font(.system(size: 15))
.lineLimit(1)
Divider()
.background(AllInColors.lightGrey100Color)
HStack{
Spacer()
Image("allcoinIcon")
.resizable()
.frame(width: 18, height: 18, alignment: .leading)
.padding([.top,.bottom],10)
Text(String("570"))
.textStyle(weight: .black, color: AllInColors.lightPurpleColor, size: 16)
.padding(.trailing, 18)
Spacer() Spacer()
Text(viewModel.friends[1].username)
.fontWeight(.bold)
.padding(.bottom, 4)
.font(.system(size: 15))
.lineLimit(1)
Divider()
.background(AllInColors.lightGrey100Color)
HStack {
Spacer()
Image("allcoinIcon")
.resizable()
.frame(width: 18, height: 18, alignment: .leading)
.padding([.top, .bottom], 10)
Text(String(viewModel.friends[1].nbCoins))
.textStyle(weight: .black, color: AllInColors.lightPurpleColor, size: 16)
.padding(.trailing, 18)
Spacer()
}
.frame(width: geometry.size.width * 0.43)
.background(AllInColors.underComponentBackgroundColor)
} }
.frame(width: geometry.size.width * 0.43, height: 90) .frame(width: geometry.size.width * 0.43)
.background(AllInColors.componentBackgroundColor) .background(AllInColors.underComponentBackgroundColor)
.cornerRadius(27.5, corners: .topRight)
.cornerRadius(8, corners: .topLeft)
.cornerRadius(15, corners: [.bottomLeft, .bottomRight])
UserPicture(picture: viewModel.friends[1].image, username: viewModel.friends[1].username, size: 50)
.offset(x: 0, y: -50)
Text("2")
.frame(width: 20, height: 20)
.foregroundColor(.white)
.background(AllInColors.lightPurpleColor)
.cornerRadius(30)
.font(.system(size: 14))
.fontWeight(.bold)
.offset(x: 0, y: -28)
} }
.padding(.top, 28) .frame(width: geometry.size.width * 0.43, height: 90)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(27.5, corners: .topRight)
.cornerRadius(8, corners: .topLeft)
.cornerRadius(15, corners: [.bottomLeft, .bottomRight])
Image("defaultUserImage")
.resizable()
.frame(width: 60, height: 60)
.scaledToFit()
.cornerRadius(180)
.offset(x: 0, y: -50)
Text("2")
.frame(width: 23, height: 23)
.foregroundColor(.white)
.background(AllInColors.lightPurpleColor)
.cornerRadius(30)
.font(.system(size: 15))
.fontWeight(.bold)
.offset(x: 0, y: -22)
} }
.padding(.top, 28)
} }
.padding([.leading, .trailing, .top], 20) .padding([.leading,.trailing,.top],20)
if viewModel.friends.count == 1 { ScrollView(showsIndicators: false){
EmptyInfo(emoji:"👀", title: String(localized: "empty_ranking_title"), explain: String(localized: "empty_ranking_explain")).padding(.top, 40) VStack(spacing: 10) {
RankingRow(number: 3, image: "defaultUserImage", pseudo: "Lucas", allCoins: 541)
} RankingRow(number: 4, image: "defaultUserImage", pseudo: "Arthur", allCoins: 542)
else{
ScrollView(showsIndicators: false) {
ForEach(viewModel.friends.indices.dropFirst(2), id: \.self) { index in
let friend = viewModel.friends[index]
RankingRow(
number: index + 1,
image: friend.image,
pseudo: friend.username,
allCoins: friend.nbCoins
)
}
} }
.padding(.top, 10) }.padding(.top, 10)
.padding(.horizontal, 20)
}
Spacer() Spacer()
} }
.edgesIgnoringSafeArea(.bottom).background(AllInColors.backgroundColor) .edgesIgnoringSafeArea(.bottom).background(AllInColors.backgroundColor)
} }
} }
} }
struct RankingView_Previews: PreviewProvider {
static var previews: some View {
RankingView(showMenu: .constant(false))
}
}

@ -27,18 +27,18 @@ struct RegisterView: View {
Spacer() Spacer()
VStack { VStack {
if !viewModel.registerUsername.isEmpty { if !viewModel.registerUsername.isEmpty {
Text("register_hello \(viewModel.registerUsername)") Text("Bonjour " + viewModel.registerUsername + ",")
.textStyle(weight: .semibold, color: AllInColors.darkBlueColor, size: 40) .textStyle(weight: .semibold, color: AllInColors.darkBlueColor, size: 40)
.padding([.trailing, .leading], 30) .padding([.trailing, .leading], 30)
} else { } else {
Text("register_hello") Text("Bonjour,")
.textStyle(weight: .semibold, color: AllInColors.darkBlueColor, size: 40) .textStyle(weight: .semibold, color: AllInColors.darkBlueColor, size: 40)
} }
Text("register_title") Text("On a besoin de ça!")
.textStyle(weight: .semibold, color: AllInColors.darkBlueColor, size: 40) .textStyle(weight: .semibold, color: AllInColors.darkBlueColor, size: 40)
} }
Text("register_subtitle") Text("Promis cest rapide.")
.textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 20) .textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 20)
.frame(width: 220) .frame(width: 220)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
@ -49,7 +49,7 @@ struct RegisterView: View {
Text(usernameError) Text(usernameError)
.textStyle(weight: .bold, color: .red, size: 10) .textStyle(weight: .bold, color: .red, size: 10)
} }
TextField("", text: $viewModel.registerUsername, prompt: Text("generic_username").foregroundColor(.gray)) TextField("", text: $viewModel.registerUsername, prompt: Text("Pseudo").foregroundColor(.gray))
.padding() .padding()
.background(Color.white.cornerRadius(9)) .background(Color.white.cornerRadius(9))
.frame(width: 300) .frame(width: 300)
@ -59,7 +59,6 @@ struct RegisterView: View {
.stroke(AllInColors.blueGrey800Color, lineWidth: 1) .stroke(AllInColors.blueGrey800Color, lineWidth: 1)
) )
.padding(.bottom, 8) .padding(.bottom, 8)
.autocorrectionDisabled(true)
.onChange(of: viewModel.registerUsername, perform: { value in .onChange(of: viewModel.registerUsername, perform: { value in
guard value != viewModel.registerUsername else { return } guard value != viewModel.registerUsername else { return }
if value.count > 25 { if value.count > 25 {
@ -75,7 +74,7 @@ struct RegisterView: View {
Text(emailError) Text(emailError)
.textStyle(weight: .bold, color: .red, size: 10) .textStyle(weight: .bold, color: .red, size: 10)
} }
TextField("", text: $viewModel.registerEmail, prompt: Text("generic_email").foregroundColor(.gray)) TextField("", text: $viewModel.registerEmail, prompt: Text("Email").foregroundColor(.gray))
.padding() .padding()
.keyboardType(.emailAddress) .keyboardType(.emailAddress)
.background(Color.white.cornerRadius(9)) .background(Color.white.cornerRadius(9))
@ -86,7 +85,6 @@ struct RegisterView: View {
.stroke(AllInColors.blueGrey800Color, lineWidth: 1) .stroke(AllInColors.blueGrey800Color, lineWidth: 1)
) )
.padding(.bottom, 8) .padding(.bottom, 8)
.autocorrectionDisabled(true)
.onChange(of: viewModel.registerEmail, perform: { value in .onChange(of: viewModel.registerEmail, perform: { value in
guard value != viewModel.registerEmail else { return } guard value != viewModel.registerEmail else { return }
if value.count > 50 { if value.count > 50 {
@ -107,9 +105,9 @@ struct RegisterView: View {
} }
Group { Group {
if isPasswordVisible { if isPasswordVisible {
SecureField("", text: $viewModel.registerPassword, prompt: Text("generic_password").foregroundColor(.gray)) SecureField("", text: $viewModel.registerPassword, prompt: Text("Mot de passe").foregroundColor(.gray))
} else { } else {
TextField("", text: $viewModel.registerPassword, prompt: Text("generic_password").foregroundColor(.gray)) TextField("", text: $viewModel.registerPassword, prompt: Text("Mot de passe").foregroundColor(.gray))
.autocapitalization(.none) .autocapitalization(.none)
} }
} }
@ -148,9 +146,9 @@ struct RegisterView: View {
Group { Group {
if isPasswordVisible { if isPasswordVisible {
SecureField("", text: $viewModel.registerConfirmPassword, prompt: Text("register_confirm_password").foregroundColor(.gray)) SecureField("", text: $viewModel.registerConfirmPassword, prompt: Text("Confirmation du Mot de passe").foregroundColor(.gray))
} else { } else {
TextField("", text: $viewModel.registerConfirmPassword, prompt: Text("register_confirm_password").foregroundColor(.gray)) TextField("", text: $viewModel.registerConfirmPassword, prompt: Text("Confirmation du Mot de passe").foregroundColor(.gray))
.autocapitalization(.none) .autocapitalization(.none)
} }
} }
@ -182,7 +180,7 @@ struct RegisterView: View {
Button(action: { Button(action: {
viewModel.register() viewModel.register()
}) { }) {
Text("generic_register") Text("S'inscrire")
.textStyle(weight: .bold, color: .white, size: 17) .textStyle(weight: .bold, color: .white, size: 17)
.frame(width: 300, height: 60) .frame(width: 300, height: 60)
@ -197,13 +195,13 @@ struct RegisterView: View {
Spacer() Spacer()
HStack(spacing: 4) { HStack(spacing: 0) {
Text("generic_already_have_account") Text("Tu as déjà un compte? ")
.textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 16) .textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 16)
NavigationLink(destination: LoginView().navigationBarBackButtonHidden(true)) NavigationLink(destination: LoginView().navigationBarBackButtonHidden(true))
{ {
Text("generic_login") Text("Se connecter")
.textStyle(weight: .semibold, color: AllInColors.darkPurpleColor, size: 16) .textStyle(weight: .semibold, color: AllInColors.darkPurpleColor, size: 16)
} }
} }
@ -217,7 +215,7 @@ struct RegisterView: View {
} }
.alert(isPresented: $viewModel.showErrorMessage) { .alert(isPresented: $viewModel.showErrorMessage) {
Alert(title: Text("register_error_title"), message: Text(viewModel.errorMessage ?? ""), dismissButton: .default(Text("generic_ok"))) Alert(title: Text("Erreur lors de l'enregistrement"), message: Text(viewModel.errorMessage ?? ""), dismissButton: .default(Text("OK")))
} }
.background(AllInColors.startBackgroundColor) .background(AllInColors.startBackgroundColor)
.onSubmit { .onSubmit {

@ -15,7 +15,7 @@ struct WelcomeView: View {
VStack(alignment: .leading, spacing: -5) { VStack(alignment: .leading, spacing: -5) {
Spacer() Spacer()
Spacer() Spacer()
Text("welcome_title") Text("Bienvenue sur,")
.textStyle(weight: .bold, color: AllInColors.darkBlueColor, size: 30) .textStyle(weight: .bold, color: AllInColors.darkBlueColor, size: 30)
.frame(alignment: .topLeading) .frame(alignment: .topLeading)
.frame(width: geometry.size.width, alignment: .topLeading) .frame(width: geometry.size.width, alignment: .topLeading)
@ -54,7 +54,7 @@ struct WelcomeView: View {
endPoint: UnitPoint(x: 0.5, y: 0.85) endPoint: UnitPoint(x: 0.5, y: 0.85)
)) ))
VStack() { VStack() {
Text("welcome_subtitle") Text("Récupère tes Allcoins et vient parier avec tes amis pour prouver qui est le meilleur.")
.textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 15) .textStyle(weight: .regular, color: AllInColors.darkBlueColor, size: 15)
.frame(width: geometry.size.width*0.8, alignment: .leading) .frame(width: geometry.size.width*0.8, alignment: .leading)
.padding([.leading,.trailing], 40) .padding([.leading,.trailing], 40)
@ -64,20 +64,20 @@ struct WelcomeView: View {
NavigationLink(destination: RegisterView().navigationBarBackButtonHidden(true)) NavigationLink(destination: RegisterView().navigationBarBackButtonHidden(true))
{ {
Text("welcome_join") Text("Rejoindre")
.textStyle(weight: .bold, color: AllInColors.whiteColor, size: 17) .textStyle(weight: .bold, color: AllInColors.whiteColor, size: 17)
.frame(width: min(geometry.size.width*0.85, 500), height: 50) .frame(width: min(geometry.size.width*0.85, 500), height: 50)
.background(AllInColors.loginPurpleColor) .background(AllInColors.loginPurpleColor)
.cornerRadius(30) .cornerRadius(30)
} }
HStack(spacing: 4) { HStack(spacing: 0) {
Text("generic_already_have_account") Text("Tu as déja un compte? ")
.textStyle(weight: .regular, color: AllInColors.loginPurpleColor, size: 16) .textStyle(weight: .regular, color: AllInColors.loginPurpleColor, size: 16)
NavigationLink(destination: LoginView().navigationBarBackButtonHidden(true)) NavigationLink(destination: LoginView().navigationBarBackButtonHidden(true))
{ {
Text("generic_login") Text("Connexion")
.textStyle(weight: .semibold, color: AllInColors.loginPurpleColor, size: 16) .textStyle(weight: .semibold, color: AllInColors.loginPurpleColor, size: 16)
.underline() .underline()
} }

@ -9,20 +9,16 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */; }; 120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */; };
1209191A2B56DC6C00D0FA29 /* DropDownAnswerMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */; }; 1209191A2B56DC6C00D0FA29 /* DropDownAnswerMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */; };
12228A212C1760D2008524F4 /* BinaryBetLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12228A202C1760D2008524F4 /* BinaryBetLine.swift */; };
12228A232C176117008524F4 /* CustomBetLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12228A222C176117008524F4 /* CustomBetLine.swift */; };
123225D92B67B46100D30BB3 /* BetEndingValidationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */; }; 123225D92B67B46100D30BB3 /* BetEndingValidationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */; };
123225DB2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */; }; 123225DB2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */; };
123590B42B51792000F7AEBD /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B32B51792000F7AEBD /* DetailsView.swift */; }; 123590B42B51792000F7AEBD /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B32B51792000F7AEBD /* DetailsView.swift */; };
123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B52B5537E200F7AEBD /* ResultBanner.swift */; }; 123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B52B5537E200F7AEBD /* ResultBanner.swift */; };
123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */; }; 123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */; };
123F31DB2C0F26E8009B6D65 /* userPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123F31DA2C0F26E8009B6D65 /* userPicture.swift */; };
123F31E02C11E99E009B6D65 /* asyncCachedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */; };
1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */; }; 1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */; };
1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF612B4EC67000374ABF /* ReviewCard.swift */; }; 1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF612B4EC67000374ABF /* ReviewCard.swift */; };
129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */; }; 129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */; };
12A9E4942C07132600AB8677 /* EmptyInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A9E4932C07132600AB8677 /* EmptyInfo.swift */; };
12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */; }; 12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */; };
12C3704A2B5D5BD000CD9F0F /* ParticiationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */; };
EC0193782B25BF16005D81E6 /* AllcoinsCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */; }; EC0193782B25BF16005D81E6 /* AllcoinsCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */; };
EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; }; EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; };
EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */; }; EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */; };
@ -36,7 +32,6 @@
EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770A2B24D9160060E34D /* WelcomeView.swift */; }; EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770A2B24D9160060E34D /* WelcomeView.swift */; };
EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770C2B24DB7A0060E34D /* Extensions.swift */; }; EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770C2B24DB7A0060E34D /* Extensions.swift */; };
EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770E2B24FCB00060E34D /* RegisterView.swift */; }; EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770E2B24FCB00060E34D /* RegisterView.swift */; };
EC34FDCE2C0DB46C0020A371 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC34FDCD2C0DB46C0020A371 /* Config.swift */; };
EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; }; EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; };
EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC60C5672B5A83FB00FFD6EF /* StubLib */; }; EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC60C5672B5A83FB00FFD6EF /* StubLib */; };
EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; }; EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; };
@ -60,15 +55,13 @@
EC6B96B72B24B4CC00FC1C58 /* AllInUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96B62B24B4CC00FC1C58 /* AllInUITests.swift */; }; EC6B96B72B24B4CC00FC1C58 /* AllInUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96B62B24B4CC00FC1C58 /* AllInUITests.swift */; };
EC6B96B92B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96B82B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift */; }; EC6B96B92B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96B82B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift */; };
EC6B96CC2B24B7E500FC1C58 /* IAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96CB2B24B7E500FC1C58 /* IAuthService.swift */; }; EC6B96CC2B24B7E500FC1C58 /* IAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96CB2B24B7E500FC1C58 /* IAuthService.swift */; };
EC6B96CF2B24B8D900FC1C58 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96CE2B24B8D900FC1C58 /* Config.swift */; };
EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D02B24BAE800FC1C58 /* AuthService.swift */; }; EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D02B24BAE800FC1C58 /* AuthService.swift */; };
EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D42B24BE0E00FC1C58 /* MainView.swift */; }; EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D42B24BE0E00FC1C58 /* MainView.swift */; };
EC6B96D82B24BF2100FC1C58 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D72B24BF2100FC1C58 /* Menu.swift */; }; EC6B96D82B24BF2100FC1C58 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6B96D72B24BF2100FC1C58 /* Menu.swift */; };
EC7A882B2B28D1E0004F226A /* DropDownMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7A882A2B28D1E0004F226A /* DropDownMenu.swift */; }; EC7A882B2B28D1E0004F226A /* DropDownMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7A882A2B28D1E0004F226A /* DropDownMenu.swift */; };
EC7A882D2B28D8A1004F226A /* CreationBetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7A882C2B28D8A1004F226A /* CreationBetView.swift */; }; EC7A882D2B28D8A1004F226A /* CreationBetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7A882C2B28D8A1004F226A /* CreationBetView.swift */; };
EC7A882F2B28E6BE004F226A /* ConfidentialityButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7A882E2B28E6BE004F226A /* ConfidentialityButton.swift */; }; EC7A882F2B28E6BE004F226A /* ConfidentialityButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7A882E2B28E6BE004F226A /* ConfidentialityButton.swift */; };
EC7EF7482B87E3E00022B5D9 /* Delegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7EF7472B87E3E00022B5D9 /* Delegates.swift */; };
EC7EF74A2B87E3FD0022B5D9 /* QuickAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7EF7492B87E3FD0022B5D9 /* QuickAction.swift */; };
EC7EF74C2B87F2AF0022B5D9 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7EF74B2B87F2AF0022B5D9 /* NotificationService.swift */; };
EC89F7BD2B250D66003821CE /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC89F7BC2B250D66003821CE /* LoginView.swift */; }; EC89F7BD2B250D66003821CE /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC89F7BC2B250D66003821CE /* LoginView.swift */; };
EC9464E92B7413E1004EEBD8 /* BetEndingValidationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC9464E82B7413E1004EEBD8 /* BetEndingValidationViewModel.swift */; }; EC9464E92B7413E1004EEBD8 /* BetEndingValidationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC9464E82B7413E1004EEBD8 /* BetEndingValidationViewModel.swift */; };
ECA9D1C92B2D9ADA0076E0EC /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA9D1C82B2D9ADA0076E0EC /* UserInfo.swift */; }; ECA9D1C92B2D9ADA0076E0EC /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA9D1C82B2D9ADA0076E0EC /* UserInfo.swift */; };
@ -79,22 +72,11 @@
ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB26A1A2B40746C00FE06B3 /* FriendsViewModel.swift */; }; ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB26A1A2B40746C00FE06B3 /* FriendsViewModel.swift */; };
ECB357322B3CA69300045D41 /* DependencyInjection.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = ECB357302B3CA69300045D41 /* DependencyInjection.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; ECB357322B3CA69300045D41 /* DependencyInjection.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = ECB357302B3CA69300045D41 /* DependencyInjection.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB7BC672B2F1ADF002A6654 /* LoginViewModel.swift */; }; ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB7BC672B2F1ADF002A6654 /* LoginViewModel.swift */; };
ECB7BC6A2B2F410A002A6654 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB7BC692B2F410A002A6654 /* AppDelegate.swift */; };
ECB7BC6C2B2F43EE002A6654 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB7BC6B2B2F43EE002A6654 /* AppState.swift */; }; ECB7BC6C2B2F43EE002A6654 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB7BC6B2B2F43EE002A6654 /* AppState.swift */; };
ECB7BC702B336E28002A6654 /* RegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB7BC6F2B336E28002A6654 /* RegisterViewModel.swift */; }; ECB7BC702B336E28002A6654 /* RegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB7BC6F2B336E28002A6654 /* RegisterViewModel.swift */; };
ECCD244A2B4DE8010071FA9E /* Api in Frameworks */ = {isa = PBXBuildFile; productRef = ECCD24492B4DE8010071FA9E /* Api */; }; ECCD244A2B4DE8010071FA9E /* Api in Frameworks */ = {isa = PBXBuildFile; productRef = ECCD24492B4DE8010071FA9E /* Api */; };
ECDDD48A2BF4A7920009223A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = ECDDD48C2BF4A7920009223A /* Localizable.strings */; };
ECDDD48F2C034A420009223A /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECDDD48E2C034A420009223A /* ProfileView.swift */; };
ECED90B52B6D9CEC00F50937 /* DailyGiftPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECED90B42B6D9CEC00F50937 /* DailyGiftPage.swift */; }; ECED90B52B6D9CEC00F50937 /* DailyGiftPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECED90B42B6D9CEC00F50937 /* DailyGiftPage.swift */; };
ECF872662B9266C000F9D240 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ECF872652B9266C000F9D240 /* WidgetKit.framework */; };
ECF872682B9266C000F9D240 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ECF872672B9266C000F9D240 /* SwiftUI.framework */; };
ECF8726B2B9266C000F9D240 /* AllInWidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF8726A2B9266C000F9D240 /* AllInWidgetsBundle.swift */; };
ECF8726D2B9266C000F9D240 /* AllInWidgetsLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF8726C2B9266C000F9D240 /* AllInWidgetsLiveActivity.swift */; };
ECF8726F2B9266C000F9D240 /* AllInCoinsWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF8726E2B9266C000F9D240 /* AllInCoinsWidget.swift */; };
ECF872722B9266C100F9D240 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ECF872712B9266C100F9D240 /* Assets.xcassets */; };
ECF872742B9266C100F9D240 /* AllInWidgets.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = ECF872702B9266C000F9D240 /* AllInWidgets.intentdefinition */; };
ECF872752B9266C100F9D240 /* AllInWidgets.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = ECF872702B9266C000F9D240 /* AllInWidgets.intentdefinition */; };
ECF872782B9266C100F9D240 /* AllInWidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = ECF872642B9266C000F9D240 /* AllInWidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
ECF872822B92696C00F9D240 /* Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF872812B92696C00F9D240 /* Provider.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -112,13 +94,6 @@
remoteGlobalIDString = EC6B96972B24B4CC00FC1C58; remoteGlobalIDString = EC6B96972B24B4CC00FC1C58;
remoteInfo = AllIn; remoteInfo = AllIn;
}; };
ECF872762B9266C100F9D240 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = EC6B96902B24B4CC00FC1C58 /* Project object */;
proxyType = 1;
remoteGlobalIDString = ECF872632B9266C000F9D240;
remoteInfo = AllInWidgetsExtension;
};
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@ -133,17 +108,6 @@
name = "Embed Frameworks"; name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
ECF872792B9266C100F9D240 /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
ECF872782B9266C100F9D240 /* AllInWidgetsExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@ -151,20 +115,16 @@
120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownAnswerMenu.swift; sourceTree = "<group>"; }; 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownAnswerMenu.swift; sourceTree = "<group>"; };
122278B72B4BDE1100E632AA /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 122278B72B4BDE1100E632AA /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; };
122278B92B4BDE9500E632AA /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Package.swift; path = ../Model/Package.swift; sourceTree = "<group>"; }; 122278B92B4BDE9500E632AA /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Package.swift; path = ../Model/Package.swift; sourceTree = "<group>"; };
12228A202C1760D2008524F4 /* BinaryBetLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryBetLine.swift; sourceTree = "<group>"; };
12228A222C176117008524F4 /* CustomBetLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomBetLine.swift; sourceTree = "<group>"; };
123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetEndingValidationView.swift; sourceTree = "<group>"; }; 123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetEndingValidationView.swift; sourceTree = "<group>"; };
123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceFinalAnswerCell.swift; sourceTree = "<group>"; }; 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceFinalAnswerCell.swift; sourceTree = "<group>"; };
123590B32B51792000F7AEBD /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; }; 123590B32B51792000F7AEBD /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; };
123590B52B5537E200F7AEBD /* ResultBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultBanner.swift; sourceTree = "<group>"; }; 123590B52B5537E200F7AEBD /* ResultBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultBanner.swift; sourceTree = "<group>"; };
123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.swift; sourceTree = "<group>"; }; 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.swift; sourceTree = "<group>"; };
123F31DA2C0F26E8009B6D65 /* userPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = userPicture.swift; sourceTree = "<group>"; };
123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = asyncCachedImage.swift; sourceTree = "<group>"; };
1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetView.swift; sourceTree = "<group>"; }; 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetView.swift; sourceTree = "<group>"; };
1244EF612B4EC67000374ABF /* ReviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewCard.swift; sourceTree = "<group>"; }; 1244EF612B4EC67000374ABF /* ReviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewCard.swift; sourceTree = "<group>"; };
129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OddCapsule.swift; sourceTree = "<group>"; }; 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OddCapsule.swift; sourceTree = "<group>"; };
12A9E4932C07132600AB8677 /* EmptyInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyInfo.swift; sourceTree = "<group>"; };
12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetLineLoading.swift; sourceTree = "<group>"; }; 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetLineLoading.swift; sourceTree = "<group>"; };
12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticiationCell.swift; sourceTree = "<group>"; };
EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCapsule.swift; sourceTree = "<group>"; }; EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCapsule.swift; sourceTree = "<group>"; };
EC0193792B25C12B005D81E6 /* BetCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetCard.swift; sourceTree = "<group>"; }; EC0193792B25C12B005D81E6 /* BetCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetCard.swift; sourceTree = "<group>"; };
EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCounter.swift; sourceTree = "<group>"; }; EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCounter.swift; sourceTree = "<group>"; };
@ -178,7 +138,6 @@
EC30770A2B24D9160060E34D /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; }; EC30770A2B24D9160060E34D /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
EC30770C2B24DB7A0060E34D /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; }; EC30770C2B24DB7A0060E34D /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
EC30770E2B24FCB00060E34D /* RegisterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterView.swift; sourceTree = "<group>"; }; EC30770E2B24FCB00060E34D /* RegisterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterView.swift; sourceTree = "<group>"; };
EC34FDCD2C0DB46C0020A371 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = "<group>"; };
EC650A412B25C817003AFCAD /* Friend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Friend.swift; sourceTree = "<group>"; }; EC650A412B25C817003AFCAD /* Friend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Friend.swift; sourceTree = "<group>"; };
EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterMenu.swift; sourceTree = "<group>"; }; EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterMenu.swift; sourceTree = "<group>"; };
EC650A452B25D686003AFCAD /* RankingRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankingRow.swift; sourceTree = "<group>"; }; EC650A452B25D686003AFCAD /* RankingRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankingRow.swift; sourceTree = "<group>"; };
@ -203,15 +162,13 @@
EC6B96B62B24B4CC00FC1C58 /* AllInUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInUITests.swift; sourceTree = "<group>"; }; EC6B96B62B24B4CC00FC1C58 /* AllInUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInUITests.swift; sourceTree = "<group>"; };
EC6B96B82B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInUITestsLaunchTests.swift; sourceTree = "<group>"; }; EC6B96B82B24B4CC00FC1C58 /* AllInUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInUITestsLaunchTests.swift; sourceTree = "<group>"; };
EC6B96CB2B24B7E500FC1C58 /* IAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAuthService.swift; sourceTree = "<group>"; }; EC6B96CB2B24B7E500FC1C58 /* IAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAuthService.swift; sourceTree = "<group>"; };
EC6B96CE2B24B8D900FC1C58 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = "<group>"; };
EC6B96D02B24BAE800FC1C58 /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = "<group>"; }; EC6B96D02B24BAE800FC1C58 /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = "<group>"; };
EC6B96D42B24BE0E00FC1C58 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; }; EC6B96D42B24BE0E00FC1C58 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
EC6B96D72B24BF2100FC1C58 /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = "<group>"; }; EC6B96D72B24BF2100FC1C58 /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = "<group>"; };
EC7A882A2B28D1E0004F226A /* DropDownMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownMenu.swift; sourceTree = "<group>"; }; EC7A882A2B28D1E0004F226A /* DropDownMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownMenu.swift; sourceTree = "<group>"; };
EC7A882C2B28D8A1004F226A /* CreationBetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreationBetView.swift; sourceTree = "<group>"; }; EC7A882C2B28D8A1004F226A /* CreationBetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreationBetView.swift; sourceTree = "<group>"; };
EC7A882E2B28E6BE004F226A /* ConfidentialityButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfidentialityButton.swift; sourceTree = "<group>"; }; EC7A882E2B28E6BE004F226A /* ConfidentialityButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfidentialityButton.swift; sourceTree = "<group>"; };
EC7EF7472B87E3E00022B5D9 /* Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegates.swift; sourceTree = "<group>"; };
EC7EF7492B87E3FD0022B5D9 /* QuickAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickAction.swift; sourceTree = "<group>"; };
EC7EF74B2B87F2AF0022B5D9 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
EC89F7BC2B250D66003821CE /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; }; EC89F7BC2B250D66003821CE /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
EC9464E82B7413E1004EEBD8 /* BetEndingValidationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetEndingValidationViewModel.swift; sourceTree = "<group>"; }; EC9464E82B7413E1004EEBD8 /* BetEndingValidationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetEndingValidationViewModel.swift; sourceTree = "<group>"; };
ECA9D1C82B2D9ADA0076E0EC /* UserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfo.swift; sourceTree = "<group>"; }; ECA9D1C82B2D9ADA0076E0EC /* UserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfo.swift; sourceTree = "<group>"; };
@ -223,24 +180,10 @@
ECB3572E2B3CA3C300045D41 /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; ECB3572E2B3CA3C300045D41 /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; };
ECB357302B3CA69300045D41 /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; ECB357302B3CA69300045D41 /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; };
ECB7BC672B2F1ADF002A6654 /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; }; ECB7BC672B2F1ADF002A6654 /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
ECB7BC692B2F410A002A6654 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
ECB7BC6B2B2F43EE002A6654 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; }; ECB7BC6B2B2F43EE002A6654 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
ECB7BC6F2B336E28002A6654 /* RegisterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterViewModel.swift; sourceTree = "<group>"; }; ECB7BC6F2B336E28002A6654 /* RegisterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterViewModel.swift; sourceTree = "<group>"; };
ECDDD48B2BF4A7920009223A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
ECDDD48D2BF4A7970009223A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
ECDDD48E2C034A420009223A /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
ECED90B42B6D9CEC00F50937 /* DailyGiftPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyGiftPage.swift; sourceTree = "<group>"; }; ECED90B42B6D9CEC00F50937 /* DailyGiftPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyGiftPage.swift; sourceTree = "<group>"; };
ECF872642B9266C000F9D240 /* AllInWidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AllInWidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
ECF872652B9266C000F9D240 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
ECF872672B9266C000F9D240 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
ECF8726A2B9266C000F9D240 /* AllInWidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInWidgetsBundle.swift; sourceTree = "<group>"; };
ECF8726C2B9266C000F9D240 /* AllInWidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInWidgetsLiveActivity.swift; sourceTree = "<group>"; };
ECF8726E2B9266C000F9D240 /* AllInCoinsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllInCoinsWidget.swift; sourceTree = "<group>"; };
ECF872702B9266C000F9D240 /* AllInWidgets.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = AllInWidgets.intentdefinition; sourceTree = "<group>"; };
ECF872712B9266C100F9D240 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
ECF872732B9266C100F9D240 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
ECF872812B92696C00F9D240 /* Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Provider.swift; sourceTree = "<group>"; };
ECF872852B93B9D900F9D240 /* AllIn.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AllIn.entitlements; sourceTree = "<group>"; };
ECF872862B93BA7D00F9D240 /* AllInWidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AllInWidgetsExtension.entitlements; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -268,26 +211,9 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
ECF872612B9266C000F9D240 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
ECF872682B9266C000F9D240 /* SwiftUI.framework in Frameworks */,
ECF872662B9266C000F9D240 /* WidgetKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
123F31DE2C11E979009B6D65 /* Utils */ = {
isa = PBXGroup;
children = (
123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */,
);
path = Utils;
sourceTree = "<group>";
};
EC1D15402B715A7A0094833E /* Protocols */ = { EC1D15402B715A7A0094833E /* Protocols */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -299,11 +225,9 @@
EC6B968F2B24B4CC00FC1C58 = { EC6B968F2B24B4CC00FC1C58 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
ECF872862B93BA7D00F9D240 /* AllInWidgetsExtension.entitlements */,
EC6B969A2B24B4CC00FC1C58 /* AllIn */, EC6B969A2B24B4CC00FC1C58 /* AllIn */,
EC6B96AB2B24B4CC00FC1C58 /* AllInTests */, EC6B96AB2B24B4CC00FC1C58 /* AllInTests */,
EC6B96B52B24B4CC00FC1C58 /* AllInUITests */, EC6B96B52B24B4CC00FC1C58 /* AllInUITests */,
ECF872692B9266C000F9D240 /* AllInWidgets */,
EC6B96992B24B4CC00FC1C58 /* Products */, EC6B96992B24B4CC00FC1C58 /* Products */,
ECB3572D2B3CA3BD00045D41 /* Frameworks */, ECB3572D2B3CA3BD00045D41 /* Frameworks */,
); );
@ -315,7 +239,6 @@
EC6B96982B24B4CC00FC1C58 /* AllIn.app */, EC6B96982B24B4CC00FC1C58 /* AllIn.app */,
EC6B96A82B24B4CC00FC1C58 /* AllInTests.xctest */, EC6B96A82B24B4CC00FC1C58 /* AllInTests.xctest */,
EC6B96B22B24B4CC00FC1C58 /* AllInUITests.xctest */, EC6B96B22B24B4CC00FC1C58 /* AllInUITests.xctest */,
ECF872642B9266C000F9D240 /* AllInWidgetsExtension.appex */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -323,9 +246,6 @@
EC6B969A2B24B4CC00FC1C58 /* AllIn */ = { EC6B969A2B24B4CC00FC1C58 /* AllIn */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
123F31DE2C11E979009B6D65 /* Utils */,
ECF872852B93B9D900F9D240 /* AllIn.entitlements */,
EC7EF7462B87E3470022B5D9 /* QuickActions */,
ECB7BC662B2F1AAD002A6654 /* ViewModels */, ECB7BC662B2F1AAD002A6654 /* ViewModels */,
EC6B96D62B24BEBD00FC1C58 /* Components */, EC6B96D62B24BEBD00FC1C58 /* Components */,
EC6B96D32B24BC6700FC1C58 /* Views */, EC6B96D32B24BC6700FC1C58 /* Views */,
@ -336,6 +256,7 @@
EC6B969D2B24B4CC00FC1C58 /* ContentView.swift */, EC6B969D2B24B4CC00FC1C58 /* ContentView.swift */,
EC6B969F2B24B4CC00FC1C58 /* Assets.xcassets */, EC6B969F2B24B4CC00FC1C58 /* Assets.xcassets */,
EC650A612B28CB72003AFCAD /* Launch Screen.storyboard */, EC650A612B28CB72003AFCAD /* Launch Screen.storyboard */,
ECB7BC692B2F410A002A6654 /* AppDelegate.swift */,
ECB7BC6B2B2F43EE002A6654 /* AppState.swift */, ECB7BC6B2B2F43EE002A6654 /* AppState.swift */,
EC6B96A12B24B4CC00FC1C58 /* Preview Content */, EC6B96A12B24B4CC00FC1C58 /* Preview Content */,
); );
@ -372,7 +293,6 @@
children = ( children = (
EC1D15402B715A7A0094833E /* Protocols */, EC1D15402B715A7A0094833E /* Protocols */,
EC6B96D02B24BAE800FC1C58 /* AuthService.swift */, EC6B96D02B24BAE800FC1C58 /* AuthService.swift */,
EC7EF74B2B87F2AF0022B5D9 /* NotificationService.swift */,
); );
path = Services; path = Services;
sourceTree = "<group>"; sourceTree = "<group>";
@ -380,9 +300,8 @@
EC6B96CD2B24B8A300FC1C58 /* Ressources */ = { EC6B96CD2B24B8A300FC1C58 /* Ressources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
EC6B96CE2B24B8D900FC1C58 /* Config.swift */,
EC3077082B24CF7F0060E34D /* Colors.swift */, EC3077082B24CF7F0060E34D /* Colors.swift */,
ECDDD48C2BF4A7920009223A /* Localizable.strings */,
EC34FDCD2C0DB46C0020A371 /* Config.swift */,
); );
path = Ressources; path = Ressources;
sourceTree = "<group>"; sourceTree = "<group>";
@ -412,7 +331,6 @@
123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */, 123225D82B67B46100D30BB3 /* BetEndingValidationView.swift */,
EC17A15D2B6A955E008A8679 /* CurrentBetView.swift */, EC17A15D2B6A955E008A8679 /* CurrentBetView.swift */,
ECED90B42B6D9CEC00F50937 /* DailyGiftPage.swift */, ECED90B42B6D9CEC00F50937 /* DailyGiftPage.swift */,
ECDDD48E2C034A420009223A /* ProfileView.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@ -444,25 +362,13 @@
120919172B56D0AE00D0FA29 /* ParticipationModal.swift */, 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */,
120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */, 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */,
12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */, 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */,
12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */,
123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */, 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */,
129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */, 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */,
12A9E4932C07132600AB8677 /* EmptyInfo.swift */,
123F31DA2C0F26E8009B6D65 /* userPicture.swift */,
12228A202C1760D2008524F4 /* BinaryBetLine.swift */,
12228A222C176117008524F4 /* CustomBetLine.swift */,
); );
path = Components; path = Components;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
EC7EF7462B87E3470022B5D9 /* QuickActions */ = {
isa = PBXGroup;
children = (
EC7EF7472B87E3E00022B5D9 /* Delegates.swift */,
EC7EF7492B87E3FD0022B5D9 /* QuickAction.swift */,
);
path = QuickActions;
sourceTree = "<group>";
};
ECB3572D2B3CA3BD00045D41 /* Frameworks */ = { ECB3572D2B3CA3BD00045D41 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -470,8 +376,6 @@
122278B72B4BDE1100E632AA /* DependencyInjection.framework */, 122278B72B4BDE1100E632AA /* DependencyInjection.framework */,
ECB357302B3CA69300045D41 /* DependencyInjection.framework */, ECB357302B3CA69300045D41 /* DependencyInjection.framework */,
ECB3572E2B3CA3C300045D41 /* DependencyInjection.framework */, ECB3572E2B3CA3C300045D41 /* DependencyInjection.framework */,
ECF872652B9266C000F9D240 /* WidgetKit.framework */,
ECF872672B9266C000F9D240 /* SwiftUI.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -493,20 +397,6 @@
path = ViewModels; path = ViewModels;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
ECF872692B9266C000F9D240 /* AllInWidgets */ = {
isa = PBXGroup;
children = (
ECF8726A2B9266C000F9D240 /* AllInWidgetsBundle.swift */,
ECF8726C2B9266C000F9D240 /* AllInWidgetsLiveActivity.swift */,
ECF8726E2B9266C000F9D240 /* AllInCoinsWidget.swift */,
ECF872812B92696C00F9D240 /* Provider.swift */,
ECF872702B9266C000F9D240 /* AllInWidgets.intentdefinition */,
ECF872712B9266C100F9D240 /* Assets.xcassets */,
ECF872732B9266C100F9D240 /* Info.plist */,
);
path = AllInWidgets;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@ -518,12 +408,10 @@
EC6B96952B24B4CC00FC1C58 /* Frameworks */, EC6B96952B24B4CC00FC1C58 /* Frameworks */,
EC6B96962B24B4CC00FC1C58 /* Resources */, EC6B96962B24B4CC00FC1C58 /* Resources */,
ECB357332B3CA69300045D41 /* Embed Frameworks */, ECB357332B3CA69300045D41 /* Embed Frameworks */,
ECF872792B9266C100F9D240 /* Embed Foundation Extensions */,
); );
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
ECF872772B9266C100F9D240 /* PBXTargetDependency */,
); );
name = AllIn; name = AllIn;
packageProductDependencies = ( packageProductDependencies = (
@ -571,23 +459,6 @@
productReference = EC6B96B22B24B4CC00FC1C58 /* AllInUITests.xctest */; productReference = EC6B96B22B24B4CC00FC1C58 /* AllInUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing"; productType = "com.apple.product-type.bundle.ui-testing";
}; };
ECF872632B9266C000F9D240 /* AllInWidgetsExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = ECF8727C2B9266C100F9D240 /* Build configuration list for PBXNativeTarget "AllInWidgetsExtension" */;
buildPhases = (
ECF872602B9266C000F9D240 /* Sources */,
ECF872612B9266C000F9D240 /* Frameworks */,
ECF872622B9266C000F9D240 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = AllInWidgetsExtension;
productName = AllInWidgetsExtension;
productReference = ECF872642B9266C000F9D240 /* AllInWidgetsExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
@ -609,9 +480,6 @@
CreatedOnToolsVersion = 14.3.1; CreatedOnToolsVersion = 14.3.1;
TestTargetID = EC6B96972B24B4CC00FC1C58; TestTargetID = EC6B96972B24B4CC00FC1C58;
}; };
ECF872632B9266C000F9D240 = {
CreatedOnToolsVersion = 14.3.1;
};
}; };
}; };
buildConfigurationList = EC6B96932B24B4CC00FC1C58 /* Build configuration list for PBXProject "AllInApp" */; buildConfigurationList = EC6B96932B24B4CC00FC1C58 /* Build configuration list for PBXProject "AllInApp" */;
@ -621,7 +489,6 @@
knownRegions = ( knownRegions = (
en, en,
Base, Base,
fr,
); );
mainGroup = EC6B968F2B24B4CC00FC1C58; mainGroup = EC6B968F2B24B4CC00FC1C58;
packageReferences = ( packageReferences = (
@ -633,7 +500,6 @@
EC6B96972B24B4CC00FC1C58 /* AllIn */, EC6B96972B24B4CC00FC1C58 /* AllIn */,
EC6B96A72B24B4CC00FC1C58 /* AllInTests */, EC6B96A72B24B4CC00FC1C58 /* AllInTests */,
EC6B96B12B24B4CC00FC1C58 /* AllInUITests */, EC6B96B12B24B4CC00FC1C58 /* AllInUITests */,
ECF872632B9266C000F9D240 /* AllInWidgetsExtension */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -644,7 +510,6 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
EC650A622B28CB72003AFCAD /* Launch Screen.storyboard in Resources */, EC650A622B28CB72003AFCAD /* Launch Screen.storyboard in Resources */,
ECDDD48A2BF4A7920009223A /* Localizable.strings in Resources */,
EC6B96A32B24B4CC00FC1C58 /* Preview Assets.xcassets in Resources */, EC6B96A32B24B4CC00FC1C58 /* Preview Assets.xcassets in Resources */,
EC6B96A02B24B4CC00FC1C58 /* Assets.xcassets in Resources */, EC6B96A02B24B4CC00FC1C58 /* Assets.xcassets in Resources */,
); );
@ -664,14 +529,6 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
ECF872622B9266C000F9D240 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
ECF872722B9266C100F9D240 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@ -681,25 +538,21 @@
files = ( files = (
EC6B96CC2B24B7E500FC1C58 /* IAuthService.swift in Sources */, EC6B96CC2B24B7E500FC1C58 /* IAuthService.swift in Sources */,
ECB26A172B4073F100FE06B3 /* CreationBetViewModel.swift in Sources */, ECB26A172B4073F100FE06B3 /* CreationBetViewModel.swift in Sources */,
12228A232C176117008524F4 /* CustomBetLine.swift in Sources */,
EC3077092B24CF7F0060E34D /* Colors.swift in Sources */, EC3077092B24CF7F0060E34D /* Colors.swift in Sources */,
ECB7BC6A2B2F410A002A6654 /* AppDelegate.swift in Sources */,
EC6B969E2B24B4CC00FC1C58 /* ContentView.swift in Sources */, EC6B969E2B24B4CC00FC1C58 /* ContentView.swift in Sources */,
EC89F7BD2B250D66003821CE /* LoginView.swift in Sources */, EC89F7BD2B250D66003821CE /* LoginView.swift in Sources */,
EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */, EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */,
120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */, 120919182B56D0AE00D0FA29 /* ParticipationModal.swift in Sources */,
123F31DB2C0F26E8009B6D65 /* userPicture.swift in Sources */,
ECB26A132B406A9400FE06B3 /* BetViewModel.swift in Sources */, ECB26A132B406A9400FE06B3 /* BetViewModel.swift in Sources */,
EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */, EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */,
EC650A522B2794DD003AFCAD /* BetView.swift in Sources */, EC650A522B2794DD003AFCAD /* BetView.swift in Sources */,
EC6B969C2B24B4CC00FC1C58 /* AllInApp.swift in Sources */, EC6B969C2B24B4CC00FC1C58 /* AllInApp.swift in Sources */,
123590B42B51792000F7AEBD /* DetailsView.swift in Sources */, 123590B42B51792000F7AEBD /* DetailsView.swift in Sources */,
ECB26A192B40744F00FE06B3 /* RankingViewModel.swift in Sources */, ECB26A192B40744F00FE06B3 /* RankingViewModel.swift in Sources */,
123F31E02C11E99E009B6D65 /* asyncCachedImage.swift in Sources */,
EC650A502B2793D5003AFCAD /* TextCapsule.swift in Sources */, EC650A502B2793D5003AFCAD /* TextCapsule.swift in Sources */,
EC650A482B25DCFF003AFCAD /* UsersPreview.swift in Sources */, EC650A482B25DCFF003AFCAD /* UsersPreview.swift in Sources */,
EC17A15E2B6A955E008A8679 /* CurrentBetView.swift in Sources */, EC17A15E2B6A955E008A8679 /* CurrentBetView.swift in Sources */,
EC7EF7482B87E3E00022B5D9 /* Delegates.swift in Sources */,
12A9E4942C07132600AB8677 /* EmptyInfo.swift in Sources */,
EC650A462B25D686003AFCAD /* RankingRow.swift in Sources */, EC650A462B25D686003AFCAD /* RankingRow.swift in Sources */,
EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */, EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */,
EC650A422B25C817003AFCAD /* Friend.swift in Sources */, EC650A422B25C817003AFCAD /* Friend.swift in Sources */,
@ -707,14 +560,13 @@
ECB7BC702B336E28002A6654 /* RegisterViewModel.swift in Sources */, ECB7BC702B336E28002A6654 /* RegisterViewModel.swift in Sources */,
EC17A1602B6A9781008A8679 /* CurrentBetViewModel.swift in Sources */, EC17A1602B6A9781008A8679 /* CurrentBetViewModel.swift in Sources */,
EC650A4C2B25E9C7003AFCAD /* RankingView.swift in Sources */, EC650A4C2B25E9C7003AFCAD /* RankingView.swift in Sources */,
ECDDD48F2C034A420009223A /* ProfileView.swift in Sources */,
EC9464E92B7413E1004EEBD8 /* BetEndingValidationViewModel.swift in Sources */, EC9464E92B7413E1004EEBD8 /* BetEndingValidationViewModel.swift in Sources */,
EC7A882B2B28D1E0004F226A /* DropDownMenu.swift in Sources */, EC7A882B2B28D1E0004F226A /* DropDownMenu.swift in Sources */,
EC7A882D2B28D8A1004F226A /* CreationBetView.swift in Sources */, EC7A882D2B28D8A1004F226A /* CreationBetView.swift in Sources */,
ECED90B52B6D9CEC00F50937 /* DailyGiftPage.swift in Sources */, ECED90B52B6D9CEC00F50937 /* DailyGiftPage.swift in Sources */,
EC6B96CF2B24B8D900FC1C58 /* Config.swift in Sources */,
1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */, 1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */,
EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */, EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */,
EC34FDCE2C0DB46C0020A371 /* Config.swift in Sources */,
EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */, EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */,
EC6B96D82B24BF2100FC1C58 /* Menu.swift in Sources */, EC6B96D82B24BF2100FC1C58 /* Menu.swift in Sources */,
EC650A4E2B278EDB003AFCAD /* TrendingBetCard.swift in Sources */, EC650A4E2B278EDB003AFCAD /* TrendingBetCard.swift in Sources */,
@ -722,24 +574,21 @@
129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */, 129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */,
123225D92B67B46100D30BB3 /* BetEndingValidationView.swift in Sources */, 123225D92B67B46100D30BB3 /* BetEndingValidationView.swift in Sources */,
EC0193782B25BF16005D81E6 /* AllcoinsCapsule.swift in Sources */, EC0193782B25BF16005D81E6 /* AllcoinsCapsule.swift in Sources */,
EC7EF74C2B87F2AF0022B5D9 /* NotificationService.swift in Sources */,
EC650A4A2B25DD58003AFCAD /* FriendsView.swift in Sources */, EC650A4A2B25DD58003AFCAD /* FriendsView.swift in Sources */,
EC3077072B24CB840060E34D /* SplashView.swift in Sources */, EC3077072B24CB840060E34D /* SplashView.swift in Sources */,
EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */, EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */,
ECA9D1CB2B2DA2320076E0EC /* DropDownFriends.swift in Sources */, ECA9D1CB2B2DA2320076E0EC /* DropDownFriends.swift in Sources */,
12C3704A2B5D5BD000CD9F0F /* ParticiationCell.swift in Sources */,
123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */, 123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */,
12228A212C1760D2008524F4 /* BinaryBetLine.swift in Sources */,
EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */, EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */,
ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */, ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */,
ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */, ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */,
1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */, 1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */,
EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */, EC6B96D52B24BE0E00FC1C58 /* MainView.swift in Sources */,
ECF872752B9266C100F9D240 /* AllInWidgets.intentdefinition in Sources */,
EC650A562B279D68003AFCAD /* WinModal.swift in Sources */, EC650A562B279D68003AFCAD /* WinModal.swift in Sources */,
EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */, EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */,
123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */, 123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */,
EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */, EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */,
EC7EF74A2B87E3FD0022B5D9 /* QuickAction.swift in Sources */,
EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */, EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */,
12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */, 12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */,
EC650A542B279545003AFCAD /* ChoiceCapsule.swift in Sources */, EC650A542B279545003AFCAD /* ChoiceCapsule.swift in Sources */,
@ -767,18 +616,6 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
ECF872602B9266C000F9D240 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
ECF8726B2B9266C000F9D240 /* AllInWidgetsBundle.swift in Sources */,
ECF872742B9266C100F9D240 /* AllInWidgets.intentdefinition in Sources */,
ECF8726F2B9266C000F9D240 /* AllInCoinsWidget.swift in Sources */,
ECF8726D2B9266C000F9D240 /* AllInWidgetsLiveActivity.swift in Sources */,
ECF872822B92696C00F9D240 /* Provider.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
@ -792,25 +629,8 @@
target = EC6B96972B24B4CC00FC1C58 /* AllIn */; target = EC6B96972B24B4CC00FC1C58 /* AllIn */;
targetProxy = EC6B96B32B24B4CC00FC1C58 /* PBXContainerItemProxy */; targetProxy = EC6B96B32B24B4CC00FC1C58 /* PBXContainerItemProxy */;
}; };
ECF872772B9266C100F9D240 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = ECF872632B9266C000F9D240 /* AllInWidgetsExtension */;
targetProxy = ECF872762B9266C100F9D240 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
ECDDD48C2BF4A7920009223A /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
ECDDD48B2BF4A7920009223A /* en */,
ECDDD48D2BF4A7970009223A /* fr */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
EC6B96BA2B24B4CC00FC1C58 /* Debug */ = { EC6B96BA2B24B4CC00FC1C58 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
@ -929,14 +749,12 @@
EC6B96BD2B24B4CC00FC1C58 /* Debug */ = { EC6B96BD2B24B4CC00FC1C58 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = AllIn/AllIn.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"AllIn/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"AllIn/Preview Content\"";
DEVELOPMENT_TEAM = P39ZK4GA2T; DEVELOPMENT_TEAM = 35KQ5BDC64;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "All In"; INFOPLIST_KEY_CFBundleDisplayName = "All In";
@ -963,14 +781,12 @@
EC6B96BE2B24B4CC00FC1C58 /* Release */ = { EC6B96BE2B24B4CC00FC1C58 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = AllIn/AllIn.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"AllIn/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"AllIn/Preview Content\"";
DEVELOPMENT_TEAM = P39ZK4GA2T; DEVELOPMENT_TEAM = 35KQ5BDC64;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "All In"; INFOPLIST_KEY_CFBundleDisplayName = "All In";
@ -1066,62 +882,6 @@
}; };
name = Release; name = Release;
}; };
ECF8727A2B9266C100F9D240 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = AllInWidgetsExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = P39ZK4GA2T;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = AllInWidgets/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AllInWidgets;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.alldev.AllIn.AllInWidgets;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
ECF8727B2B9266C100F9D240 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = AllInWidgetsExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = P39ZK4GA2T;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = AllInWidgets/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AllInWidgets;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.alldev.AllIn.AllInWidgets;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
@ -1161,15 +921,6 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
ECF8727C2B9266C100F9D240 /* Build configuration list for PBXNativeTarget "AllInWidgetsExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
ECF8727A2B9266C100F9D240 /* Debug */,
ECF8727B2B9266C100F9D240 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */

@ -1,214 +0,0 @@
//
// AllInCoinsWidgets.swift
// AllInCoinsWidgets
//
// Created by Emre on 01/03/2024.
//
import WidgetKit
import SwiftUI
struct AllInCoinsWidgetEntryView : View {
var user: Provider.Entry
@Environment(\.widgetFamily) var family
var body: some View {
switch family {
case .systemSmall:
SmallSizedWidget()
case .systemMedium:
MediumSizedWidget()
case .accessoryRectangular:
LockScreenRectangularWidget()
case .accessoryInline:
LockScreenInlineWidget()
case .accessoryCircular:
LockScreenCircularWidget()
default:
Text("Not implemented")
}
}
@ViewBuilder
func LockScreenInlineWidget() -> some View {
if user.connected {
Text("💸 " + user.coins.abbreviated())
.bold()
.font(.headline)
.foregroundColor(.white)
} else {
Text("💸 Connexion")
.bold()
.font(.headline)
.foregroundColor(.white)
}
}
@ViewBuilder
func LockScreenCircularWidget() -> some View {
if user.connected {
Gauge(value: Float(user.coins) / 10000) {
Text(user.coins.abbreviated())
}
.gaugeStyle(.accessoryCircular)
} else {
ZStack {
Image("launchScreenImage")
.resizable()
.aspectRatio(contentMode: .fill)
VStack {
Text("Vide")
Text("All In")
}
}
}
}
@ViewBuilder
func LockScreenRectangularWidget() -> some View {
VStack(alignment: .leading) {
HStack {
Image("allcoinIcon")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
if user.connected {
VStack(alignment: .leading) {
Text(user.coins.abbreviated())
.fontWeight(.bold)
.font(.headline)
.foregroundColor(.white)
Text(user.username.description.capitalized + ", venez jouez !")
.font(.caption2)
.foregroundColor(.white)
}
} else {
Text("Connexion")
.font(.headline)
.foregroundColor(.white)
}
}
Text("All In")
.font(.callout)
.fontWeight(.semibold)
}
}
@ViewBuilder
func SmallSizedWidget() -> some View {
ZStack {
Image("launchScreenImage")
.resizable()
.aspectRatio(contentMode: .fill)
VStack {
HStack {
Image("allcoinWhiteIcon")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
if user.connected {
VStack(alignment: .leading) {
Text(user.coins.abbreviated())
.fontWeight(.bold)
.font(.headline)
.foregroundColor(.white)
Text(user.username.description.capitalized + ", venez jouez !")
.font(.caption2)
.foregroundColor(.white)
}
} else {
Text("Connexion")
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.white)
}
}
}
}
}
@ViewBuilder
func MediumSizedWidget() -> some View {
ZStack {
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [Color("PinkAccentColor"), Color("PurpleAccentColor"), Color("BlueAccentColor")]), startPoint: .top, endPoint: .bottom))
VStack {
HStack {
Image("allcoinWhiteIcon")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 45, height: 45)
if user.connected {
VStack(alignment: .leading) {
Text(user.coins.abbreviated())
.fontWeight(.bold)
.font(.title)
.foregroundColor(.white)
Text(user.username.description.capitalized + ", venez jouez !")
.font(.caption)
.foregroundColor(.white)
}
} else {
Text("Connexion")
.font(.title)
.fontWeight(.bold)
.foregroundColor(.white)
}
}
}
}
}
}
struct AllInCoinsWidget: Widget {
let kind: String = "AllInCoinsWidgets"
var body: some WidgetConfiguration {
IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in
AllInCoinsWidgetEntryView(user: entry)
}
.configurationDisplayName("All Coins")
.description("Visualiser rapidement votre nombre de all coins restants.")
.supportedFamilies([.systemSmall, .systemMedium, .accessoryRectangular, .accessoryInline, .accessoryCircular])
}
}
struct AllInCoinsWidget_Previews: PreviewProvider {
static var previews: some View {
AllInCoinsWidgetEntryView(user: User(date: Date(), coins: 1000, username: "test", connected: false))
.previewContext(WidgetPreviewContext(family: .systemSmall))
AllInCoinsWidgetEntryView(user: User(date: Date(), coins: 1000, username: "test", connected: true))
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}
extension Int {
func abbreviated() -> String {
if self < 1000 {
return "\(self)"
}
let abbreviations = ["", "K", "M", "B", "T"]
var num = Double(self)
var index = 0
while num >= 1000 && index < abbreviations.count - 1 {
num /= 1000
index += 1
}
return String(format: "%.1f%@", num, abbreviations[index])
}
}

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>INEnums</key>
<array/>
<key>INIntentDefinitionModelVersion</key>
<string>1.2</string>
<key>INIntentDefinitionNamespace</key>
<string>88xZPY</string>
<key>INIntentDefinitionSystemVersion</key>
<string>20A294</string>
<key>INIntentDefinitionToolsBuildVersion</key>
<string>12A6144</string>
<key>INIntentDefinitionToolsVersion</key>
<string>12.0</string>
<key>INIntents</key>
<array>
<dict>
<key>INIntentCategory</key>
<string>information</string>
<key>INIntentDescriptionID</key>
<string>tVvJ9c</string>
<key>INIntentEligibleForWidgets</key>
<true/>
<key>INIntentIneligibleForSuggestions</key>
<true/>
<key>INIntentName</key>
<string>Configuration</string>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Configuration</string>
<key>INIntentTitleID</key>
<string>gpCwrM</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>View</string>
</dict>
</array>
<key>INTypes</key>
<array/>
</dict>
</plist>

@ -1,17 +0,0 @@
//
// AllInWidgetsBundle.swift
// AllInWidgets
//
// Created by Emre on 01/03/2024.
//
import WidgetKit
import SwiftUI
@main
struct AllInWidgetsBundle: WidgetBundle {
var body: some Widget {
AllInCoinsWidget()
AllInWidgetsLiveActivity()
}
}

@ -1,77 +0,0 @@
//
// AllInWidgetsLiveActivity.swift
// AllInWidgets
//
// Created by Emre on 01/03/2024.
//
import ActivityKit
import WidgetKit
import SwiftUI
struct AllInWidgetsAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// Dynamic stateful properties about your activity go here!
var value: Int
}
// Fixed non-changing properties about your activity go here!
var name: String
}
struct AllInWidgetsLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: AllInWidgetsAttributes.self) { context in
// Lock screen/banner UI goes here
VStack {
Text("Hello")
}
.activityBackgroundTint(Color.cyan)
.activitySystemActionForegroundColor(Color.black)
} dynamicIsland: { context in
DynamicIsland {
// Expanded UI goes here. Compose the expanded UI through
// various regions, like leading/trailing/center/bottom
DynamicIslandExpandedRegion(.leading) {
Text("Leading")
}
DynamicIslandExpandedRegion(.trailing) {
Text("Trailing")
}
DynamicIslandExpandedRegion(.bottom) {
Text("Bottom")
// more content
}
} compactLeading: {
Text("L")
} compactTrailing: {
Text("T")
} minimal: {
Text("Min")
}
.widgetURL(URL(string: "http://www.apple.com"))
.keylineTint(Color.red)
}
}
}
struct AllInWidgetsLiveActivity_Previews: PreviewProvider {
static let attributes = AllInWidgetsAttributes(name: "Me")
static let contentState = AllInWidgetsAttributes.ContentState(value: 3)
static var previews: some View {
attributes
.previewContext(contentState, viewKind: .dynamicIsland(.compact))
.previewDisplayName("Island Compact")
attributes
.previewContext(contentState, viewKind: .dynamicIsland(.expanded))
.previewDisplayName("Island Expanded")
attributes
.previewContext(contentState, viewKind: .dynamicIsland(.minimal))
.previewDisplayName("Minimal")
attributes
.previewContext(contentState, viewKind: .content)
.previewDisplayName("Notification")
}
}

@ -1,20 +0,0 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFB",
"green" : "0x7B",
"red" : "0x7F"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -1,14 +0,0 @@
{
"images" : [
{
"filename" : "Logo.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

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

@ -1,6 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

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

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

@ -1,11 +0,0 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>codefirst.iut.uca.fr</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
</dict>
</plist>

@ -1,78 +0,0 @@
//
// Provider.swift
// AllInWidgetsExtension
//
// Created by Emre on 01/03/2024.
//
import WidgetKit
import Intents
let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/"
struct Provider: IntentTimelineProvider {
func placeholder(in context: Context) -> User {
User(date: Date())
}
func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (User) -> ()) {
var entry = User(date: Date())
entry.connected = true
entry.username = "toto"
entry.coins = 50000
completion(entry)
}
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<User>) -> ()) {
let currentDate = Date()
Task {
if var userData = try? await fetchData() {
userData.date = currentDate
let nextUpdate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)!
let timeline = Timeline(entries: [userData], policy: .after(nextUpdate))
completion(timeline)
}
}
}
func fetchData() async throws -> User {
let defaults = UserDefaults(suiteName: "group.alldev.AllIn")
guard let token = defaults?.string(forKey: "authenticationRefresh") else {
return User()
}
let url = URL(string: allInApi + "users/token")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
if let userData = try? JSONDecoder().decode(User.self, from: data) {
var updatedUser = userData
updatedUser.connected = true
return updatedUser
}
}
return User()
}
}
struct User: TimelineEntry, Codable {
var date: Date = .init()
var coins: Int = 0
var username: String = ""
var connected: Bool = false
enum CodingKeys: String, CodingKey {
case coins = "nbCoins"
case username = "username"
}
}

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array/>
</dict>
</plist>

@ -11,38 +11,26 @@ import Model
public struct BetApiManager: BetDataManager { public struct BetApiManager: BetDataManager {
public let token: String public let token: String
public let url: String
public init(withUserToken token: String, andApiUrl url: String) { public init(withUserToken token: String) {
self.token = token self.token = token
self.url = url
} }
public func getBets(withIndex index: Int, withCount count: Int, filters: [BetFilter] = [], completion: @escaping ([Bet]) -> Void) { public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
let url = URL(string: url + "bets/gets")! let url = URL(string: allInApi + "bets/gets")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let filterStrings = filters.map { $0.rawValue } var bets: [Bet] = []
let jsonDictionary: [String: Any] = ["filters": filterStrings]
do {
let jsonData = try JSONSerialization.data(withJSONObject: jsonDictionary, options: [])
request.httpBody = jsonData
} catch {
print("Error creating JSON data: \(error)")
return
}
URLSession.shared.dataTask(with: request) { data, response, error in URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data { if let data = data {
print ("ALLIN : get bets") print ("ALLIN : get bets")
do { do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
var bets: [Bet] = []
for json in jsonArray { for json in jsonArray {
if let bet = FactoryApiBet().toBet(from: json) { if let bet = FactoryApiBet().toBet(from: json) {
bets.append(bet) bets.append(bet)
@ -57,14 +45,13 @@ public struct BetApiManager: BetDataManager {
} }
}.resume() }.resume()
} }
public func getUsers(username: String) -> [User] { public func getUsers(username: String) -> [User] {
return [] return []
} }
public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) { public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) {
let url = URL(string: url + "betdetail/get/" + id)! let url = URL(string: allInApi + "betdetail/get/" + id)!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -76,36 +63,10 @@ public struct BetApiManager: BetDataManager {
print ("ALLIN : get bet with id :" + id) print ("ALLIN : get bet with id :" + id)
do { do {
if let httpResponse = response as? HTTPURLResponse, let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { if let httpResponse = response as? HTTPURLResponse, let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
print(httpResponse.statusCode)
print(json)
if let betDetail = FactoryApiBet().toBetDetail(from: json) { if let betDetail = FactoryApiBet().toBetDetail(from: json) {
completion(betDetail) completion(betDetail)
} }
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
}
public func getPopularBet(completion: @escaping (Bet) -> Void) {
let url = URL(string: url + "bets/popular")!
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 popular bet")
do {
if let httpResponse = response as? HTTPURLResponse, let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
if let bet = FactoryApiBet().toBet(from: json) {
completion(bet)
}
print(httpResponse.statusCode) print(httpResponse.statusCode)
} }
} catch { } catch {

@ -23,37 +23,71 @@ public class FactoryApiBet: FactoryBet {
"sentenceBet": bet.phrase, "sentenceBet": bet.phrase,
"endRegistration": formatZonedDateTime(dateTime: bet.endRegisterDate), "endRegistration": formatZonedDateTime(dateTime: bet.endRegisterDate),
"endBet": formatZonedDateTime(dateTime: bet.endBetDate), "endBet": formatZonedDateTime(dateTime: bet.endBetDate),
"isPrivate": String(bet.isPrivate), "isPrivate": String(bet.isPublic),
"response": bet.getResponses(), "response": ["Yes","No"],
"userInvited": bet.invited,
"type": betTypeString(fromType: String(describing: type(of: bet))) "type": betTypeString(fromType: String(describing: type(of: bet)))
] ]
print(json)
return json return json
} }
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? { public func toBet(from json: [String: Any]) -> Bet? {
guard let type = json["type"] as? String, let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) else { 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,
let isPublic = json["isPrivate"] as? Bool,
let createdBy = json["createdBy"] as? String,
let type = json["type"] as? String,
let status = json["status"] as? String else {
return nil return nil
} }
let decoder = JSONDecoder()
do { guard let endRegisterDate = fromJsonDateString(endRegisterDateString),
switch type { let endBetDate = fromJsonDateString(endBetDateString) else {
case "BINARY":
return try decoder.decode(BinaryBet.self, from: jsonData)
case "MATCH":
return try decoder.decode(MatchBet.self, from: jsonData)
case "CUSTOM":
return try decoder.decode(CustomBet.self, from: jsonData)
default:
return try decoder.decode(BinaryBet.self, from: jsonData)
}
} catch {
print("Error decoding Bet object: \(error)")
return nil return nil
} }
return toBet(id: id, theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, status: toStatus(status: status), creator: User(username: createdBy, email: createdBy, nbCoins: 0, friends: []), type: type)
}
func toStatus(status: String) -> BetStatus {
switch status {
case "IN_PROGRESS":
return .inProgress
case "WAITING":
return .waiting
case "CLOSING":
return .closing
case "FINISHED":
return .finished
case "CANCELLED":
return .cancelled
default:
return .finished
}
}
public func toBet(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: User, type: String) -> Bet {
switch type {
case "BINARY":
return BinaryBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
case "MATCH":
return MatchBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "")
case "CUSTOM":
return CustomBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])
default:
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? { public func toBetDetail(from json: [String: Any]) -> BetDetail? {
@ -63,74 +97,28 @@ public class FactoryApiBet: FactoryBet {
} }
var participations: [Participation] = [] var participations: [Participation] = []
var wonParticipation: Participation?
var userParticipation: Participation?
if let participationsJson = json["participations"] as? [[String: Any]] { if let participationsJson = json["participations"] as? [[String: Any]], !participationsJson.isEmpty {
do { for participationJson in participationsJson {
participations = try JSONDecoder().decode([Participation].self, from: JSONSerialization.data(withJSONObject: participationsJson)) if let participation = self.toParticipate(from: participationJson) {
} catch { participations.append(participation)
print("Error decoding participations: \(error)") }
} }
} }
var answers: [AnswerDetail] = [] return BetDetail(bet: bet, answers: [], participations: participations)
if let answersJson = json["answers"] as? [[String: Any]] {
do {
answers = try JSONDecoder().decode([AnswerDetail].self, from: JSONSerialization.data(withJSONObject: answersJson))
} catch {
print("Error decoding answers: \(error)")
}
}
if let participationJson = json["wonParticipation"] as? [String: Any] {
do {
wonParticipation = try JSONDecoder().decode(Participation.self, from: JSONSerialization.data(withJSONObject: participationJson))
} catch {
print("Error decoding participation: \(error)")
}
}
if let participationUserJson = json["userParticipation"] as? [String: Any] {
do {
userParticipation = try JSONDecoder().decode(Participation.self, from: JSONSerialization.data(withJSONObject: participationUserJson))
} catch {
print("Error decoding participation: \(error)")
}
}
return BetDetail(bet: bet, answers: answers, participations: participations, wonParticipation: wonParticipation, userParticipation: userParticipation)
} }
public func toBetResultDetail(from json: [String: Any]) -> BetResultDetail? { public func toParticipate(from json: [String: Any]) -> Participation? {
guard let id = json["id"] as? String,
guard let amount = json["amount"] as? Int, let betId = json["betId"] as? String,
let won = json["won"] as? Bool else { let username = json["username"] as? String,
return nil let answer = json["answer"] as? String,
} let stake = json["stake"] as? Int else {
guard let betJson = json["bet"] as? [String: Any],
let bet = self.toBet(from: betJson) else {
return nil
}
let decoder = JSONDecoder()
guard let betResultJson = json["betResult"] as? [String: Any],
let betResultData = try? JSONSerialization.data(withJSONObject: betResultJson),
let betResult = try? decoder.decode(BetResult.self, from: betResultData) else {
print("Error decoding bet result")
return nil
}
guard let participationJson = json["participation"] as? [String: Any],
let participationData = try? JSONSerialization.data(withJSONObject: participationJson),
let participation = try? decoder.decode(Participation.self, from: participationData) else {
print("Error decoding participation")
return nil return nil
} }
return BetResultDetail(betResult: betResult, bet: bet, participation: participation, amount: amount, won: won) return Participation(id: id, stake: stake, date: Date(), response: answer, user: User(username: username, email: "Email", nbCoins: 0, friends: []), betId: betId)
} }
public func betTypeString(fromType type: String) -> String { public func betTypeString(fromType type: String) -> String {

@ -8,14 +8,14 @@
import Foundation import Foundation
import Model import Model
let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/"
public struct UserApiManager: UserDataManager { public struct UserApiManager: UserDataManager {
public let token: String public let token: String
public let url: String
public init(withUserToken token: String, andApiUrl url: String) { public init(withUserToken token: String) {
self.token = token self.token = token
self.url = url
} }
public func getBets(withIndex index: Int, withCount count: Int) -> [Bet] { public func getBets(withIndex index: Int, withCount count: Int) -> [Bet] {
@ -23,7 +23,7 @@ public struct UserApiManager: UserDataManager {
} }
public func getBetsOver(completion : @escaping ([BetDetail])-> ()) { public func getBetsOver(completion : @escaping ([BetDetail])-> ()) {
let url = URL(string: url + "bets/toConfirm")! let url = URL(string: allInApi + "bets/toConfirm")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -38,6 +38,7 @@ public struct UserApiManager: UserDataManager {
do { do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for json in jsonArray { for json in jsonArray {
print(json)
if let bet = FactoryApiBet().toBetDetail(from: json) { if let bet = FactoryApiBet().toBetDetail(from: json) {
bets.append(bet) bets.append(bet)
} }
@ -52,41 +53,9 @@ public struct UserApiManager: UserDataManager {
}.resume() }.resume()
} }
public func getBetsWon(completion : @escaping ([BetResultDetail])-> ()) {
let url = URL(string: url + "bets/getWon")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var bets: [BetResultDetail] = []
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print ("ALLIN : get bets won")
do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for json in jsonArray {
if let bet = FactoryApiBet().toBetResultDetail(from: json) {
print(bet)
bets.append(bet)
}
}
print(httpResponse.statusCode)
completion(bets)
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
}
public func addBet(bet: Bet, completion : @escaping (Int)-> ()) { public func addBet(bet: Bet, completion : @escaping (Int)-> ()) {
let url = URL(string: url + "bets/add")! let url = URL(string: allInApi + "bets/add")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
@ -105,128 +74,12 @@ public struct UserApiManager: UserDataManager {
} }
} }
public func addFriend(username: String, completion : @escaping (Int)-> ()) { public func getFriends() -> [User] {
fatalError("Not implemented yet")
let url = URL(string: url + "friends/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] = ["username": username]
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){
URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in
print ("ALLIN : Add friend")
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
completion(httpResponse.statusCode)
}
}.resume()
}
}
public func removeFriend(username: String, completion : @escaping (Int)-> ()) {
let url = URL(string: url + "friends/delete")!
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] = ["username": username]
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){
URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in
print ("ALLIN : Remove friend")
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
completion(httpResponse.statusCode)
}
}.resume()
}
}
public func getFriends(completion: @escaping ([User]) -> Void) {
let url = URL(string: url + "friends/gets")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var users: [User] = []
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print ("ALLIN : get friends")
do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray))
print(httpResponse.statusCode)
completion(users)
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
}
public func getRequests(completion: @escaping ([User]) -> Void) {
let url = URL(string: url + "friends/requests")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var users: [User] = []
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print ("ALLIN : get friends")
do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray))
print(httpResponse.statusCode)
completion(users)
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
}
public func getUsers(withName name: String, completion: @escaping ([User]) -> Void) {
let url = URL(string: url + "friends/search/" + name)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var users: [User] = []
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print ("ALLIN : get friends by search")
do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
users = try JSONDecoder().decode([User].self, from: JSONSerialization.data(withJSONObject: jsonArray))
print(httpResponse.statusCode)
completion(users)
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
} }
public func getGifts(completion : @escaping (Int, Int)-> ()) { public func getGifts(completion : @escaping (Int, Int)-> ()) {
let url = URL(string: url + "users/gift")! let url = URL(string: allInApi + "users/gift")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@ -250,46 +103,19 @@ public struct UserApiManager: UserDataManager {
}.resume() }.resume()
} }
public func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetResultDetail]) -> Void) { public func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
let url = URL(string: url + "bets/history")! fatalError("Not implemented yet")
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var bets: [BetResultDetail] = []
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print ("ALLIN : get old bets")
do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
print(jsonArray)
for json in jsonArray {
if let bet = FactoryApiBet().toBetResultDetail(from: json) {
bets.append(bet)
}
}
print(httpResponse.statusCode)
completion(bets)
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
} }
public func getCurrentBets(withIndex index: Int, withCount count: Int, completion: @escaping ([BetDetail]) -> Void) { public func getCurrentBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
let url = URL(string: url + "bets/current")! let url = URL(string: allInApi + "bets/current")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
var bets: [BetDetail] = [] var bets: [Bet] = []
URLSession.shared.dataTask(with: request) { data, response, error in URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data { if let data = data {
@ -297,7 +123,7 @@ public struct UserApiManager: UserDataManager {
do { do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for json in jsonArray { for json in jsonArray {
if let bet = FactoryApiBet().toBetDetail(from: json) { if let bet = FactoryApiBet().toBet(from: json) {
bets.append(bet) bets.append(bet)
} }
} }
@ -312,7 +138,7 @@ public struct UserApiManager: UserDataManager {
} }
public func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int, completion : @escaping (Int)-> ()) { public func addParticipation(withId id: String, withAnswer answer: String, andStake stake: Int, completion : @escaping (Int)-> ()) {
let url = URL(string: url + "participations/add")! let url = URL(string: allInApi + "participations/add")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
@ -336,18 +162,24 @@ public struct UserApiManager: UserDataManager {
} }
public func addResponse(withIdBet id: String, andResponse responseBet: String) { public func addResponse(withIdBet id: String, andResponse responseBet: String) {
let url = URL(string: url + "bets/confirm/" + id)! let url = URL(string: allInApi + "bets/confirm/" + id)!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared.uploadTask(with: request, from: responseBet.data(using: .utf8)) { data, response, error in let json: [String: String] = [
print ("ALLIN : add response " + responseBet + " for the bet Id " + id) "result": responseBet,
if let httpResponse = response as? HTTPURLResponse { ]
print(httpResponse.statusCode)
} if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){
}.resume() URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in
print ("ALLIN : add response " + responseBet + " for the bet Id " + id)
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
}
}.resume()
}
} }
} }

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

@ -8,8 +8,8 @@
import Foundation import Foundation
/// A class representing detailed information about a specific answer option for a bet. /// A class representing detailed information about a specific answer option for a bet.
public class AnswerDetail: ObservableObject, Codable, Equatable, Identifiable, Hashable { public class AnswerDetail: ObservableObject, Hashable {
/// The response or outcome associated with this answer. /// The response or outcome associated with this answer.
public private(set) var response: String public private(set) var response: String
@ -21,7 +21,7 @@ public class AnswerDetail: ObservableObject, Codable, Equatable, Identifiable, H
/// The highest stake placed on this answer. /// The highest stake placed on this answer.
public private(set) var highestStake: Int public private(set) var highestStake: Int
/// The odds associated with this answer. /// The odds associated with this answer.
public private(set) var odds: Float public private(set) var odds: Float
@ -41,19 +41,16 @@ public class AnswerDetail: ObservableObject, Codable, Equatable, Identifiable, H
self.odds = odds self.odds = odds
} }
public static func == (lhs: AnswerDetail, rhs: AnswerDetail) -> Bool {
return lhs.response == rhs.response &&
lhs.totalStakes == rhs.totalStakes &&
lhs.totalParticipants == rhs.totalParticipants &&
lhs.highestStake == rhs.highestStake &&
lhs.odds == rhs.odds
}
public func hash(into hasher: inout Hasher) { public func hash(into hasher: inout Hasher) {
hasher.combine(response) // Use properties that define the uniqueness of the instance for hashing
hasher.combine(totalStakes) hasher.combine(response)
hasher.combine(totalParticipants) // ... (combine other properties)
hasher.combine(highestStake) }
hasher.combine(odds)
} public static func == (lhs: AnswerDetail, rhs: AnswerDetail) -> Bool {
// Check equality based on properties
return lhs.response == rhs.response
// ... (check other properties)
}
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save