Merge with feature/display_bet_details 🔀

view/details-page
Emre KARTAL 1 year ago
commit 5b0c2248a4

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

@ -1,3 +1,55 @@
# Swift
<div align="center">
Client IOS
<img src="Documentation/Images/Banner-AllIn.png" />
---
&nbsp; ![Swift](https://img.shields.io/badge/Swift-F05138.svg?style=for-the-badge&logo=Swift&logoColor=white)
&nbsp; ![iOS](https://img.shields.io/badge/iOS-000000.svg?style=for-the-badge&logo=Apple&logoColor=white)
---
[Présentation](#apple---all-in) | [Répartition du dépôt](#répartition-du-gitlab) | [Structures](#structures) | [Technologies](#technologies) | [Outils](#outils) | [Wiki](https://codefirst.iut.uca.fr/git/AllDev/Gestion_de_projet/wiki)
</div>
### Apple - ALL IN!
**Contexte** : Application Swift et SwiftUI pour le projet universitaire de troisième année (B.U.T Informatique de Clermont-Ferrand) intitulé *All In*.
</br>
**Description** : Ce dépôt contient l'ensemble du code pour la partie client iOS de l'application *ALL IN*.
</br>
# Répartition du GitLab
[**Sources**](Sources) : **Code de l'application**
[**Documentation**](Documentation) : **Documentation de l'application**
# Structures
- MVVM
# Technologies
<img src="" />
Pour réaliser l'interface visuelle, nous avons opté pour **SwiftUI** du fait qu'elle permet de réaliser des interfaces utilisateurs complexes de manière élégante. Le framework est récent, mis à jour régulièrement, et facile à prendre en main pour le développement.
# Outils
Pour la partie API, nous avons utilisé plusieurs outils :
- UserDefaults
Pour stocker le token localement, nous utilisons l'outil fourni par SwiftUI qui est UserDefaults, afin de réaliser une authentification automatique lorsque le client ouvre l'application, en récupérant son token lors de la précédente connexion.
<div align="center">
© AllDev - Apple
</div>

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

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

@ -8,8 +8,8 @@
import SwiftUI
struct AllcoinsCounter: View {
var backgroundColor: Color = AllInColors.whiteColor
var foreGroundColor: Color = AllInColors.primaryColor
var backgroundColor: Color = .white
var foregroundColor: Color = AllInColors.primaryColor
var body: some View {
HStack(alignment: .center) {
Image("allcoinIcon")
@ -17,7 +17,7 @@ struct AllcoinsCounter: View {
.frame(width: 17, height: 17, alignment: .leading)
Text(String(AppStateContainer.shared.user?.nbCoins ?? 0))
.fontWeight(.black)
.foregroundColor(foreGroundColor)
.foregroundColor(foregroundColor)
}
.frame(width: 90, height: 40)
.background(backgroundColor)

@ -6,26 +6,34 @@
//
import SwiftUI
import Model
struct BetCard: View {
var bet: Bet
@State var showDetails: Bool = false
@State var showParticipate: Bool = false
var body: some View {
VStack(spacing: 0){
VStack(alignment: .leading,spacing: 2){
HStack{
Spacer()
Text("proposé par Lucas").font(.system(size: 10)).foregroundColor(AllInColors.grey800Color)
Text("proposé par " + bet.author.username.capitalized)
.font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color)
}
Text("Etudes").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
Text("Emre va réussir son TP de CI/CD mercredi?").font(.system(size: 20)).fontWeight(.bold)
Text(bet.theme)
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
Text(bet.phrase)
.font(.system(size: 20))
.fontWeight(.bold)
HStack{
Text("Commence le").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
TextCapsule()
TextCapsule()
TextCapsule(date: bet.endRegisterDate)
Spacer()
}
}
.frame(width: .infinity)
@ -36,33 +44,41 @@ struct BetCard: View {
HStack{
Spacer()
UsersPreview()
Text(" 4 joueurs en attente").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color).fontWeight(.medium)
Text(String(bet.registered.count) + " joueurs en attente")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
.fontWeight(.medium)
Spacer()
}.padding(0)
ParticipateButton(isOpen: $showParticipate).padding(.top, 5)
}
.frame(width: .infinity)
.padding(.all,8)
.background(AllInColors.underComponentBackgroundColor)
.cornerRadius(20, corners: [.bottomLeft,.bottomRight])
.border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
}.onTapGesture {
}
.onTapGesture {
showDetails.toggle()
}.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails)
}
.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails, id: bet.id)
}
}
}
struct BetCard_Previews: PreviewProvider {
static var previews: some View {
BetCard()
BetCard(bet: BinaryBet(theme: "Football - Finale de la Ligue des Champions",
phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.",
endRegisterDate: Date().addingTimeInterval(86400),
endBetDate: Date().addingTimeInterval(172800),
totalStakes: 100,
isPublic: true,
invited: [],
author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []),
registered: []))
.preferredColorScheme(.dark)
}
}

@ -25,7 +25,7 @@ struct ParticipationModal: View {
HStack{
Text("Faites vos paris").font(.system(size: 18)).foregroundColor(AllInColors.blackTitleColor).fontWeight(.semibold)
Spacer()
AllcoinsCounter(backgroundColor: AllInColors.purpleAccentColor, foreGroundColor: AllInColors.whiteColor)
AllcoinsCounter(backgroundColor: AllInColors.purpleAccentColor, foregroundColor: AllInColors.whiteColor)
}
.padding(.leading, 15)
VStack(alignment: .leading){

@ -32,8 +32,7 @@ struct RecapBetCard: View {
Text("Fini le ")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
TextCapsule()
TextCapsule()
TextCapsule(date: Date())
Spacer()
}
}
@ -108,7 +107,7 @@ struct RecapBetCard: View {
.onTapGesture {
showDetails.toggle()
}.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails)
DetailsView(isModalPresented: $showDetails, id: "1")
}
.gesture(
LongPressGesture(minimumDuration: 0.5)

@ -24,8 +24,7 @@ struct ReviewCard: View {
Text("Emre va réussir son TP de CI/CD mercredi?").font(.system(size: 20)).fontWeight(.bold)
HStack{
Text("Fini le").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
TextCapsule()
TextCapsule()
TextCapsule(date: Date())
Spacer()
}
@ -38,14 +37,14 @@ struct ReviewCard: View {
HStack(){
Spacer()
Text(amountBetted.description)
.foregroundColor(AllInColors.whiteColor)
.foregroundColor(.white)
.font(.system(size: 25))
.fontWeight(.bold)
Image("allcoinWhiteIcon")
.resizable()
.frame(width: 20, height: 20, alignment: .bottom)
Text(isAWin ? "Gagnés!" : "Perdus!")
.foregroundColor(AllInColors.whiteColor)
.foregroundColor(.white)
.font(.system(size: 25))
.fontWeight(.bold)
Spacer()
@ -71,7 +70,7 @@ struct ReviewCard: View {
.onTapGesture {
showDetails.toggle()
}.fullScreenCover(isPresented: $showDetails) {
DetailsView(isModalPresented: $showDetails)
DetailsView(isModalPresented: $showDetails, id: "1")
}
}
}

@ -8,21 +8,53 @@
import SwiftUI
struct TextCapsule: View {
var date: Date
private var formattedDate: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMM"
return dateFormatter.string(from: date)
}
private var formattedTime: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
return dateFormatter.string(from: date)
}
var body: some View {
Text("12 sept.").font(.system(size: 15))
HStack {
Text(formattedDate)
.font(.system(size: 15))
.foregroundColor(AllInColors.lightPurpleColor)
.fontWeight(.bold)
.padding([.leading, .trailing], 10)
.padding([.top, .bottom], 5)
.background(AllInColors.underComponentBackgroundColor)
.clipShape(Capsule())
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(AllInColors.delimiterGrey, lineWidth: 1)
)
Text(formattedTime)
.font(.system(size: 15))
.foregroundColor(AllInColors.lightPurpleColor)
.fontWeight(.bold)
.padding([.leading,.trailing],10)
.padding([.top,.bottom], 5).background(AllInColors.underComponentBackgroundColor)
.padding([.leading, .trailing], 10)
.padding([.top, .bottom], 5)
.background(AllInColors.underComponentBackgroundColor)
.clipShape(Capsule())
.overlay(RoundedRectangle(cornerRadius: 20)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(AllInColors.delimiterGrey, lineWidth: 1)
)
}
}
}
struct TextCapsule_Previews: PreviewProvider {
static var previews: some View {
TextCapsule()
TextCapsule(date: Date())
}
}

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

