clean up text and summon stuff

multistore
Razmig Sarkissian 1 year ago
parent 11e3995a95
commit d3c658c615
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 17
      PadelClub/Data/Match.swift
  3. 8
      PadelClub/Data/TeamRegistration.swift
  4. 16
      PadelClub/Data/Tournament.swift
  5. 2
      PadelClub/Views/Calling/CallSettingsView.swift
  6. 4
      PadelClub/Views/Calling/CallView.swift
  7. 2
      PadelClub/Views/Club/Shared/ClubCourtSetupView.swift
  8. 8
      PadelClub/Views/Match/Components/MatchDateView.swift
  9. 43
      PadelClub/Views/Tournament/Screen/Components/TournamentClubSettingsView.swift
  10. 15
      PadelClub/Views/Tournament/Screen/TableStructureView.swift

@ -1919,7 +1919,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12; CURRENT_PROJECT_VERSION = 13;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1957,7 +1957,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12; CURRENT_PROJECT_VERSION = 13;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -148,6 +148,18 @@ class Match: ModelObject, Storable {
return scores return scores
} }
func cleanScheduleAndSave(_ targetStartDate: Date? = nil) {
startDate = targetStartDate
endDate = nil
followingMatch()?.cleanScheduleAndSave(nil)
_loserMatch()?.cleanScheduleAndSave(nil)
do {
try DataStore.shared.matches.addOrUpdate(instance: self)
} catch {
Logger.error(error)
}
}
func resetMatch() { func resetMatch() {
losingTeamId = nil losingTeamId = nil
winningTeamId = nil winningTeamId = nil
@ -289,6 +301,11 @@ class Match: ModelObject, Storable {
Store.main.filter(isIncluded: { $0.round == round && $0.index > index }).sorted(by: \.index).first Store.main.filter(isIncluded: { $0.round == round && $0.index > index }).sorted(by: \.index).first
} }
func followingMatch() -> Match? {
guard let nextRoundId = roundObject?.nextRound()?.id else { return nil }
return Store.main.filter(isIncluded: { $0.round == nextRoundId && $0.index == index / 2 }).first
}
func getDuration() -> Int { func getDuration() -> Int {
if let tournament = currentTournament() { if let tournament = currentTournament() {
matchFormat.getEstimatedDuration(tournament.additionalEstimationDuration) matchFormat.getEstimatedDuration(tournament.additionalEstimationDuration)

@ -64,6 +64,14 @@ class TeamRegistration: ModelObject, Storable {
bracketPosition = seedPosition bracketPosition = seedPosition
} }
func expectedSummonDate() -> Date? {
if let groupStageStartDate = groupStageObject()?.startDate {
return groupStageStartDate
} else if let roundMatchStartDate = initialMatch()?.startDate {
return roundMatchStartDate
}
return nil
}
var initialWeight: Int { var initialWeight: Int {
lockedWeight ?? weight lockedWeight ?? weight

@ -844,13 +844,9 @@ class Tournament : ModelObject, Storable {
} }
func isStartDateIsDifferentThanCallDate(_ team: TeamRegistration) -> Bool { func isStartDateIsDifferentThanCallDate(_ team: TeamRegistration) -> Bool {
guard let callDate = team.callDate else { return true } guard let summonDate = team.callDate else { return true }
if let groupStageStartDate = team.groupStageObject()?.startDate { guard let expectedSummonDate = team.expectedSummonDate() else { return true }
return Calendar.current.compare(callDate, to: groupStageStartDate, toGranularity: .minute) != ComparisonResult.orderedSame return Calendar.current.compare(summonDate, to: expectedSummonDate, toGranularity: .minute) != ComparisonResult.orderedSame
} else if let roundMatchStartDate = team.initialMatch()?.startDate {
return Calendar.current.compare(callDate, to: roundMatchStartDate, toGranularity: .minute) != ComparisonResult.orderedSame
}
return true
} }
func availableToStart(_ allMatches: [Match]) -> [Match] { func availableToStart(_ allMatches: [Match]) -> [Match] {
@ -1082,8 +1078,8 @@ class Tournament : ModelObject, Storable {
func callStatus() -> TournamentStatus { func callStatus() -> TournamentStatus {
let selectedSortedTeams = selectedSortedTeams() let selectedSortedTeams = selectedSortedTeams()
let called = selectedSortedTeams.filter{ $0.called() } let called = selectedSortedTeams.filter { isStartDateIsDifferentThanCallDate($0) == false }
let label = called.count.formatted() + " / " + selectedSortedTeams.count.formatted() + " paires convoquées" let label = called.count.formatted() + " / " + selectedSortedTeams.count.formatted() + " convoquées au bon horaire"
let completion = (Double(called.count) / Double(selectedSortedTeams.count)) let completion = (Double(called.count) / Double(selectedSortedTeams.count))
let completionLabel = completion.isNaN ? "" : completion.formatted(.percent.precision(.fractionLength(0))) let completionLabel = completion.isNaN ? "" : completion.formatted(.percent.precision(.fractionLength(0)))
return TournamentStatus(label: label, completion: completionLabel) return TournamentStatus(label: label, completion: completionLabel)
@ -1121,7 +1117,7 @@ class Tournament : ModelObject, Storable {
return [teamCount.formatted() + " équipes", groupStageLabel].compactMap({ $0 }).joined(separator: ", ") return [teamCount.formatted() + " équipes", groupStageLabel].compactMap({ $0 }).joined(separator: ", ")
} }
func buildStructure() { func deleteAndBuildEverything() {
deleteStructure() deleteStructure()
deleteGroupStages() deleteGroupStages()
buildGroupStages() buildGroupStages()

@ -43,7 +43,7 @@ struct CallSettingsView: View {
RowButtonView("Tout le monde a été convoqué", role: .destructive) { RowButtonView("Tout le monde a été convoqué", role: .destructive) {
let teams = tournament.unsortedTeams() let teams = tournament.unsortedTeams()
teams.forEach { team in teams.forEach { team in
team.callDate = Date() team.callDate = team.expectedSummonDate()
} }
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: teams) try? dataStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} }

@ -31,7 +31,7 @@ struct CallView: View {
Text(startDate.formatted(.dateTime.weekday().day(.twoDigits).month().year())) Text(startDate.formatted(.dateTime.weekday().day(.twoDigits).month().year()))
} }
Spacer() Spacer()
Text("paires convoquées") Text("convoquées au bon horaire")
} }
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(.secondary)
@ -130,7 +130,6 @@ struct CallView: View {
MessageComposeView(recipients: recipients, body: body) { result in MessageComposeView(recipients: recipients, body: body) { result in
switch result { switch result {
case .cancelled: case .cancelled:
_called(true)
break break
case .failed: case .failed:
self.sentError = .messageFailed self.sentError = .messageFailed
@ -153,7 +152,6 @@ struct CallView: View {
switch result { switch result {
case .cancelled, .saved: case .cancelled, .saved:
self.contactType = nil self.contactType = nil
_called(true)
case .failed: case .failed:
self.contactType = nil self.contactType = nil
self.sentError = .mailFailed self.sentError = .mailFailed

@ -17,7 +17,7 @@ struct ClubCourtSetupView: View {
@ViewBuilder @ViewBuilder
var body: some View { var body: some View {
Section { Section {
TournamentFieldsManagerView(localizedStringKey: "Terrains", count: $club.courtCount) TournamentFieldsManagerView(localizedStringKey: "Terrains du club", count: $club.courtCount)
.disabled(displayContext == .lockedForEditing) .disabled(displayContext == .lockedForEditing)
.onChange(of: club.courtCount) { .onChange(of: club.courtCount) {
if displayContext != .addition { if displayContext != .addition {

@ -46,15 +46,11 @@ struct MatchDateView: View {
let tournament = match.currentTournament() let tournament = match.currentTournament()
let estimatedDuration = tournament != nil ? match.matchFormat.getEstimatedDuration(tournament!.additionalEstimationDuration) : match.matchFormat.getEstimatedDuration() let estimatedDuration = tournament != nil ? match.matchFormat.getEstimatedDuration(tournament!.additionalEstimationDuration) : match.matchFormat.getEstimatedDuration()
Button("Décaler de \(estimatedDuration) minutes") { Button("Décaler de \(estimatedDuration) minutes") {
match.startDate = match.startDate?.addingTimeInterval(Double(estimatedDuration) * 60.0) match.cleanScheduleAndSave(match.startDate?.addingTimeInterval(Double(estimatedDuration) * 60.0))
match.endDate = nil
_save()
} }
} }
Button("Retirer l'horaire") { Button("Retirer l'horaire") {
match.startDate = nil match.cleanScheduleAndSave()
match.endDate = nil
_save()
} }
} }
} label: { } label: {

@ -49,6 +49,49 @@ struct TournamentClubSettingsView: View {
} }
} }
Section {
TournamentFieldsManagerView(localizedStringKey: "Terrains pour le tournoi", count: $tournament.courtCount)
if let event = tournament.eventObject() {
NavigationLink {
CourtAvailabilitySettingsView(event: event)
.environment(tournament)
} label: {
Text("Préciser la disponibilité des terrains")
}
}
} footer: {
if let club = tournament.club() {
if tournament.courtCount < club.courtCount {
let plural = tournament.courtCount.pluralSuffix
let verb = tournament.courtCount > 1 ? "seront" : "sera"
Text("En réduisant les terrains maximum, seul\(plural) le\(plural) \(tournament.courtCount) premier\(plural) terrain\(plural) \(verb) utilisé\(plural)") + Text(", par contre, si vous augmentez le nombre de terrains, vous pourrez plutôt préciser quel terrain n'est pas disponible.")
} else if tournament.courtCount > club.courtCount {
let isCreatedByUser = club.hasBeenCreated(by: dataStore.user.id)
Button {
do {
club.courtCount = tournament.courtCount
try dataStore.clubs.addOrUpdate(instance: club)
} catch {
Logger.error(error)
}
} label: {
if isCreatedByUser {
Text("Vous avez indiqué plus de terrains dans ce tournoi que dans le club.")
+ Text("Mettre à jour le club ?").underline().foregroundStyle(.master)
} else {
Label("Vous avez indiqué plus de terrains dans ce tournoi que dans le club.", systemImage: "exclamationmark.triangle.fill").foregroundStyle(.logoRed)
}
}
.buttonStyle(.plain)
.disabled(isCreatedByUser == false)
}
}
}
if let selectedClub { if let selectedClub {
ClubCourtSetupView(club: selectedClub, displayContext: selectedClub.hasBeenCreated(by: dataStore.user.id) ? .edition : .lockedForEditing, selectedCourt: $selectedCourt) ClubCourtSetupView(club: selectedClub, displayContext: selectedClub.hasBeenCreated(by: dataStore.user.id) ? .edition : .lockedForEditing, selectedCourt: $selectedCourt)
.onChange(of: selectedClub.courtCount) { .onChange(of: selectedClub.courtCount) {

@ -204,15 +204,15 @@ struct TableStructureView: View {
} }
} }
.disabled(updatedElements.isEmpty) .disabled(updatedElements.isEmpty)
.confirmationDialog("Mise à jour de la structure", isPresented: $presentRefreshStructureWarning, actions: { .confirmationDialog("Refaire la structure", isPresented: $presentRefreshStructureWarning, actions: {
if requirements.allSatisfy({ $0 == .groupStage }) { if requirements.allSatisfy({ $0 == .groupStage }) {
Button("Mettre à jour les poules") { Button("Refaire les poules") {
_save(rebuildEverything: false) _save(rebuildEverything: false)
} }
} }
Button("Tout mettre à jour", role: .destructive) { Button("Tout refaire", role: .destructive) {
_save(rebuildEverything: true) _save(rebuildEverything: true)
} }
@ -234,10 +234,6 @@ struct TableStructureView: View {
do { do {
let requirements = Set(updatedElements.compactMap { $0.requiresRebuilding }) let requirements = Set(updatedElements.compactMap { $0.requiresRebuilding })
if (rebuildEverything == false && requirements.contains(.all)) || rebuildEverything {
tournament.deleteStructure()
}
tournament.teamCount = teamCount tournament.teamCount = teamCount
tournament.groupStageCount = groupStageCount tournament.groupStageCount = groupStageCount
tournament.teamsPerGroupStage = teamsPerGroupStage tournament.teamsPerGroupStage = teamsPerGroupStage
@ -245,8 +241,9 @@ struct TableStructureView: View {
tournament.groupStageAdditionalQualified = groupStageAdditionalQualified tournament.groupStageAdditionalQualified = groupStageAdditionalQualified
if (rebuildEverything == false && requirements.contains(.all)) || rebuildEverything { if (rebuildEverything == false && requirements.contains(.all)) || rebuildEverything {
tournament.buildStructure() tournament.deleteAndBuildEverything()
} else if (rebuildEverything == false && requirements.contains(.groupStage)) { } else if (rebuildEverything == false && requirements.contains(.groupStage)) {
tournament.deleteGroupStages()
tournament.buildGroupStages() tournament.buildGroupStages()
} }
@ -342,7 +339,7 @@ extension TableStructureView {
var rebuildingRequirementMessage: String { var rebuildingRequirementMessage: String {
switch self { switch self {
case .groupStage: case .groupStage:
return "Si vous le souhaitez, seulement les poules seront mis à jour. Le tableau ne sera pas modifié." return "Si vous le souhaitez, seulement les poules seront refaites. Le tableau ne sera pas modifié."
case .all: case .all:
return "Tous les matchs seront re-générés. La position des têtes de série sera remise à zéro et les poules seront reconstruites." return "Tous les matchs seront re-générés. La position des têtes de série sera remise à zéro et les poules seront reconstruites."
} }

Loading…
Cancel
Save