diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 2f8d0c0..1ab3708 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -1985,7 +1985,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; OTHER_SWIFT_FLAGS = "-Onone"; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; @@ -2033,7 +2033,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=5 -Xfrontend -warn-long-expression-type-checking=20 -Xfrontend -warn-long-function-bodies=50"; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index c5db5d1..1c90fef 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -498,6 +498,14 @@ final class TeamRegistration: ModelObject, Storable { return self.tournamentStore.matches.first(where: { $0.round == initialRoundObject.id && $0.index == bracketPosition / 2 }) } + func toggleSummonConfirmation() { + if confirmationDate == nil { confirmationDate = Date() } + else { confirmationDate = nil } + } + + func didConfirmSummon() -> Bool { + confirmationDate != nil + } func tournamentObject() -> Tournament? { return Store.main.findById(tournament) diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 3fe8d03..7ad53ff 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -113,7 +113,7 @@ final class Tournament : ModelObject, Storable { self.startDate = startDate self.endDate = endDate self.creationDate = creationDate - self.isPrivate = isPrivate + self.isPrivate = Guard.main.purchasedTransactions.isEmpty self.groupStageFormat = groupStageFormat self.roundFormat = roundFormat self.loserRoundFormat = loserRoundFormat diff --git a/PadelClub/Utils/Patcher.swift b/PadelClub/Utils/Patcher.swift index 0b6368c..66a71ee 100644 --- a/PadelClub/Utils/Patcher.swift +++ b/PadelClub/Utils/Patcher.swift @@ -15,6 +15,7 @@ enum PatchError: Error { enum Patch: String, CaseIterable { case alexisLeDu case importDataFromDevToProd + case fixMissingMatches var id: String { return "padelclub.app.patch.\(self.rawValue)" @@ -45,6 +46,7 @@ class Patcher { switch patch { case .alexisLeDu: self._patchAlexisLeDu() case .importDataFromDevToProd: try self._importDataFromDev() + case .fixMissingMatches: self._patchMissingMatches() } } @@ -115,5 +117,48 @@ class Patcher { } } + + fileprivate static func _patchMissingMatches() { + + guard let url = StoreCenter.main.synchronizationApiURL else { + return + } + guard url == "https://padelclub.app/roads/" else { + return + } + let services = Services(url: url) + + for tournament in DataStore.shared.tournaments { + + let store = tournament.tournamentStore + let identifier = StoreIdentifier(value: tournament.id, parameterName: "tournament") + + Task { + + do { + // if nothing is online we upload the data + let matches: [Match] = try await services.get(identifier: identifier) + if matches.isEmpty { + store.matches.insertAllIntoCurrentService() + } + + let playerRegistrations: [PlayerRegistration] = try await services.get(identifier: identifier) + if playerRegistrations.isEmpty { + store.playerRegistrations.insertAllIntoCurrentService() + } + + let teamScores: [TeamScore] = try await services.get(identifier: identifier) + if teamScores.isEmpty { + store.teamScores.insertAllIntoCurrentService() + } + + } catch { + Logger.error(error) + } + + } + } + + } } diff --git a/PadelClub/Views/Calling/TeamsCallingView.swift b/PadelClub/Views/Calling/TeamsCallingView.swift index 656351a..4575acb 100644 --- a/PadelClub/Views/Calling/TeamsCallingView.swift +++ b/PadelClub/Views/Calling/TeamsCallingView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import LeStorage struct TeamsCallingView: View { @Environment(Tournament.self) var tournament: Tournament @@ -15,7 +16,23 @@ struct TeamsCallingView: View { let teams = tournament.selectedSortedTeams() Section { ForEach(teams) { team in - TeamRowView(team: team, displayCallDate: true) + Menu { + _menuOptions(team: team) + } label: { + HStack { + TeamRowView(team: team, displayCallDate: true) + if team.called() { + Spacer() + Menu { + _menuOptions(team: team) + } label: { + LabelOptions().labelStyle(.iconOnly) + } + } + } + } + .buttonStyle(.plain) + .listRowView(isActive: team.didConfirmSummon(), color: .green, hideColorVariation: true) } } } @@ -25,4 +42,34 @@ struct TeamsCallingView: View { .toolbarBackground(.visible, for: .navigationBar) } + @ViewBuilder + func _menuOptions(team: TeamRegistration) -> some View { + Button { + team.toggleSummonConfirmation() + do { + try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team) + } catch { + Logger.error(error) + } + } label: { + if team.didConfirmSummon() { + Label("Confirmation reçue", systemImage: "checkmark.circle.fill").foregroundStyle(.green) + } else { + Label("Confirmation reçue", systemImage: "circle").foregroundStyle(.logoRed) + } + } + Divider() + + Button(role: .destructive) { + team.callDate = nil + do { + try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team) + } catch { + Logger.error(error) + } + } label: { + Text("Effacer la date de convocation") + } + + } } diff --git a/PadelClub/Views/Navigation/Umpire/UmpireView.swift b/PadelClub/Views/Navigation/Umpire/UmpireView.swift index 945d2d7..ac79547 100644 --- a/PadelClub/Views/Navigation/Umpire/UmpireView.swift +++ b/PadelClub/Views/Navigation/Umpire/UmpireView.swift @@ -56,7 +56,7 @@ struct UmpireView: View { Section { if let currentPlayerData { //todo palmares - ImportedPlayerView(player: currentPlayerData) + ImportedPlayerView(player: currentPlayerData, showProgression: true) // NavigationLink { // // } label: { diff --git a/PadelClub/Views/Shared/ImportedPlayerView.swift b/PadelClub/Views/Shared/ImportedPlayerView.swift index 70b41e6..fd99bf8 100644 --- a/PadelClub/Views/Shared/ImportedPlayerView.swift +++ b/PadelClub/Views/Shared/ImportedPlayerView.swift @@ -11,7 +11,7 @@ struct ImportedPlayerView: View { let player: PlayerHolder var index: Int? = nil var showFemaleInMaleAssimilation: Bool = false - @State var showProgression: Bool = false + var showProgression: Bool = false var body: some View { VStack(alignment: .leading) { @@ -54,7 +54,7 @@ struct ImportedPlayerView: View { } } - if player.getProgression() != 0 { + if showProgression, player.getProgression() != 0 { HStack(alignment: .top, spacing: 2) { Text("(") Text(player.getProgression().formatted(.number.sign(strategy: .always()))) @@ -77,6 +77,7 @@ struct ImportedPlayerView: View { } } } + .lineLimit(1) if showFemaleInMaleAssimilation, let assimilatedAsMaleRank = player.getAssimilatedAsMaleRank() { HStack(alignment: .top, spacing: 2) { diff --git a/PadelClub/Views/Shared/SelectablePlayerListView.swift b/PadelClub/Views/Shared/SelectablePlayerListView.swift index b0f195d..b5d9a2d 100644 --- a/PadelClub/Views/Shared/SelectablePlayerListView.swift +++ b/PadelClub/Views/Shared/SelectablePlayerListView.swift @@ -364,7 +364,7 @@ struct MySearchView: View { let array = Array(searchViewModel.selectedPlayers) Section { ForEach(array) { player in - ImportedPlayerView(player: player, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation) + ImportedPlayerView(player: player, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation, showProgression: true) } .onDelete { indexSet in for index in indexSet { @@ -379,7 +379,7 @@ struct MySearchView: View { } else { Section { ForEach(players, id: \.self) { player in - ImportedPlayerView(player: player, index: nil, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation) + ImportedPlayerView(player: player, index: nil, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation, showProgression: true) } } header: { if players.isEmpty == false { @@ -398,7 +398,7 @@ struct MySearchView: View { Button { searchViewModel.selectedPlayers.insert(player) } label: { - ImportedPlayerView(player: player, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation) + ImportedPlayerView(player: player, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation, showProgression: true) } .buttonStyle(.plain) } @@ -412,7 +412,7 @@ struct MySearchView: View { Section { ForEach(players.indices, id: \.self) { index in let player = players[index] - ImportedPlayerView(player: player, index: searchViewModel.showIndex() ? (index + 1) : nil, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation) + ImportedPlayerView(player: player, index: searchViewModel.showIndex() ? (index + 1) : nil, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation, showProgression: true) } } header: { if players.isEmpty == false { @@ -429,13 +429,13 @@ struct MySearchView: View { Button { searchViewModel.selectedPlayers.insert(player) } label: { - ImportedPlayerView(player: player, index: searchViewModel.showIndex() ? (index + 1) : nil, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation) + ImportedPlayerView(player: player, index: searchViewModel.showIndex() ? (index + 1) : nil, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation, showProgression: true) .contentShape(Rectangle()) } .frame(maxWidth: .infinity) .buttonStyle(.plain) } else { - ImportedPlayerView(player: player, index: searchViewModel.showIndex() ? (index + 1) : nil, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation) + ImportedPlayerView(player: player, index: searchViewModel.showIndex() ? (index + 1) : nil, showFemaleInMaleAssimilation: searchViewModel.showFemaleInMaleAssimilation, showProgression: true) } } } header: { diff --git a/PadelClub/Views/Team/EditingTeamView.swift b/PadelClub/Views/Team/EditingTeamView.swift index 492822e..d3ac838 100644 --- a/PadelClub/Views/Team/EditingTeamView.swift +++ b/PadelClub/Views/Team/EditingTeamView.swift @@ -76,6 +76,22 @@ struct EditingTeamView: View { } label: { Text("Convocation") } + + Button { + team.toggleSummonConfirmation() + do { + try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team) + } catch { + Logger.error(error) + } + } label: { + if team.didConfirmSummon() { + Label("Confirmation reçue", systemImage: "checkmark.circle.fill").foregroundStyle(.green) + } else { + Label("Confirmation reçue", systemImage: "circle").foregroundStyle(.logoRed) + } + } + } else { Text("Cette équipe n'a pas été convoquée") } diff --git a/PadelClub/Views/Tournament/Screen/BroadcastView.swift b/PadelClub/Views/Tournament/Screen/BroadcastView.swift index 54648cc..836197d 100644 --- a/PadelClub/Views/Tournament/Screen/BroadcastView.swift +++ b/PadelClub/Views/Tournament/Screen/BroadcastView.swift @@ -108,9 +108,18 @@ struct BroadcastView: View { Section { Toggle(isOn: $tournament.isPrivate) { Text("Tournoi privé") + if (tournament.isPrivate && Guard.main.purchasedTransactions.isEmpty) { + Text("Vous devez disposer d'une offre pour rendre publique ce tournoi.") + .foregroundStyle(.logoRed) + } } + #if DEBUG + #else + .disabled((tournament.isPrivate && Guard.main.purchasedTransactions.isEmpty)) + #endif } footer: { - let footerString = "Le tournoi sera masqué sur le site [Padel Club](\(URLs.main.rawValue))" + let verb : String = tournament.isPrivate ? "est" : "sera" + let footerString = " Le tournoi \(verb) masqué sur le site [Padel Club](\(URLs.main.rawValue))" Text(.init(footerString)) }