@ -7,14 +7,13 @@
import Foundation
import Model
import ViewModel
import DependencyInjection
import Api
import StubLib
class AuthService: IAuthService {
public func login(login: String, password: String, completion : @escaping (Int)-> ()) {
public func login(login: String, password: String, completion: @escaping (Int) -> ()) {
let url = URL(string: Config.allInApi + "users/login")!
var request = URLRequest(url: url)
@ -26,31 +25,35 @@ class AuthService: IAuthService {
"password": password,
]
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) {
URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in
print ("ALLIN : Process LOGIN")
print("ALLIN: Process LOGIN")
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let token = json["token"] as? String {
AppStateContainer.shared.authenticationRefresh = token;
AppStateContainer.shared.authenticationRefresh = token
self.initializeUser(withToken: token) { status in
print(status)
if status != 200 {
completion(status)
AppStateContainer.shared.authenticationRefresh = nil;
AppStateContainer.shared.authenticationRefresh = nil
} else {
self.initManagerVM(token: token)
completion(httpResponse.statusCode)
}
}
}
}
} else {
completion(httpResponse.statusCode)
}
}
}.resume()
}
}
func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) {
let url = URL(string: Config.allInApi + "/users/register")!
var request = URLRequest(url: url)
@ -60,8 +63,7 @@ class AuthService: IAuthService {
let json = [
"email": email.lowercased(),
"username": username.lowercased(),
"password": password,
"nbCoins": "0"
"password": password
]
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){
@ -79,12 +81,14 @@ class AuthService: IAuthService {
AppStateContainer.shared.authenticationRefresh = nil;
} else {
self.initManagerVM(token: token)
completion(httpResponse.statusCode)
}
}
}
}
} else {
completion(httpResponse.statusCode)
}
}
}.resume()
}
}
@ -119,8 +123,10 @@ class AuthService: IAuthService {
}
private func initializeUser(withToken token: String, completion: @escaping (Int) -> ()) {
let url = URL(string: Config.allInApi + "users/token")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
@ -144,7 +150,7 @@ class AuthService: IAuthService {
}
private func initManagerVM(token: String) {
DependencyInjection.shared.addSingleton(ManagerVM.self, ManagerVM(withModel: Manager(withBetDataManager: BetStubManager(), withUserDataManager: UserApiManager(withUserToken: token))))
DependencyInjection.shared.addSingleton(Manager.self, Manager(withBetDataManager: BetStubManager(), withUserDataManager: UserApiManager(withUserToken: token)))
}
}

