Skip to content

Instantly share code, notes, and snippets.

@allfinlir
Last active October 26, 2023 15:39
Show Gist options
  • Save allfinlir/716fc74d443c8f8c4475a9766f2ccdbc to your computer and use it in GitHub Desktop.
Save allfinlir/716fc74d443c8f8c4475a9766f2ccdbc to your computer and use it in GitHub Desktop.
import SwiftUI
struct AddBetView: View {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var betViewModel: BetViewModel
@AppStorage("savehometeam") var homeTeamData: String = "Home Team"
@AppStorage("saveawayteam") var awayTeamData: String = "Away Team"
@State var chooseLeague: Leagues = .chooseleague
@State var homeTeam: String = ""
@State var awayTeam: String = ""
@State var selectDate = Date()
@State var typeOfBetInput: String = ""
@State var oddsOnBet: String = ""
@State var bettedAmount: String = ""
@State var potentialWinnings: String = ""
@State var countBets: Int = 0
@State var descriptionInput: String = ""
@State var addNewBettor: String = ""
@State private var presentAddBettorView: Bool = false
var body: some View {
Form {
Group {
Section(header: Text("New bet")) {
Picker("League", selection: $chooseLeague) {
ForEach(Leagues.allCases, id: \.self) { league in
Text(league.localName)
}
}
Picker("Home team", selection: $homeTeam) {
ForEach(selectLeague(league: chooseLeague), id: \.self) { selectedHomeTeam in
Text(selectedHomeTeam)
}
}
.onChange(of: homeTeam) { _ in
homeTeamData = homeTeam
}
Picker("Away team", selection: $awayTeam) {
ForEach(selectLeague(league: chooseLeague), id: \.self) { selectedAwayTeam in
Text(selectedAwayTeam)
}
}
.onChange(of: awayTeam) { _ in
awayTeamData = awayTeam
}
DatePicker("Game starts", selection: $selectDate, displayedComponents: [.date, .hourAndMinute])
.datePickerStyle(.compact)
TextField("Type of bet: 1X2, O/U, DC, HT/FT....", text: $typeOfBetInput)
// .keyboardType(.decimalPad) // not needed because not only numbers here to be inputed
TextField("Odds?", text: $oddsOnBet)
.keyboardType(.decimalPad)
TextField("Amount/Units on bet..", text: $bettedAmount)
.keyboardType(.decimalPad)
HStack {
Picker("Bettor", selection: $addNewBettor) {
ForEach(betViewModel.newBettors) { bettor in
NewBettorView(bettor: bettor)
.tag(bettor.newBettor)
}
}
HStack {
Text("")
}
.contentShape(Rectangle())
.padding(.leading, 16)
.overlay {
HStack {
// Spacer()
Button(action: {
presentAddBettorView = true
}, label: {
Image(systemName: "plus.circle")
.foregroundStyle(.blue)
})
.buttonStyle(PlainButtonStyle())
}
}
.layoutPriority(1)
}
}
Section(header: Text("Motivate bet: ")) {
TextEditor(text: $descriptionInput)
.frame(height: 200)
Button(action: {
pressSaveButton()
}, label: {
Text("Save bet")
.foregroundColor(.green)
})
}
}
}
.sheet(isPresented: $presentAddBettorView, content: {
AddBettorView(addNewBettor: addNewBettor, presentAddBettorView: $presentAddBettorView)
})
}
var oddsOnBetReplaceComma: String {
oddsOnBet.replacingOccurrences(of: ",", with: ".")
}
var bettedAmountReplaceComma: String {
bettedAmount.replacingOccurrences(of: ",", with: ".")
}
func pressSaveButton() {
betViewModel.addBet(league: chooseLeague.rawValue, country: selectedLeagueForCountryFlag(country: chooseLeague), homeTeam: homeTeam, awayTeam: awayTeam, dateForBet: selectDate, typeOfBet: typeOfBetInput, odds: Double(oddsOnBetReplaceComma) ?? 0.0, betAmount: Double(bettedAmountReplaceComma) ?? 0.0, bettor: [addNewBettor], potentialWin: Double(potentialWinnings) ?? 0.0, betCount: countBets, description: descriptionInput)
// betViewModel.newBettorAdded(bettor: addNewBettor)
presentationMode.wrappedValue.dismiss()
}
}
import SwiftUI
struct BetDetailsView: View {
var bet: BetModel
@EnvironmentObject var betViewModel: BetViewModel
// States to use draggesture to close this view
@GestureState private var dragToCloseView = CGSize.zero
@State private var currentPosition: CGFloat = 0.0
// States for the button animations
@State var scaleWinButton: CGFloat = 1.0
@State var scaleLooseButton: CGFloat = 1.0
@State var scalePushButton: CGFloat = 1.0
// Properties for the custom back button instead of using the built in nav bar back button.
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var customBackButton: some View {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}, label: {
Image(systemName: "chevron.left")
.foregroundColor(.black)
.font(.title)
})
}
// Alert used to show user they cant update the bet since game hasnt started yet
@State var gameNotstarted: Bool = false
@State var currentTimeDetailView = Date()
var body: some View {
VStack {
HStack {
customBackButton
Spacer()
}
ScrollView {
VStack(alignment: .leading, spacing: 10) {
HStack {
Spacer()
Text(bet.dateForBet, style: .date)
}
Text(bet.league)
.foregroundColor(.secondary)
.font(.title3)
.fontWeight(.semibold)
HStack {
Text(bet.homeTeam)
Text("vs")
.foregroundColor(.secondary)
.font(.title3)
Text(bet.awayTeam)
}
.font(.title2)
if currentTimeDetailView <= bet.dateForBet {
HStack(alignment: .center, spacing: 15) {
RoundedRectangle(cornerRadius: 4)
.frame(width: 55, height: 44)
.foregroundColor(.green.opacity(0.1))
.overlay {
Text("W")
.font(.system(size: 13))
.foregroundColor(.black)
.fontWeight(.light)
}
.onTapGesture {
gameNotstarted = true
}
RoundedRectangle(cornerRadius: 5)
.frame(width: 55, height: 44)
.foregroundColor(.red.opacity(0.1))
.overlay {
Text("L")
.font(.system(size: 13))
.foregroundColor(.black)
.fontWeight(.light)
}
.onTapGesture {
gameNotstarted = true
}
RoundedRectangle(cornerRadius: 5)
.frame(width: 55, height: 44)
.foregroundColor(.blue.opacity(0.1))
.overlay {
Text("P")
.font(.system(size: 13))
.foregroundColor(.black)
.fontWeight(.light)
}
.onTapGesture {
gameNotstarted = true
}
}
.padding(.top, 15)
.alert(isPresented: $gameNotstarted, content: {
Alert(title: Text("Game not started"), message: Text("You can update the result of your bet once the game has started. Good luck!"), dismissButton: .default(Text("Got it!")))
})
.frame(maxWidth: .infinity)
} else {
HStack(alignment: .center, spacing: 15) {
RoundedRectangle(cornerRadius: 4)
.frame(width: 55, height: 44)
.foregroundColor(bet.winBet ? .green : .green.opacity(0.1))
.overlay {
Text("W")
.font(.system(size: 13))
.foregroundColor(bet.winBet ? .white : .black)
.fontWeight(bet.winBet ? .semibold : .light)
}
.scaleEffect(scaleWinButton)
.animation(.easeInThenBackOut(duration: 0.3), value: scaleWinButton)
.onTapGesture {
betViewModel.updateWinBet(bet: bet)
scaleWinButton = 1.4
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
scaleWinButton = 1.0
}
}
RoundedRectangle(cornerRadius: 5)
.frame(width: 55, height: 44)
.foregroundColor(bet.looseBet ? .red : .red.opacity(0.1))
.overlay {
Text("L")
.font(.system(size: 13))
.foregroundColor(bet.looseBet ? .white : .black)
.fontWeight(bet.looseBet ? .semibold : .light)
}
.scaleEffect(scaleLooseButton)
.animation(.easeInThenBackOut(duration: 0.3), value: scaleLooseButton)
.onTapGesture {
betViewModel.updateLooseBet(bet: bet)
scaleLooseButton = 1.4
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
scaleLooseButton = 1.0
}
}
RoundedRectangle(cornerRadius: 5)
.frame(width: 55, height: 44)
.foregroundColor(bet.pushBet ? .blue : .blue.opacity(0.1))
.overlay {
Text("P")
.font(.system(size: 13))
.foregroundColor(bet.pushBet ? .white : .black)
.fontWeight(bet.pushBet ? .semibold : .light)
}
.scaleEffect(scalePushButton)
.animation(.easeInThenBackOut(duration: 0.3), value: scalePushButton)
.onTapGesture {
betViewModel.updatePushBet(bet: bet)
scalePushButton = 1.4
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
scalePushButton = 1.0
}
}
}
.padding(.top, 15)
.frame(maxWidth: .infinity)
}
VStack(alignment: .leading, spacing: 25) {
HStack {
Text("Bet:")
Text(bet.typeOfBet)
.foregroundStyle(.secondary)
.padding(.trailing, 8)
Text("Odds:")
Text("\(bet.odds, specifier: "%.2f")")
.foregroundStyle(.secondary)
.padding(.trailing, 8)
Text("Amount:")
Text("\(bet.betAmount, specifier: "%.2f")")
.foregroundStyle(.secondary)
}
.padding(.top, 25)
HStack(alignment: .bottom, spacing: 20) {
Text("Result:")
Text("\(bet.potentialWin, specifier: "%.2f")")
.foregroundStyle(bet.potentialWin < 0.0 ? .red : (bet.potentialWin > 0.0 ? .green : .secondary))
.font(.title2)
.opacity(bet.winBet || bet.looseBet || bet.pushBet ? 1 : 0)
}
}
Text("Motivation")
.foregroundColor(.secondary)
.font(.title3)
.fontWeight(.semibold)
.padding(.top, 15)
if bet.description.isEmpty {
VStack {
Text("No motivation for bet")
}
} else {
VStack {
Text(bet.description)
.frame(maxWidth: .infinity)
.font(.title3)
.multilineTextAlignment(.center)
.padding(.vertical, 15)
.padding(.horizontal, 25)
.background(
ZStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.white)
.shadow(color: .black.opacity(0.1), radius: 4, x: 4, y: 4)
}
)
}
.frame(maxWidth: .infinity)
}
NavigationLink("Edit", destination: {
EditBetView(bet: bet, chooseLeague: Leagues(rawValue: bet.league)!, homeTeam: bet.homeTeam, awayTeam: bet.awayTeam, selectDate: bet.dateForBet, typeOfBetInput: bet.typeOfBet, oddsOnBet: String(bet.odds), bettedAmount: String(bet.betAmount), potentialWinnings: String(bet.potentialWin), countBets: bet.betCount, descriptionInput: bet.description, addNewBettor: bet.bettor)
})
}
}
.offset(x: dragToCloseView.width)
.gesture(
DragGesture(minimumDistance: 75)
.updating($dragToCloseView, body: { (value, dragToCloseView, transaction) in
dragToCloseView = value.translation
})
.onEnded({ value in
if value.translation.width > 10 || value.translation.width < -10 {
self.presentationMode.wrappedValue.dismiss()
}
})
)
}
.padding()
.onAppear() {
currentTimeDetailView = Date()
}
}
}
/*struct BetDetailsView_Previews: PreviewProvider {
static var betItem1 = BetModel(league: "LaLiga", country: "spain", homeTeam: "Real Madrid", awayTeam: "Atletico Madrid", dateForBEt: Date(), typeOfBet: "1", odds: 1.78, betAmount: 100, bettor: ["Rikard", "Petros"], potentialWin: 178, winBet: false, looseBet: false, pushBet: false, betCount: 1, description: "I think Real Madrid will win because they are so much better than Atletico :)")
@Namespace static var namespace
@State static var bool: Bool = false
static var previews: some View {
BetDetailsView(bet: betItem1)
}
} */
// The animation for the button press for win, loss & push.
extension Animation {
static var easeInThenBackOut: Animation {
Animation.timingCurve(0.5, -1, 0.5, 1.5)
}
static func easeInThenBackOut(duration: TimeInterval = 0.2) -> Animation {
Animation.timingCurve(0.5, -1, 0.5, 1.5, duration: duration)
}
}
import Foundation
import SwiftUI
struct BetModel: Identifiable, Codable { // Identifiable so we have id on each item and codable so it can handle JSON data
let id: String
var league: String
var country: String
var homeTeam: String
var awayTeam: String
var dateForBet: Date
var typeOfBet: String
var odds: Double
var betAmount: Double
var bettor: [String]
var potentialWin: Double
var winBet: Bool
var looseBet: Bool
var pushBet: Bool
var betCount: Int
var description: String
init(id: String = UUID().uuidString, league: String, country: String, homeTeam: String, awayTeam: String, dateForBEt: Date, typeOfBet: String, odds: Double, betAmount: Double, bettor: [String], potentialWin: Double, winBet: Bool, looseBet: Bool, pushBet: Bool, betCount: Int, description: String) {
self.id = id
self.league = league
self.country = country
self.homeTeam = homeTeam
self.awayTeam = awayTeam
self.dateForBet = dateForBEt
self.typeOfBet = typeOfBet
self.odds = odds
self.betAmount = betAmount
self.bettor = bettor
self.potentialWin = potentialWin
self.winBet = winBet
self.looseBet = looseBet
self.pushBet = pushBet
self.betCount = betCount
self.description = description
}
func updateWinCompletion() -> BetModel {
return BetModel(id: id, league: league, country: country, homeTeam: homeTeam, awayTeam: awayTeam, dateForBEt: dateForBet, typeOfBet: typeOfBet, odds: odds, betAmount: betAmount, bettor: bettor, potentialWin: winBet ? 0.0 : (odds * betAmount) - betAmount, winBet: !winBet, looseBet: looseBet, pushBet: pushBet, betCount: betCount, description: description)
}
func updateLostCompletion() -> BetModel {
return BetModel(id: id, league: league, country: country, homeTeam: homeTeam, awayTeam: awayTeam, dateForBEt: dateForBet, typeOfBet: typeOfBet, odds: odds, betAmount: betAmount, bettor: bettor, potentialWin: looseBet ? 0.0 : -betAmount, winBet: winBet, looseBet: !looseBet, pushBet: pushBet, betCount: betCount, description: description)
}
func updatePushCompletion() -> BetModel {
return BetModel(id: id, league: league, country: country, homeTeam: homeTeam, awayTeam: awayTeam, dateForBEt: dateForBet, typeOfBet: typeOfBet, odds: odds, betAmount: betAmount, bettor: bettor, potentialWin: 0.0, winBet: winBet, looseBet: looseBet, pushBet: !pushBet, betCount: betCount, description: description)
}
func editBetCompletion() -> BetModel {
return BetModel(id: id, league: league, country: country, homeTeam: homeTeam, awayTeam: awayTeam, dateForBEt: dateForBet, typeOfBet: typeOfBet, odds: odds, betAmount: betAmount, bettor: bettor, potentialWin: potentialWin, winBet: winBet, looseBet: looseBet, pushBet: pushBet, betCount: betCount, description: description)
}
}
struct BetRowView: View {
var bet: BetModel
@EnvironmentObject var betViewModel: BetViewModel
@State var currentTime = Date()
var body: some View {
ZStack(alignment: .center) {
VStack(spacing: 5) {
HStack {
Spacer()
if currentTime <= bet.dateForBet {
VStack {
Text(bet.dateForBet, style: .relative)
Text("to game time")
}
.font(.system(size: 10))
} else if currentTime >= bet.dateForBet.addingTimeInterval(200) || bet.winBet || bet.looseBet || bet.pushBet {
ZStack {
HStack(spacing: 5) {
ZStack {
Image(systemName: "arrow.up.forward")
.foregroundStyle(.green)
.opacity(bet.winBet ? 1 : 0)
Image(systemName: "arrow.down.forward")
.foregroundStyle(.red)
.opacity(bet.looseBet ? 1 : 0)
Image(systemName: "arrow.clockwise")
.foregroundStyle(.blue)
.opacity(bet.pushBet ? 1 : 0)
}
ZStack {
Text("Win?")
.fontWeight(.semibold)
.opacity(bet.winBet ? 0 : 1)
.opacity(bet.looseBet ? 0 : 1)
.opacity(bet.pushBet ? 0 : 1)
Text("Win")
.foregroundStyle(.white)
.fontWeight(.semibold)
.padding(3)
.background(
Color.green
.opacity(0.7)
)
.opacity(bet.winBet ? 1 : 0)
Text("Loss")
.foregroundStyle(.white)
.fontWeight(.semibold)
.padding(3)
.background(
Color.red
.opacity(0.7)
)
.opacity(bet.looseBet ? 1 : 0)
Text("Push")
.foregroundStyle(.white)
.fontWeight(.semibold)
.padding(3)
.background(
Color.blue
.opacity(0.7)
)
.opacity(bet.pushBet ? 1 : 0)
}
}
}
.font(.system(size: 10))
} else {
Text("Ongoing")
.font(.system(size: 10))
.foregroundStyle(.orange)
}
}
.padding(.trailing, 30)
}
.onReceive(Timer.publish(every: 1, on: .main, in: .common).autoconnect()) { _ in
currentTime = Date()
}
HStack(alignment: .center) {
VStack(alignment: .leading, spacing: 5) {
HStack {
Image("\(bet.country)")
.resizable()
.frame(width: 16, height: 9)
Text(bet.league)
.foregroundColor(.secondary)
.font(.system(size: 10))
.fontWeight(.semibold)
}
Text(bet.homeTeam)
.font(.system(size: 15))
Text(bet.awayTeam)
.font(.system(size: 15))
HStack(spacing: 3) {
Text("Bet:")
.fontWeight(.semibold)
Text(bet.typeOfBet)
.foregroundColor(.secondary)
.padding(.trailing, 8)
Text("Odds:")
.fontWeight(.semibold)
Text("\(bet.odds, specifier: "%.2f")")
.foregroundColor(.secondary)
.padding(.trailing, 8)
Text("Amount:")
.fontWeight(.semibold)
Text("\(bet.betAmount, specifier: "%.2f")")
.foregroundColor(.secondary)
}
.font(.system(size: 10))
}
.lineLimit(1)
Spacer()
}
.frame(maxWidth: .infinity)
}
}
}
struct BetRowView_Previews: PreviewProvider {
static var betItem1 = BetModel(league: "LaLiga", country: "spain", homeTeam: "Real Madrid", awayTeam: "Atletico Madrid", dateForBEt: Date(), typeOfBet: "U2.5", odds: 1.73, betAmount: 100, bettor: ["Rikard", "Petros"], potentialWin: 178, winBet: false, looseBet: false, pushBet: false, betCount: 1, description: "Hello there")
@Namespace static var namespace
static var previews: some View {
BetRowView(bet: betItem1)
.previewLayout(.sizeThatFits)
}
}
import SwiftUI
struct BetView: View {
@EnvironmentObject var betViewModel: BetViewModel
var body: some View {
ZStack {
NavigationStack {
VStack {
if betViewModel.betItems.isEmpty {
NoBetView()
} else {
ZStack {
List {
ForEach(betViewModel.betItems) { bet in
NavigationLink(destination: BetDetailsView(bet: bet).navigationBarBackButtonHidden()) {
BetRowView(bet: bet)
}
}
.onDelete(perform: betViewModel.deleteBet)
.onMove(perform: betViewModel.moveBet)
//.listRowSeparator(.hidden)
}
.listStyle(.inset)
VStack {
Spacer()
HStack {
Spacer()
NavigationLink(destination: AddBetView(), label: {
Image(systemName: "plus")
.foregroundColor(.white)
.font(.system(size: 30))
.padding()
.background(
Circle()
.foregroundColor(.green)
.shadow(color: .black.opacity(0.2), radius: 1, x: 1, y: 1)
)
})
.padding(20)
}
}
}
}
}
.navigationBarItems(leading: EditButton(), trailing: NavigationLink("Add", destination: AddBetView()))
}
}
}
}
import Foundation
class BetViewModel: ObservableObject {
@Published var betItems: [BetModel] = []
@Published var newBettors: [AddBettorDataModel] = []
init() {
getBets() // fetches my data from getBets() function
}
let betItemKey: String = "Bets"
func getBets() {
guard let data = UserDefaults.standard.data(forKey: betItemKey),
let savedBetItems = try? JSONDecoder().decode([BetModel].self, from: data)
else { return }
self.betItems = savedBetItems.sorted(by: { $0.dateForBet > $1.dateForBet }) // this will sort all bets in the array by date.
}
// MARK: So data get saved once the app is closed by the user,
func saveBet() {
if let encodedBetData = try? JSONEncoder().encode(betItems) {
UserDefaults.standard.set(encodedBetData, forKey: betItemKey)
getBets() // by adding the function here, all new items in the array will be sorted on date as well.
} else {
print("Couldn't save bet")
}
}
public var totalWinningsLosses: Double {
return betItems.reduce(0) { sum, betResults in
sum + betResults.potentialWin
}
}
// MARK: So we can add more bettors to select from
func newBettorAdded(bettor: String) {
let newBettor = AddBettorDataModel(newBettor: bettor)
newBettors.insert(newBettor, at: 0)
// saveBet()
}
// MARK: Sorts all bets by date in the WinChart View
func makeChartData(from bets: [BetModel]) -> [BetDataPoint] {
let sortedBets = betItems.sorted { $0.dateForBet < $1.dateForBet }
var currentTotal = 0.0
let dataPoints = sortedBets.map { bet in
currentTotal += bet.potentialWin
return BetDataPoint(date: bet.dateForBet, total: currentTotal, league: bet.league)
}
return dataPoints
}
// MARK: sorts the bets to only the latest 7 days bet results
func chartDataPerWeek(from bets: [BetModel]) -> [BetDataPointPerWeek] {
let lastWeek = Calendar.current.date(byAdding: .day, value: -7, to: Date()) ?? Date()
let sortedBetsLastWeek = betItems.filter { $0.dateForBet >= lastWeek }.sorted(by: { $0.dateForBet < $1.dateForBet })
var currentWeekTotal = 0.0
let weekDataPoints = sortedBetsLastWeek.map { weekBets in
currentWeekTotal += weekBets.potentialWin
return BetDataPointPerWeek(date: weekBets.dateForBet, totalLastWeek: currentWeekTotal)
}
return weekDataPoints
}
// MARK: sorts the bets to only the latest 7 days bet results
func resultsLastWeek() -> [BetModel] {
let lastWeek = Calendar.current.date(byAdding: .day, value: -7, to: Date()) ?? Date()
return betItems.filter { $0.dateForBet >= lastWeek }.sorted(by: { $0.dateForBet > $1.dateForBet})
}
// MARK: So you can delete bets from the list
func deleteBet(indexSet: IndexSet) {
betItems.remove(atOffsets: indexSet)
saveBet()
}
// test code for now
func editBet(indexSet: IndexSet, updatedBet: BetModel) {
for index in indexSet {
betItems[index] = updatedBet
}
saveBet()
}
// MARK: So you can move items in the bet list
func moveBet(from: IndexSet, to: Int) {
betItems.move(fromOffsets: from, toOffset: to)
}
// MARK: Counts all winning bets
func winningBets() -> Int {
betItems.filter { $0.winBet == true }.count
}
// MARK: Counts all loosing bets.
func loosingBets() -> Int {
betItems.filter { $0.looseBet == true }.count
}
// MARK: counts all bet that are push bets
func pushBets() -> Int {
betItems.filter { $0.pushBet == true }.count
}
// MARK: calculates all bets that have not been decided yet, those that are ongoing
func ongoingBets() -> Int {
betItems.filter { $0.winBet == false && $0.looseBet == false && $0.pushBet == false }.count
}
// MARK: So you can add a bet in the bet view, save saveBet() is there so the list is saved when app is closed by user.
func addBet(league: String, country: String, homeTeam: String, awayTeam: String, dateForBet: Date, typeOfBet: String, odds: Double, betAmount: Double, bettor: [String], potentialWin: Double, betCount: Int, description: String) {
let newBet = BetModel(league: league, country: country, homeTeam: homeTeam, awayTeam: awayTeam, dateForBEt: dateForBet, typeOfBet: typeOfBet, odds: odds, betAmount: betAmount, bettor: bettor, potentialWin: potentialWin, winBet: false, looseBet: false, pushBet: false, betCount: betCount, description: description)
// betItems.append(newBet)
betItems.insert(newBet, at: 0) // use this instead if you want your bet to append at the top of your list
saveBet()
}
// MARK: Updates the bet row view and toggles the winbet boolean from false to true.
func updateWinBet(bet: BetModel) {
if let betWinIndex = betItems.firstIndex(where: {$0.id == bet.id }) {
betItems[betWinIndex] = bet.updateWinCompletion() // updateWinCompletion sätter jag i BetModel som uppdaterar winBet boolean och så gör vi de andra till false så att man bara "kan" välja en.
betItems[betWinIndex].looseBet = false
betItems[betWinIndex].pushBet = false
saveBet()
}
}
func editBetInfo(bet: BetModel) {
if let editBetIndex = betItems.firstIndex(where: { $0.id == bet.id }) {
betItems[editBetIndex] = bet.editBetCompletion()
saveBet()
}
}
// MARK: Updates the bet row view and toggles the loosebet boolean from false to true.
func updateLooseBet(bet: BetModel) {
if let betLooseIndex = betItems.firstIndex(where: {$0.id == bet.id }) {
betItems[betLooseIndex] = bet.updateLostCompletion() // updateLostCompletion sätter vi ju in vår BetModel
betItems[betLooseIndex].winBet = false
betItems[betLooseIndex].pushBet = false
saveBet()
}
}
// MARK: Updates the bet row view and toggles the pushbet boolean from false to true.
func updatePushBet(bet: BetModel) {
if let betPushIndex = betItems.firstIndex(where: {$0.id == bet.id}) {
betItems[betPushIndex] = bet.updatePushCompletion()
betItems[betPushIndex].winBet = false
betItems[betPushIndex].looseBet = false
saveBet()
}
}
// MARK: Filter all winning bets to a list. Used for the button in HomeView.
func winBetsFilterList() -> [BetModel] {
betItems.filter { $0.winBet == true }
}
// MARK: Filter all loosing bets to a list. Used for the button in HomeView.
func looseBetsFilterList() -> [BetModel] {
betItems.filter { $0.looseBet == true }
}
// MARK: Filter all push bets to a list. Used for the button in HomeView.
func pushBetsFilterList() -> [BetModel] {
betItems.filter { $0.pushBet == true }
}
}
import SwiftUI
struct EditBetView: View {
@State var bet: BetModel
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var betViewModel: BetViewModel
@AppStorage("savehometeam") var homeTeamData: String = "Home Team"
@AppStorage("saveawayteam") var awayTeamData: String = "Away Team"
@State var chooseLeague: Leagues = .chooseleague
@State var homeTeam: String = ""
@State var awayTeam: String = ""
@State var selectDate = Date()
@State var typeOfBetInput: String = ""
@State var oddsOnBet: String = ""
@State var bettedAmount: String = ""
@State var potentialWinnings: String = ""
@State var countBets: Int = 0
@State var descriptionInput: String = ""
@State var addNewBettor: [String] = [""]
@State var addnewNewBettor: String = ""
@State private var presentAddBettorView: Bool = false
let indicesIndexSet = IndexSet(integer: 0)
var body: some View {
Form {
Group {
Section(header: Text("New bet")) {
Picker("League", selection: $chooseLeague) {
ForEach(Leagues.allCases, id: \.self) { league in
Text(league.localName)
}
}
Picker("Home team", selection: $homeTeam) {
ForEach(selectLeague(league: chooseLeague), id: \.self) { selectedHomeTeam in
Text(selectedHomeTeam)
}
}
.onChange(of: homeTeam) { _ in
homeTeamData = homeTeam
}
Picker("Away team", selection: $awayTeam) {
ForEach(selectLeague(league: chooseLeague), id: \.self) { selectedAwayTeam in
Text(selectedAwayTeam)
}
}
.onChange(of: awayTeam) { _ in
awayTeamData = awayTeam
}
DatePicker("Game starts", selection: $selectDate, displayedComponents: [.date, .hourAndMinute])
.datePickerStyle(.compact)
TextField("Type of bet: 1X2, O/U, DC, HT/FT....", text: $typeOfBetInput)
// .keyboardType(.decimalPad) // not needed because not only numbers here to be inputed
TextField("Odds?", text: $oddsOnBet)
.keyboardType(.decimalPad)
TextField("Amount/Units on bet..", text: $bettedAmount)
.keyboardType(.decimalPad)
HStack {
Picker("Bettor", selection: $addNewBettor) {
ForEach(betViewModel.newBettors) { bettor in
NewBettorView(bettor: bettor)
.tag(bettor.newBettor)
}
}
HStack {
Text("")
}
.contentShape(Rectangle())
.padding(.leading, 16)
.overlay {
HStack {
// Spacer()
Button(action: {
presentAddBettorView = true
}, label: {
Image(systemName: "plus.circle")
.foregroundStyle(.blue)
})
.buttonStyle(PlainButtonStyle())
}
}
.layoutPriority(1)
}
}
Section(header: Text("Motivate bet: ")) {
TextEditor(text: $descriptionInput)
.frame(height: 200)
Button(action: {
bet.league = chooseLeague.rawValue
bet.homeTeam = homeTeam
bet.awayTeam = awayTeam
bet.dateForBet = selectDate
bet.typeOfBet = typeOfBetInput
bet.odds = Double(oddsOnBet) ?? 0.0
bet.betAmount = Double(bettedAmount) ?? 0.0
bet.potentialWin = Double(potentialWinnings) ?? 0.0
bet.description = descriptionInput
bet.bettor = [addnewNewBettor]
betViewModel.editBetInfo(bet: bet)
presentationMode.wrappedValue.dismiss()
}, label: {
Text("Update bet")
.foregroundColor(.green)
})
}
}
}
.sheet(isPresented: $presentAddBettorView, content: {
AddBettorView(addNewBettor: addnewNewBettor, presentAddBettorView: $presentAddBettorView)
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment