clean up inscription

multistore
Razmig Sarkissian 2 years ago
parent 455074c155
commit d34967df33
  1. 15
      PadelClub/Data/TeamRegistration.swift
  2. 15
      PadelClub/Data/Tournament.swift
  3. 8
      PadelClub/Manager/FileImportManager.swift
  4. 4
      PadelClub/Manager/PadelRule.swift
  5. 13
      PadelClub/ViewModel/TournamentSeedEditing.swift
  6. 4
      PadelClub/Views/Calling/CallView.swift
  7. 5
      PadelClub/Views/Calling/GroupStageCallingView.swift
  8. 2
      PadelClub/Views/Calling/SeedsCallingView.swift
  9. 4
      PadelClub/Views/Match/MatchRowView.swift
  10. 8
      PadelClub/Views/Round/LoserRoundsView.swift
  11. 4
      PadelClub/Views/Round/RoundSettingsView.swift
  12. 6
      PadelClub/Views/Round/RoundView.swift
  13. 6
      PadelClub/Views/Round/RoundsView.swift
  14. 4
      PadelClub/Views/Team/TeamDetailView.swift
  15. 2
      PadelClub/Views/Team/TeamRowView.swift
  16. 51
      PadelClub/Views/Tournament/FileImportView.swift
  17. 62
      PadelClub/Views/Tournament/Screen/Components/InscriptionInfoView.swift
  18. 9
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift

@ -283,6 +283,21 @@ class TeamRegistration: ModelObject, Storable {
return Store.main.findById(groupStage)
}
func initialRound() -> Round? {
guard let bracketPosition else { return nil }
let matchIndex = RoundRule.matchIndex(fromBracketPosition: bracketPosition)
let roundIndex = RoundRule.roundIndex(fromMatchIndex: bracketPosition / 2)
return Store.main.filter(isIncluded: { $0.tournament == tournament && $0.index == roundIndex }).first
}
func initialMatch() -> Match? {
guard let bracketPosition else { return nil }
guard let initialRoundObject = initialRound() else { return nil }
let matchIndex = RoundRule.matchIndex(fromBracketPosition: bracketPosition)
return Store.main.filter(isIncluded: { $0.round == initialRoundObject.id && $0.index == matchIndex }).first
}
func tournamentObject() -> Tournament? {
Store.main.findById(tournament)
}