@ -7,29 +7,24 @@
import Foundation
import DependencyInjection
import ViewModel
import Model
import Combine
class BetViewModel: ObservableObject {
@Inject var manager: ManagerVM
@Inject var manager: Manager
@Published private(set) var bets: [Bet] = []
init() {
getItems()
}
func getItems() {
manager.getBets(withIndex: 0, withCount: 20) { bets in
self.bets = bets
}
func deleteItem(indexSet: IndexSet) {
}
func moveltem(from: IndexSet, to: Int) {
}
func addItem(title: String) {
}
private var cancellables: Set<AnyCancellable> = []
}

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

@ -0,0 +1,30 @@
//
// DetailsViewModel.swift
// AllIn
//
// Created by Emre on 16/01/2024.
//
import Foundation
import SwiftUI
import DependencyInjection
import Model
class DetailsViewModel: ObservableObject {
@Inject var manager: Manager
var id: String
@Published var betDetail: BetDetail?
init(id: String) {
self.id = id
getItem(withId: id)
}
func getItem(withId id: String) {
manager.getBet(withId: id) { bet in
self.betDetail = bet
}
}
}

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

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

@ -23,10 +23,6 @@ class LoginViewModel: ObservableObject {
func login() {
#if DEBUG
self.onLoginSuccess()
#endif
guard checkAndSetError(forLogin: true, forPassword: true) else {
return
}

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

@ -6,6 +6,7 @@
//
import SwiftUI
import Model
struct BetView: View {
@ -14,11 +15,8 @@ struct BetView: View {
@State var showingSheet: Bool = false
var body: some View {
ZStack(){
VStack(alignment: .center, spacing: 0) {
TopBar(showMenu: self.$showMenu)
ScrollView(showsIndicators: false) {
LazyVStack(alignment: .leading, spacing: 0, pinnedViews: [.sectionHeaders]) {
@ -27,11 +25,12 @@ struct BetView: View {
Section {
VStack(spacing: 20){
BetCard()
ForEach(viewModel.bets, id: \.id) { (bet: Bet) in
BetCard(bet: bet)
}
Button("Show Sheet") {
showingSheet.toggle()
}
}
.padding([.leading,.trailing],25)
@ -55,6 +54,9 @@ struct BetView: View {
}
}
}
.refreshable {
viewModel.getItems()
}
.sheet(isPresented: $showingSheet) {
WinModal()
}
@ -64,9 +66,9 @@ struct BetView: View {
.background(AllInColors.backgroundColor)
}
}
}
struct BetView_Previews: PreviewProvider {
static var previews: some View {
BetView(showMenu: .constant(false))

@ -1,9 +1,20 @@
import SwiftUI
struct DetailsView: View {
@Binding var isModalPresented: Bool
@State var isModalParticipated: Bool = false
@State var progressValue: Float = 0.2
var id: String
@StateObject private var viewModel: DetailsViewModel
init(isModalPresented: Binding<Bool>, id: String) {
self._isModalPresented = isModalPresented
self.id = id
self._viewModel = StateObject(wrappedValue: DetailsViewModel(id: id))
}
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .bottom) {
@ -11,7 +22,7 @@ struct DetailsView: View {
HStack{
Text("Terminé!").font(.system(size: 25)).fontWeight(.bold).padding(.bottom, 10).foregroundStyle(AllInColors.blackTitleColor).opacity(0.7)
Spacer()
Image("CloseiconRounded")
Image("closeIcon")
.resizable()
.frame(maxWidth: 25, maxHeight: 25)
.onTapGesture {
@ -27,38 +38,48 @@ struct DetailsView: View {
VStack(alignment: .leading,spacing: 5){
HStack{
Spacer()
Text("proposé par Lucas").font(.system(size: 10)).foregroundColor(AllInColors.grey800Color)
Text("proposé par " + (viewModel.betDetail?.bet.author.username ?? "Unknown").capitalized)
.font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color)
}
Text("Etudes").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
Text("Emre va réussir son TP de CI/CD mercredi?").font(.system(size: 20)).fontWeight(.bold).padding(.bottom, 10)
Text(viewModel.betDetail?.bet.theme ?? "Not loaded")
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
Text(viewModel.betDetail?.bet.phrase ?? "Not loaded")
.font(.system(size: 20))
.fontWeight(.bold)
.padding(.bottom, 10)
HStack{
Text("Commence le").frame(maxWidth: 100).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
TextCapsule()
TextCapsule()
Text("Commence le")
.frame(maxWidth: 100)
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
TextCapsule(date: viewModel.betDetail?.bet.endRegisterDate ?? Date())
Spacer()
}.padding(.bottom, 10)
HStack{
Text("Fini le").frame(maxWidth: 100).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color)
TextCapsule()
TextCapsule()
Text("Fini le")
.frame(maxWidth: 100)
.font(.system(size: 15))
.foregroundColor(AllInColors.grey800Color)
TextCapsule(date: viewModel.betDetail?.bet.endBetDate ?? Date())
Spacer()
}
}
.frame(width: .infinity)
.padding(.all,15).padding(.vertical, 10)
.background(AllInColors.whiteColor).cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0)
ResultBanner()
VStack(alignment: .leading,spacing: 15){
VStack(alignment: .leading, spacing: 15) {
BetLineLoading(value: $progressValue).padding(.vertical, 15)
Spacer()
}
.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight : .infinity)
.padding([.bottom,.trailing,.leading],15)
.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity)
.padding([.bottom,.trailing,.leading], 15)
.background(AllInColors.underComponentBackgroundColor)
.border(width: 1, edges: [.top], color: AllInColors.delimiterGrey)
Spacer()
@ -67,7 +88,7 @@ struct DetailsView: View {
}
.frame(maxWidth: .infinity, maxHeight: geometry.size.height*0.98)
.background(Color.white)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(15)
ParticipateButton(isOpen: $isModalParticipated).padding(10)
@ -81,9 +102,3 @@ struct DetailsView: View {
}
}
}
struct DetailsView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

@ -19,14 +19,15 @@
EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; };
EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */; };
EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937D2B25C52E005D81E6 /* TopBar.swift */; };
EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */; };
EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */; };
EC3077072B24CB840060E34D /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077062B24CB840060E34D /* SplashView.swift */; };
EC3077092B24CF7F0060E34D /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077082B24CF7F0060E34D /* Colors.swift */; };
EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770A2B24D9160060E34D /* WelcomeView.swift */; };
EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770C2B24DB7A0060E34D /* Extensions.swift */; };
EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770E2B24FCB00060E34D /* RegisterView.swift */; };
EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; };
EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2D2B4EC04B00853949 /* ViewModel */; };
EC4F0D302B4EC05D00853949 /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2F2B4EC05D00853949 /* StubLib */; };
EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC60C5672B5A83FB00FFD6EF /* StubLib */; };
EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; };
EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */; };
EC650A462B25D686003AFCAD /* RankingRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A452B25D686003AFCAD /* RankingRow.swift */; };
@ -106,7 +107,6 @@
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; };
122278B92B4BDE9500E632AA /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Package.swift; path = ../Model/Package.swift; sourceTree = "<group>"; };
122278BB2B4BDEC300E632AA /* Sources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Sources; path = ../StubLib/Sources; sourceTree = "<group>"; };
123590B32B51792000F7AEBD /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; };
123590B52B5537E200F7AEBD /* ResultBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultBanner.swift; sourceTree = "<group>"; };
123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.swift; sourceTree = "<group>"; };
@ -117,6 +117,8 @@
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>"; };
EC01937D2B25C52E005D81E6 /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.swift; sourceTree = "<group>"; };
EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsViewModel.swift; sourceTree = "<group>"; };
EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetViewModel.swift; sourceTree = "<group>"; };
EC3077062B24CB840060E34D /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = "<group>"; };
EC3077082B24CF7F0060E34D /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
EC30770A2B24D9160060E34D /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
@ -173,10 +175,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EC4F0D302B4EC05D00853949 /* StubLib in Frameworks */,
EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */,
EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */,
ECCD244A2B4DE8010071FA9E /* Api in Frameworks */,
EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -341,7 +342,6 @@
ECB3572D2B3CA3BD00045D41 /* Frameworks */ = {
isa = PBXGroup;
children = (
122278BB2B4BDEC300E632AA /* Sources */,
122278B92B4BDE9500E632AA /* Package.swift */,
122278B72B4BDE1100E632AA /* DependencyInjection.framework */,
ECB357302B3CA69300045D41 /* DependencyInjection.framework */,
@ -359,6 +359,8 @@
ECB26A162B4073F100FE06B3 /* CreationBetViewModel.swift */,
ECB26A182B40744F00FE06B3 /* RankingViewModel.swift */,
ECB26A1A2B40746C00FE06B3 /* FriendsViewModel.swift */,
EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */,
EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
@ -383,8 +385,7 @@
packageProductDependencies = (
ECB357342B3E13A400045D41 /* Model */,
ECCD24492B4DE8010071FA9E /* Api */,
EC4F0D2D2B4EC04B00853949 /* ViewModel */,
EC4F0D2F2B4EC05D00853949 /* StubLib */,
EC60C5672B5A83FB00FFD6EF /* StubLib */,
);
productName = AllIn;
productReference = EC6B96982B24B4CC00FC1C58 /* AllIn.app */;
@ -539,6 +540,7 @@
EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */,
ECA9D1CB2B2DA2320076E0EC /* DropDownFriends.swift in Sources */,
123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */,
EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */,
ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */,
ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */,
1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */,
@ -546,6 +548,7 @@
EC650A562B279D68003AFCAD /* WinModal.swift in Sources */,
EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */,
123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */,
EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */,
EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */,
12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */,
EC650A542B279545003AFCAD /* ChoiceCapsule.swift in Sources */,
@ -881,11 +884,7 @@
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
EC4F0D2D2B4EC04B00853949 /* ViewModel */ = {
isa = XCSwiftPackageProductDependency;
productName = ViewModel;
};
EC4F0D2F2B4EC05D00853949 /* StubLib */ = {
EC60C5672B5A83FB00FFD6EF /* StubLib */ = {
isa = XCSwiftPackageProductDependency;
productName = StubLib;
};

@ -0,0 +1,53 @@
//
// BetApiManager.swift
//
//
// Created by Emre on 12/01/2024.
//
import Foundation
import Model
public struct BetApiManager: BetDataManager {
public init() { }
public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
let url = URL(string: allInApi + "bets/gets")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
var bets: [Bet] = []
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print ("ALLIN : get bets")
do {
if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for json in jsonArray {
if let bet = FactoryApiBet().toModel(from: json) {
bets.append(bet)
print(bet.theme)
}
}
print(httpResponse.statusCode)
completion(bets)
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
}
public func getUsers(username: String) -> [User] {
return []
}
public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) {
}
}

@ -11,13 +11,13 @@ import Model
public class FactoryApiBet: FactoryBet {
public func toResponse(bet: Bet) -> [String: Any] {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let json: [String: Any] = [
"id": "1",
"theme": bet.theme,
"sentenceBet": bet.phrase,
"endRegistration": dateFormatter.string(from: bet.endRegisterDate),
"endBet": dateFormatter.string(from: bet.endBetDate),
"endRegistration": bet.endRegisterDate.timeIntervalSince1970,
"endBet": bet.endBetDate.timeIntervalSince1970,
"isPrivate": String(bet.isPublic),
"response": [],
]
@ -26,13 +26,13 @@ public class FactoryApiBet: FactoryBet {
}
public func toModel(from json: [String: Any]) -> Bet? {
guard let theme = json["theme"] as? String,
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 isPublicString = json["isPrivate"] as? String,
let createdBy = json["createdBy"] as? User, // Assuming User object can be parsed from JSON
let type = json["type"] as? Int else {
let isPublic = json["isPrivate"] as? Bool,
let createdBy = json["createdBy"] as? String else {
return nil
}
@ -44,21 +44,19 @@ public class FactoryApiBet: FactoryBet {
return nil
}
let isPublic = (isPublicString.lowercased() == "true")
return toModel(theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, creator: createdBy, type: type)
return toModel(id: id, theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, creator: User(username: createdBy, email: createdBy, nbCoins: 0, friends: []), type: 0)
}
public func toModel(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet {
public func toModel(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet {
switch type {
case 0:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])
return BinaryBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])
case 1:
return MatchBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "")
return MatchBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "")
case 2:
return CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])
return CustomBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])
default:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])
return BinaryBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])
}
}

@ -8,7 +8,7 @@
import Foundation
import Model
let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api"
let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/"
public struct UserApiManager: UserDataManager {
@ -37,9 +37,6 @@ public struct UserApiManager: UserDataManager {
URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in
print ("ALLIN : Add BET")
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 201 {
}
print(httpResponse.statusCode)
}
}.resume()
@ -49,4 +46,8 @@ public struct UserApiManager: UserDataManager {
public func getFriends() -> [User] {
fatalError("Not implemented yet")
}
public func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
fatalError("Not implemented yet")
}
}

@ -8,7 +8,11 @@
import Foundation
/// A class representing a betting entity, including details about the bet theme, participants, and deadlines.
public class Bet: ObservableObject {
public class Bet: ObservableObject, Identifiable {
/// The id for the bet.
public private(set) var id: String
/// The theme or topic of the bet.
public private(set) var theme: String
@ -39,6 +43,32 @@ public class Bet: ObservableObject {
/// Custom Constructor
///
/// - Parameters:
/// - id: The id for the bet.
/// - theme: The theme or topic of the bet.
/// - phrase: The specific phrase or question related to the bet.
/// - endRegisterDate: The deadline for users to register for the bet.
/// - endBetDate: The deadline for the actual betting to take place.
/// - totalStakes: The total stakes or amount involved in the bet.
/// - isPublic: Indicates whether the bet is public or private.
/// - invited: List of users who are invited to participate in the bet.
/// - author: The user who created the bet.
/// - registered: List of users who have registered for the bet.
public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User]) {
self.id = id
self.theme = theme
self.phrase = phrase
self.endRegisterDate = endRegisterDate
self.endBetDate = endBetDate
self.totalStakes = totalStakes
self.isPublic = isPublic
self.invited = invited
self.author = author
self.registered = registered
}
/// Custom Constructor without Id
///
/// - Parameters:
/// - theme: The theme or topic of the bet.
/// - phrase: The specific phrase or question related to the bet.
/// - endRegisterDate: The deadline for users to register for the bet.
@ -49,6 +79,7 @@ public class Bet: ObservableObject {
/// - author: The user who created the bet.
/// - registered: List of users who have registered for the bet.
public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User]) {
self.id = UUID().uuidString
self.theme = theme
self.phrase = phrase
self.endRegisterDate = endRegisterDate

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

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

@ -0,0 +1,38 @@
//
// BetDetail.swift
//
//
// Created by Emre on 19/01/2024.
//
import Foundation
/// A class representing detailed information about a specific bet, including answers and user participations.
public class BetDetail: ObservableObject {
/// The main bet information.
public private(set) var bet: Bet
/// Details about the answers available for the bet.
public private(set) var answers: [BetAnswerDetail]
/// List of user participations in the bet.
public private(set) var participations: [Participation]
/// The user's own participation in the bet.
public private(set) var userParticipation: Participation
/// Custom Constructor
///
/// - Parameters:
/// - bet: The main bet information.
/// - answers: Details about the answers available for the bet.
/// - participations: List of user participations in the bet.
/// - userParticipation: The user's own participation in the bet.
public init(bet: Bet, answers: [BetAnswerDetail], participations: [Participation], userParticipation: Participation) {
self.bet = bet
self.answers = answers
self.participations = participations
self.userParticipation = userParticipation
}
}

@ -13,6 +13,23 @@ public class BinaryBet: Bet {
// Custom Constructor
///
/// - Parameters:
/// - id: The id for the bet.
/// - theme: The theme or topic of the binary bet.
/// - phrase: The specific phrase or question related to the binary bet.
/// - endRegisterDate: The deadline for users to register for the binary bet.
/// - endBetDate: The deadline for the actual betting to take place for the binary bet.
/// - totalStakes: The total stakes or amount involved in the binary bet.
/// - isPublic: Indicates whether the binary bet is public or private.
/// - invited: List of users who are invited to participate in the binary bet.
/// - author: The user who created the binary bet.
/// - registered: List of users who have registered for the binary bet.
public override init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User]) {
super.init(id: id, theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, totalStakes: totalStakes, isPublic: isPublic, invited: invited, author: author, registered: registered)
}
// Custom Constructor without Id
///
/// - Parameters:
/// - theme: The theme or topic of the binary bet.
/// - phrase: The specific phrase or question related to the binary bet.
/// - endRegisterDate: The deadline for users to register for the binary bet.

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

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

@ -10,5 +10,5 @@ import Foundation
public protocol FactoryBet {
func toResponse(bet: Bet) -> [String: Any]
func toModel(from json: [String: Any]) -> Bet?
func toModel(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet
func toModel(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet
}

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

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

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

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

@ -11,4 +11,5 @@ public protocol UserDataManager {
func getBets(withIndex index: Int, withCount count: Int) -> [Bet]
func addBet(bet: Bet)
func getFriends() -> [User]
func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void)
}

@ -12,14 +12,20 @@ public struct BetStubManager: BetDataManager {
public init() {}
public func getBets(withIndex index: Int, withCount count: Int) -> [Bet] {
return Stub.shared.bets
public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) {
completion(Stub.shared.bets)
}
public func getUsers(username: String) -> [User] {
return Stub.shared.users
.filter { user in
user.username.contains(username)
return []
}
public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) {
if let betDetail = Stub.shared.betsDetail.first(where: { $0.bet.id == id }) {
completion(betDetail)
} else {
print("BetDetail with ID \(id) not found.")
}
}

@ -12,6 +12,7 @@ struct Stub {
static var shared = Stub()
public var bets: [Bet] = []
public var betsDetail: [BetDetail] = []
public var users: [User] = []
public init() {
@ -83,9 +84,14 @@ struct Stub {
)
self.bets.append(bet4)
for bet in bets {
let betDetail = BetDetail(bet: bet, answers: [], participations: [], userParticipation: Participation(stake: 0, date: Date(), response: "", user: user1, betId: ""))
self.betsDetail.append(betDetail)
}
}
public mutating func add(bet: Bet) {
self.bets.append(bet)
let newBetDetail = BetDetail(bet: bet, answers: [], participations: [], userParticipation: Participation(stake: 0, date: Date(), response: "", user: users[1], betId: ""))
self.betsDetail.append(newBetDetail)
}
}

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

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

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

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