diff --git a/PadelClub/Data/Match.swift b/PadelClub/Data/Match.swift index 0c25194..accc976 100644 --- a/PadelClub/Data/Match.swift +++ b/PadelClub/Data/Match.swift @@ -700,6 +700,8 @@ defer { print("teams.count != 2") return false } + guard hasEnded() == false else { return false } + guard hasStarted() == false else { return false } return teams.compactMap({ $0.team }).allSatisfy({ ((checkCanPlay && $0.canPlay()) || checkCanPlay == false) && isTeamPlaying($0, inMatches: matches) == false }) diff --git a/PadelClub/Utils/PadelRule.swift b/PadelClub/Utils/PadelRule.swift index 8caae56..bc7aee6 100644 --- a/PadelClub/Utils/PadelRule.swift +++ b/PadelClub/Utils/PadelRule.swift @@ -1262,9 +1262,9 @@ enum MatchFormat: Int, Hashable, Codable, CaseIterable { case .nineGamesDecisivePoint: return 40 case .megaTie: - return 30 + return 20 case .superTie: - return 25 + return 15 } } @@ -1349,7 +1349,7 @@ enum MatchFormat: Int, Hashable, Codable, CaseIterable { case .superTie: return "E" case .megaTie: - return "F" + return "F (non officiel)" case .twoSetsDecisivePoint: return "A2" case .twoSetsDecisivePointSuperTie: diff --git a/PadelClub/Views/Planning/PlanningSettingsView.swift b/PadelClub/Views/Planning/PlanningSettingsView.swift index 1246d65..c545c81 100644 --- a/PadelClub/Views/Planning/PlanningSettingsView.swift +++ b/PadelClub/Views/Planning/PlanningSettingsView.swift @@ -147,6 +147,13 @@ struct PlanningSettingsView: View { let allGroupStages = tournament.allGroupStages() let allRounds = tournament.allRounds() let matchesWithDate = allMatches.filter({ $0.startDate != nil }) + + let groupMatchesByDay = _groupMatchesByDay(matches: matchesWithDate) + + let countedSet = _matchCountPerDay(matchesByDay: groupMatchesByDay, tournament: tournament) + + _formatPerDayView(matchCountPerDay: countedSet) + let groupStagesWithDate = allGroupStages.filter({ $0.startDate != nil }) let roundsWithDate = allRounds.filter({ $0.startDate != nil }) if matchesWithDate.isEmpty == false || groupStagesWithDate.isEmpty == false || roundsWithDate.isEmpty == false { @@ -391,6 +398,135 @@ struct PlanningSettingsView: View { Logger.error(error) } } + + private func _groupMatchesByDay(matches: [Match]) -> [Date: [Match]] { + var matchesByDay = [Date: [Match]]() + let calendar = Calendar.current + + for match in matches { + // Extract day/month/year and create a date with only these components + let components = calendar.dateComponents([.year, .month, .day], from: match.computedStartDateForSorting) + let strippedDate = calendar.date(from: components)! + + // Group matches by the strippedDate (only day/month/year) + if matchesByDay[strippedDate] == nil { + matchesByDay[strippedDate] = [] + } + + let shouldIncludeMatch: Bool + switch match.matchType { + case .groupStage: + shouldIncludeMatch = !matchesByDay[strippedDate]!.filter { $0.groupStage != nil }.compactMap { $0.groupStage }.contains(match.groupStage!) + case .bracket: + shouldIncludeMatch = !matchesByDay[strippedDate]!.filter { $0.round != nil }.compactMap { $0.round }.contains(match.round!) + case .loserBracket: + shouldIncludeMatch = true + } + + if shouldIncludeMatch { + matchesByDay[strippedDate]!.append(match) + } + } + + return matchesByDay + } + + private func _matchCountPerDay(matchesByDay: [Date: [Match]], tournament: Tournament) -> [Date: NSCountedSet] { + let days = matchesByDay.keys + var matchCountPerDay = [Date: NSCountedSet]() + + for day in days { + if let matches = matchesByDay[day] { + var groupStageCount = 0 + let countedSet = NSCountedSet() + + for match in matches { + switch match.matchType { + case .groupStage: + if let groupStage = match.groupStageObject { + if groupStageCount < groupStage.size - 1 { + groupStageCount = groupStage.size - 1 + } + } + case .bracket: + countedSet.add(match.matchFormat) + case .loserBracket: + break + } + } + + if groupStageCount > 0 { + for _ in 0.. some View { + ForEach(Array(matchCountPerDay.keys).sorted(), id: \.self) { date in + if let countedSet = matchCountPerDay[date] { + Section { + let totalMatches = countedSet.totalCount() + ForEach(Array(countedSet).compactMap { $0 as? MatchFormat }, id: \.self) { matchFormat in + + let count = countedSet.count(for: matchFormat) + let totalForThisFormat = matchFormat.maximumMatchPerDay(for: totalMatches) + let error = count > totalForThisFormat + // Presenting LabeledContent for each match format and its count + LabeledContent { + Image(systemName: error ? "exclamationmark.triangle" : "checkmark") + .font(.title3) + .foregroundStyle(error ? .red : .green) + } label: { + let label = "\(count) match\(count.pluralSuffix) en \(matchFormat.format)" + let subtitle = "pas plus de " + totalForThisFormat.formatted() + " match\(totalForThisFormat.pluralSuffix) pour ce jour" + Text(label) + Text(subtitle) + } + } + } header: { + Text(date.formatted(.dateTime.weekday(.abbreviated).day(.twoDigits).month(.abbreviated))) + } + } + } + } + + // Helper function to format date to string (you can customize the format) + private func _formattedDate(_ date: Date) -> String { + let formatter = DateFormatter() + formatter.dateStyle = .medium // Set the date style (e.g., Oct 12, 2024) + return formatter.string(from: date) + } + + +} + +// Extension to compute the total count in an NSCountedSet +extension NSCountedSet { + func totalCount() -> Int { + var total = 0 + for element in self { + total += self.count(for: element) + } + return total + } } //#Preview { diff --git a/PadelClub/Views/Shared/MatchFormatPickerView.swift b/PadelClub/Views/Shared/MatchFormatPickerView.swift index 8004386..c50c3a7 100644 --- a/PadelClub/Views/Shared/MatchFormatPickerView.swift +++ b/PadelClub/Views/Shared/MatchFormatPickerView.swift @@ -17,7 +17,13 @@ struct MatchFormatPickerView: View { DisclosureGroup(isExpanded: $isExpanded) { Picker(selection: $matchFormat) { ForEach(MatchFormat.allCases, id: \.rawValue) { format in - Text(format.computedShortLabel).tag(format) + LabeledContent { + Text("~" + format.formattedEstimatedDuration(tournament.additionalEstimationDuration)) + } label: { + Text(format.format + " " + format.suffix) + Text(format.longLabel) + } + .tag(format) } } label: { }