@ -506,6 +506,11 @@ class Tournament : ModelObject, Storable {
return players.filter({ ($0.isImported() && $0.isValidLicenseNumber(year: licenseYearValidity) == false) || ($0.isImported() == false && ($0.licenceId == nil || $0.licenceId?.isLicenseNumber == false || $0.licenceId?.isEmpty == true)) })
}
func getStartDate(ofSeedIndex seedIndex: Int?) -> Date? {
guard let seedIndex else { return nil }
return selectedSortedTeams()[safe: seedIndex]?.callDate
}
func importTeams(_ teams: [FileImportManager.TeamHolder]) {
var teamsToImport = [TeamRegistration]()
teams.forEach { team in
@ -523,6 +528,16 @@ class Tournament : ModelObject, Storable {
}
func isStartDateIsDifferentThanCallDate(_ team: TeamRegistration) -> Bool {
guard let callDate = team.callDate else { return false }
if let groupStageStartDate = team.groupStageObject()?.startDate {
return Calendar.current.compare(callDate, to: groupStageStartDate, toGranularity: .minute) != ComparisonResult.orderedSame
} else if let roundMatchStartDate = team.initialMatch()?.startDate {
return Calendar.current.compare(callDate, to: roundMatchStartDate, toGranularity: .minute) != ComparisonResult.orderedSame
}
return false
}
func lockRegistration() {
closedRegistrationDate = Date()
let count = selectedSortedTeams().count

@ -80,6 +80,14 @@ class FileImportManager {
teams.firstIndex(where: { $0.id == id })
}
func formattedSeedIndex(index: Int?) -> String {
if let index {
return "#\(index + 1)"
} else {
return "###"
}
}
func formattedSeed(in teams: [TeamHolder]) -> String {
if let index = index(in: teams) {
return "#\(index + 1)"

@ -1419,6 +1419,10 @@ enum RoundRule {
return (1 << roundIndex) - 1
}
static func matchIndex(fromBracketPosition: Int) -> Int {
roundIndex(fromMatchIndex: fromBracketPosition / 2) + fromBracketPosition%2
}
static func roundIndex(fromMatchIndex matchIndex: Int) -> Int {
Int(log2(Double(matchIndex + 1)))
}

@ -8,22 +8,13 @@
import Foundation
import SwiftUI
// Create an environment key
private struct TournamentSeedEditing: EnvironmentKey {
static let defaultValue: Bool = false
static let defaultValue: Binding<Bool> = .constant(false)
}
// ## Introduce new value to EnvironmentValues
extension EnvironmentValues {
var isEditingTournamentSeed: Bool {
var isEditingTournamentSeed: Binding<Bool> {
get { self[TournamentSeedEditing.self] }
set { self[TournamentSeedEditing.self] = newValue }
}
}
// Add a dedicated modifier (Optional)
extension View {
func editTournamentSeed(_ value: Bool) -> some View {
environment(\.isEditingTournamentSeed, value)
}
}

@ -86,7 +86,11 @@ struct CallView: View {
let callWord = teams.allSatisfy({ $0.called() }) ? "Reconvoquer" : "Convoquer"
HStack {
if teams.count == 1 {
if let previousCallDate = teams.first?.callDate, Calendar.current.compare(previousCallDate, to: callDate, toGranularity: .minute) != .orderedSame {
Text("Reconvoquer " + callDate.localizedDate() + " par")
} else {
Text(callWord + " cette paire par")
}
} else {
Text(callWord + " ces \(teams.count) paires par")
}

@ -19,7 +19,7 @@ struct GroupStageCallingView: View {
ForEach(groupStages) { groupStage in
let seeds = groupStage.teams()
let callSeeds = seeds.filter({ $0.callDate != nil })
let callSeeds = seeds.filter({ tournament.isStartDateIsDifferentThanCallDate($0) == false })
if seeds.isEmpty == false {
Section {
@ -51,8 +51,9 @@ struct GroupStageCallingView: View {
ForEach(keys, id: \.self) { key in
if let _groupStages = times[key], _groupStages.count > 1 {
let teams = _groupStages.flatMap { $0.teams() }
let callSeeds = teams.filter({ tournament.isStartDateIsDifferentThanCallDate($0) == false })
Section {
CallView.CallStatusView(count: teams.filter({ $0.callDate != nil }).count, total: teams.count, startDate: key)
CallView.CallStatusView(count: callSeeds.count, total: teams.count, startDate: key)
} header: {
Text(groupStages.map { $0.groupStageTitle() }.joined(separator: ", "))
} footer: {

@ -15,7 +15,7 @@ struct SeedsCallingView: View {
List {
ForEach(tournament.rounds()) { round in
let seeds = round.seeds()
let callSeeds = seeds.filter({ $0.callDate != nil })
let callSeeds = seeds.filter({ tournament.isStartDateIsDifferentThanCallDate($0) == false })
if seeds.isEmpty == false {
Section {
NavigationLink {

@ -10,11 +10,11 @@ import SwiftUI
struct MatchRowView: View {
var match: Match
let matchViewStyle: MatchViewStyle
@Environment(\.editMode) private var editMode
@Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
@ViewBuilder
var body: some View {
if editMode?.wrappedValue.isEditing == true && match.isGroupStage() == false && match.isLoserBracket == false {
if isEditingTournamentSeed.wrappedValue == true && match.isGroupStage() == false && match.isLoserBracket == false {
MatchSetupView(match: match)
} else {
NavigationLink {

@ -40,7 +40,7 @@ struct LoserRoundsView: View {
struct LoserRoundView: View {
@EnvironmentObject var dataStore: DataStore
let loserRounds: [Round]
@Environment(\.editMode) private var editMode
@Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
private func _roundDisabled() -> Bool {
loserRounds.allSatisfy({ $0.isDisabled() })
@ -48,7 +48,7 @@ struct LoserRoundView: View {
var body: some View {
List {
if editMode?.wrappedValue.isEditing == true {
if isEditingTournamentSeed.wrappedValue == true {
_editingView()
}
@ -73,7 +73,9 @@ struct LoserRoundView: View {
}
.headerProminence(.increased)
.toolbar {
EditButton()
Button(isEditingTournamentSeed.wrappedValue == true ? "Valider" : "Modifier") {
isEditingTournamentSeed.wrappedValue.toggle()
}
}
}

@ -9,7 +9,7 @@ import SwiftUI
struct RoundSettingsView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(\.editMode) private var editMode
@Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
@Environment(Tournament.self) var tournament: Tournament
var body: some View {
@ -21,7 +21,7 @@ struct RoundSettingsView: View {
tournament.allRounds().forEach({ round in
round.enableRound()
})
editMode?.wrappedValue = .active
self.isEditingTournamentSeed.wrappedValue = true
}
}

@ -8,7 +8,7 @@
import SwiftUI
struct RoundView: View {
@Environment(\.editMode) private var editMode
@Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
@Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var dataStore: DataStore
@ -17,7 +17,7 @@ struct RoundView: View {
var body: some View {
List {
if editMode?.wrappedValue.isEditing == false {
if isEditingTournamentSeed.wrappedValue == false {
let loserRounds = round.loserRounds()
if loserRounds.isEmpty == false, let first = loserRounds.first(where: { $0.isDisabled() == false }) {
Section {
@ -37,7 +37,7 @@ struct RoundView: View {
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.seeds())
if tournament.availableSeeds().isEmpty {
editMode?.wrappedValue = .inactive
self.isEditingTournamentSeed.wrappedValue = false
}
}
}

@ -10,13 +10,13 @@ import SwiftUI
struct RoundsView: View {
var tournament: Tournament
@State private var selectedRound: Round?
@State var editMode: EditMode = .inactive
@State private var isEditingTournamentSeed = false
init(tournament: Tournament) {
self.tournament = tournament
_selectedRound = State(wrappedValue: tournament.getActiveRound())
if tournament.availableSeeds().isEmpty == false {
_editMode = .init(wrappedValue: .active)
_isEditingTournamentSeed = State(wrappedValue: true)
}
}
@ -32,7 +32,7 @@ struct RoundsView: View {
.navigationTitle(selectedRound.roundTitle())
}
}
.environment(\.editMode, $editMode)
.environment(\.isEditingTournamentSeed, $isEditingTournamentSeed)
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
}

@ -16,10 +16,14 @@ struct TeamDetailView: View {
Text("Aucun joueur, espace réservé")
} else {
ForEach(team.players()) { player in
NavigationLink {
Text("Hello wolrd")
} label: {
PlayerView(player: player)
}
}
}
}
}
#Preview {

@ -31,7 +31,7 @@ struct TeamRowView: View {
}
} label: {
Text(team.teamLabel(.short))
if let callDate = team.callDate {
if let callDate = team.callDate, displayCallDate {
Text("Déjà convoquée \(callDate.localizedDate())")
.foregroundStyle(.red)
.italic()

@ -141,29 +141,16 @@ struct FileImportView: View {
}
}
Section {
ForEach(_filteredTeams) { team in
LabeledContent {
HStack {
if let previousTeam = team.previousTeam {
Text(previousTeam.formattedSeed(in: previousTeams))
Image(systemName: "arrowshape.forward.fill")
}
Text(team.formattedSeed(in: _filteredTeams))
}
Text(_filteredTeams.count.formatted())
} label: {
VStack(alignment: .leading) {
Text(team.playerOne.playerLabel())
Text(team.playerTwo.playerLabel())
}
}
}
} header: {
HStack {
Text("Équipe\(_filteredTeams.count.pluralSuffix) \(tournament.tournamentCategory.importingRawValue) détectée\(_filteredTeams.count.pluralSuffix)")
Spacer()
Text(_filteredTeams.count.formatted())
}
}
ForEach(_filteredTeams) { team in
_teamView(team: team, inTeams: _filteredTeams, previousTeams: previousTeams)
}
}
}
.onAppear {
@ -273,6 +260,34 @@ struct FileImportView: View {
}
}
@ViewBuilder
private func _teamView(team: FileImportManager.TeamHolder, inTeams teams: [FileImportManager.TeamHolder], previousTeams: [TeamRegistration]) -> some View {
let newIndex = team.index(in: teams)
Section {
HStack {
VStack(alignment: .leading) {
Text(team.playerOne.playerLabel())
Text(team.playerTwo.playerLabel())
}
Spacer()
HStack {
if let previousTeam = team.previousTeam {
Text(previousTeam.formattedSeed(in: previousTeams))
Image(systemName: "arrowshape.forward.fill")
}
Text(team.formattedSeedIndex(index: newIndex))
}
}
if let callDate = team.previousTeam?.callDate, let newDate = tournament.getStartDate(ofSeedIndex: newIndex), callDate != newDate {
Text("Attention, cette paire a déjà été convoquée à \(callDate.localizedDate())")
.foregroundStyle(.red)
.italic()
.font(.caption)
}
}
}
private func _save() {
try? dataStore.tournaments.addOrUpdate(instance: tournament)
}

@ -10,14 +10,21 @@ import SwiftUI
struct InscriptionInfoView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament
@State private var duplicates = [PlayerRegistration]()
@State private var problematicPlayers = [PlayerRegistration]()
@State private var inadequatePlayers = [PlayerRegistration]()
@State private var playersWithoutValidLicense = [PlayerRegistration]()
@State private var entriesFromBeachPadel = [TeamRegistration]()
@State private var playersMissing = [TeamRegistration]()
@State private var waitingList = [TeamRegistration]()
@State private var selectedTeams = [TeamRegistration]()
var players : [PlayerRegistration] { tournament.unsortedPlayers() }
var selectedTeams : [TeamRegistration] { tournament.selectedSortedTeams() }
var callDateIssue : [TeamRegistration] {
selectedTeams.filter { tournament.isStartDateIsDifferentThanCallDate($0) }
}
var waitingList : [TeamRegistration] { tournament.waitingListTeams(in: selectedTeams) }
var duplicates : [PlayerRegistration] { tournament.duplicates(in: players) }
var problematicPlayers : [PlayerRegistration] { players.filter({ $0.sex == -1 }) }
var inadequatePlayers : [PlayerRegistration] { tournament.inadequatePlayers(in: players) }
var playersWithoutValidLicense : [PlayerRegistration] { tournament.playersWithoutValidLicense(in: players) }
var entriesFromBeachPadel : [TeamRegistration] { tournament.unsortedTeams().filter({ $0.isImported() }) }
var playersMissing : [TeamRegistration] { selectedTeams.filter({ $0.unsortedPlayers().count < 2 }) }
var body: some View {
List {
@ -47,6 +54,30 @@ struct InscriptionInfoView: View {
.listRowView(color: .green)
}
Section {
DisclosureGroup {
ForEach(callDateIssue) { team in
CallView.TeamView(team: team)
if let groupStage = team.groupStageObject(), let callDate = groupStage.startDate {
CallView(teams: [team], callDate: callDate, matchFormat: groupStage.matchFormat, roundLabel: "poule")
} else if let initialRound = team.initialRound(),
let initialMatch = team.initialMatch(),
let callDate = initialMatch.startDate {
CallView(teams: [team], callDate: callDate, matchFormat: initialMatch.matchFormat, roundLabel: initialRound.roundTitle())
}
}
} label: {
LabeledContent {
Text(callDateIssue.count.formatted())
} label: {
Text("Erreur de convocation")
}
}
.listRowView(color: .brown)
} footer: {
Text("L'horaire de la convocation est différente du match initial")
}
let waitingListInBracket = waitingList.filter({ $0.bracketPosition != nil })
let waitingListInGroupStage = waitingList.filter({ $0.groupStage != nil })
@ -166,21 +197,6 @@ struct InscriptionInfoView: View {
.navigationTitle("Synthèse")
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.onAppear {
_initData()
}
}
private func _initData() {
let players = tournament.unsortedPlayers()
selectedTeams = tournament.selectedSortedTeams()
waitingList = tournament.waitingListTeams(in: selectedTeams)
duplicates = tournament.duplicates(in: players)
problematicPlayers = players.filter({ $0.sex == -1 })
inadequatePlayers = tournament.inadequatePlayers(in: players)
playersWithoutValidLicense = tournament.playersWithoutValidLicense(in: players)
entriesFromBeachPadel = tournament.unsortedTeams().filter({ $0.isImported() })
playersMissing = selectedTeams.filter({ $0.unsortedPlayers().count < 2 })
}
}

@ -739,7 +739,7 @@ struct InscriptionManagerView: View {
private func _teamFooterView(_ team: TeamRegistration) -> some View {
HStack {
if let formattedRegistrationDate = team.formattedInscriptionDate() {
Text(formattedRegistrationDate).font(.caption).foregroundStyle(.secondary)
Text(formattedRegistrationDate).foregroundStyle(.secondary)
}
Spacer()
_teamMenuOptionView(team)
@ -748,7 +748,7 @@ struct InscriptionManagerView: View {
private func _teamMenuOptionView(_ team: TeamRegistration) -> some View {
Menu {
Section {
Button("Éditer les joueurs") {
Button("Modifier l'équipe") {
editedTeam = team
team.unsortedPlayers().forEach { player in
createdPlayers.insert(player)
@ -799,12 +799,11 @@ struct InscriptionManagerView: View {
} label: {
LabelDelete()
}
} header: {
Text(team.teamLabel(.short))
// } header: {
// Text(team.teamLabel(.short))
}
} label: {
LabelOptions().labelStyle(.titleOnly)
.font(.caption)
}
}

Loading…
Cancel
Save