Last active
October 26, 2023 15:39
-
-
Save allfinlir/716fc74d443c8f8c4475a9766f2ccdbc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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())) | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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