get custom answers and add the creation of bet custom

pull/39/head
Emre KARTAL 8 months ago
parent b878759b3d
commit b7efad2eed

@ -0,0 +1 @@
Subproject commit 5d1ea8492aa6d4be39036165d00016d6951ae91a

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

@ -1,12 +1,3 @@
//
// DropDownAnswerMenu.swift
// AllIn
//
// Created by Lucas Delanier on 16/01/2024.
//
import SwiftUI
//
// DropDownMenu.swift
// AllIn
@ -15,20 +6,21 @@ import SwiftUI
//
import SwiftUI
import Model
struct DropDownAnswerMenu: View {
@State var expand = false
@Binding var selectedOption: Int
var options: [(Int, String, Float)]
@Binding var selectedAnswer: AnswerDetail
var answers: [AnswerDetail]
var body: some View {
VStack(spacing: 0, content: {
Button(action: { self.expand.toggle() }) {
Button(action: { withTransaction(Transaction(animation: nil)) { self.expand.toggle() } }) {
HStack{
Text(options[selectedOption].1.description)
Text(selectedAnswer.response)
.textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20)
Text(options[selectedOption].2.description)
Text(selectedAnswer.odds.description)
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10)
Spacer()
@ -43,19 +35,21 @@ struct DropDownAnswerMenu: View {
.foregroundColor(AllInColors.delimiterGrey)
.padding(.bottom, 18)
VStack(spacing: 0) {
ForEach(0..<options.count, id: \.self) { index in
if options[index].0 != selectedOption {
Button(action: {self.selectedOption = options[index].0
self.expand.toggle()}) {
HStack{
Text(options[index].1.description)
.textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20)
Text(options[index].2.description)
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10)
Spacer()
}
ForEach(answers) { (answer: AnswerDetail) in
if answer != selectedAnswer {
Button(action: {
self.selectedAnswer = answer
self.expand.toggle()}
) {
HStack{
Text(answer.response)
.textStyle(weight: .bold, color: AllInColors.blueAccentColor, size: 20)
Text(answer.odds.description)
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 10)
Spacer()
}
.padding(.bottom, 15)
}
.padding(.bottom, 15)
}
}
}
@ -70,15 +64,3 @@ 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,33 +6,25 @@
//
import SwiftUI
import Model
struct ParticipationModal: View {
@Binding private var selectedOption: Int
@Binding private var mise: String
private var description: String
var participationAddedCallback: (() -> Void)?
@Binding var selectedAnswer: AnswerDetail
@Binding var mise: String
var phrase: String
var answers: [AnswerDetail]
var participationAddedCallback: () -> Void
var checkAndSetError: () -> Bool
var possibleGain: Int {
if let stake = Float(mise), let selectedOption = options.first(where: { $0.0 == self.selectedOption }) {
return Int(round(stake * selectedOption.2))
if let stake = Float(mise) {
return Int(round(stake * selectedAnswer.odds))
} else {
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 {
GeometryReader { geometry in
VStack(alignment: .leading){
@ -56,12 +48,12 @@ struct ParticipationModal: View {
}
.padding(.leading, 15)
VStack(alignment: .leading){
Text(description)
Text(phrase)
.font(.system(size: 13))
.foregroundColor(AllInColors.primaryTextColor)
.fontWeight(.light)
DropDownAnswerMenu(selectedOption: $selectedOption, options: options)
DropDownAnswerMenu(selectedAnswer: $selectedAnswer, answers: answers)
TextField("", text: $mise, prompt: Text("generic_stake")
.foregroundColor(AllInColors.lightGrey300Color)
@ -104,7 +96,7 @@ struct ParticipationModal: View {
.padding(.top, 10)
.padding(.bottom, 0)
Button {
participationAddedCallback?()
participationAddedCallback()
} label: {
Text("Miser")
.font(.system(size: 23))
@ -125,16 +117,4 @@ struct ParticipationModal: View {
.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
}
}
}

@ -23,19 +23,36 @@ class CreationBetViewModel: ObservableObject {
@Published var endRegisterDate = Date()
@Published var endBetDate = Date()
@Published var betAdded = false
@Published var selectedOption = 0
@Published var selectedTypeBet = 0 {
didSet {
values.removeAll()
groupedItems.removeAll()
response = ""
}
}
@Published var values: [String] = []
@Published var invited: Set<String> = []
@Published var themeFieldError: String?
@Published var descriptionFieldError: String?
@Published var endRegisterDateFieldError: String?
@Published var endBetDateFieldError: String?
@Published var responsesFieldError: String?
@Published var errorMessage: String?
@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()
}
@ -50,14 +67,14 @@ class CreationBetViewModel: ObservableObject {
func create() {
guard checkAndSetError(forTheme: true, forDescription: true, forEndRegisterDate: true, forEndBetDate: true) else {
guard checkAndSetError(forTheme: true, forDescription: true, forEndRegisterDate: true, forEndBetDate: true, forResponse: true) else {
return
}
resetAllFieldErrors()
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: selectedOption)) { statusCode in
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
print(statusCode)
switch statusCode {
case 201:
@ -72,12 +89,13 @@ class CreationBetViewModel: ObservableObject {
}
}
func checkAndSetError(forTheme checkTheme: Bool, forDescription checkDescription: Bool, forEndRegisterDate checkEndRegisterDate: Bool, forEndBetDate checkEndBetDate: Bool) -> Bool {
func checkAndSetError(forTheme checkTheme: Bool, forDescription checkDescription: Bool, forEndRegisterDate checkEndRegisterDate: Bool, forEndBetDate checkEndBetDate: Bool, forResponse checkResponse: Bool) -> Bool {
var newThemeFieldError: String?
var newDescriptionFieldError: String?
var newEndRegisterDateFieldError: String?
var newEndBetDateFieldError: String?
var newResponsesFieldError: String?
var hasError = false
@ -105,6 +123,19 @@ class CreationBetViewModel: ObservableObject {
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 {
// No error
return true
@ -115,6 +146,7 @@ class CreationBetViewModel: ObservableObject {
descriptionFieldError = newDescriptionFieldError
endRegisterDateFieldError = newEndRegisterDateFieldError
endBetDateFieldError = newEndBetDateFieldError
responsesFieldError = newResponsesFieldError
}
return false
}
@ -125,6 +157,7 @@ class CreationBetViewModel: ObservableObject {
descriptionFieldError = nil
endRegisterDateFieldError = nil
endBetDateFieldError = nil
responsesFieldError = nil
}
}
@ -140,7 +173,11 @@ class CreationBetViewModel: ObservableObject {
case 1:
return MatchBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator, nameTeam1: "", nameTeam2: "")
case 2:
return CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator)
var bet = CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator)
for answer in values {
bet.addCustomResponse(answer)
}
return bet
default:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPrivate: isPrivate, status: status, invited: invited, author: creator)
}

@ -15,9 +15,9 @@ class DetailsViewModel: ObservableObject {
@Inject var manager: Manager
var id: String
@Published var answer = 0
@Published var selectedAnswer = AnswerDetail(response: "", totalStakes: 0, totalParticipants: 0, highestStake: 0, odds: 0)
@Published var mise: String = ""
@Published var betDetail: BetDetail?
init(id: String) {
@ -28,28 +28,22 @@ class DetailsViewModel: ObservableObject {
func getItem(withId id: String) {
manager.getBet(withId: id) { bet in
DispatchQueue.main.async {
for par in bet.participations {
print(par.id)
}
self.betDetail = bet
if let firstAnswer = bet.answers.first {
self.selectedAnswer = firstAnswer
}
}
}
}
func addParticipate() {
if let stake = Int(mise) {
var rep: String = ""
if answer == 0 {
rep = "Yes"
} else {
rep = "No"
}
manager.addParticipation(withId: id, withAnswer: rep, andStake: stake) { statusCode in
manager.addParticipation(withId: id, withAnswer: selectedAnswer.response, andStake: stake) { statusCode in
switch statusCode {
case 201:
AppStateContainer.shared.user?.nbCoins -= stake
WidgetCenter.shared.reloadAllTimelines()
self.getItem(withId: self.id)
default:
break
@ -57,10 +51,20 @@ class DetailsViewModel: ObservableObject {
}
}
mise = ""
answer = 0
if let firstAnswer = betDetail!.answers.first {
self.selectedAnswer = firstAnswer
}
}
func checkAndSetError() {
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
}
}
}

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

@ -122,7 +122,6 @@ struct DetailsView: View {
.padding(.bottom, 10)
ScrollView(showsIndicators: false) {
ForEach(viewModel.betDetail?.participations ?? []) { participation in
// TODO
UserInfo(username: participation.username, picture: nil , value: participation.stake).padding(.horizontal, 10)
}
}
@ -145,10 +144,11 @@ struct DetailsView: View {
.padding(.horizontal, 10)
}
.sheet(isPresented: $isModalParticipated) {
ParticipationModal(answer: $viewModel.answer, mise: $viewModel.mise, description: viewModel.betDetail?.bet.phrase ?? "Not loaded", participationAddedCallback: {
ParticipationModal(selectedAnswer: $viewModel.selectedAnswer, mise: $viewModel.mise, phrase: viewModel.betDetail?.bet.phrase ?? "", answers: viewModel.betDetail?.answers ?? [], participationAddedCallback: {
viewModel.addParticipate()
isModalParticipated.toggle()
})
},
checkAndSetError: viewModel.checkAndSetError)
.presentationDetents([.fraction(0.55)])
}
.edgesIgnoringSafeArea(.bottom)

@ -24,7 +24,7 @@ public class FactoryApiBet: FactoryBet {
"endRegistration": formatZonedDateTime(dateTime: bet.endRegisterDate),
"endBet": formatZonedDateTime(dateTime: bet.endBetDate),
"isPrivate": String(bet.isPrivate),
"response": ["Yes","No"],
"response": bet.getResponses(),
"userInvited": bet.invited,
"type": betTypeString(fromType: String(describing: type(of: bet)))
]

@ -67,7 +67,6 @@ public struct UserApiManager: UserDataManager {
print ("ALLIN : get bets won")
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) {
print(bet)

@ -8,7 +8,7 @@
import Foundation
/// A class representing detailed information about a specific answer option for a bet.
public class AnswerDetail: ObservableObject, Identifiable, Codable {
public class AnswerDetail: ObservableObject, Codable, Equatable, Identifiable {
/// The response or outcome associated with this answer.
public private(set) var response: String
@ -41,4 +41,12 @@ public class AnswerDetail: ObservableObject, Identifiable, Codable {
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
}
}

@ -8,7 +8,7 @@
import Foundation
/// A class representing a betting entity, including details about the bet theme, participants, and deadlines.
public class Bet: ObservableObject, Identifiable, Codable {
public class Bet: ObservableObject, Codable {
/// The id for the bet.
public private(set) var id: String
@ -112,4 +112,11 @@ public class Bet: ObservableObject, Identifiable, Codable {
self.author = author
}
/// Function that returns an empty list of responses
///
/// - Returns: An empty list of responses
public func getResponses() -> [String] {
return []
}
}

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

Loading…
Cancel
Save