From 860eab9b76e10164913fa40676875102fdac78d5 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Wed, 15 May 2024 22:52:41 +0200 Subject: [PATCH 1/4] fix more stuff --- PadelClub/Data/GroupStage.swift | 2 +- PadelClub/Data/Match.swift | 9 +- PadelClub/Data/MatchScheduler.swift | 30 +++- PadelClub/Data/Round.swift | 6 +- PadelClub/Data/Tournament.swift | 65 +++++++-- PadelClub/Utils/URLs.swift | 2 +- PadelClub/Views/Club/ClubDetailView.swift | 42 ++++-- PadelClub/Views/Club/CourtView.swift | 1 + .../Views/Planning/PlanningSettingsView.swift | 21 ++- PadelClub/Views/Round/RoundSettingsView.swift | 2 +- PadelClub/Views/Round/RoundView.swift | 28 ++-- .../Tournament/Screen/BroadcastView.swift | 132 +++++++++++++----- PadelClubTests/ServerDataTests.swift | 8 +- 13 files changed, 265 insertions(+), 83 deletions(-) diff --git a/PadelClub/Data/GroupStage.swift b/PadelClub/Data/GroupStage.swift index 50c361d..de2babd 100644 --- a/PadelClub/Data/GroupStage.swift +++ b/PadelClub/Data/GroupStage.swift @@ -79,7 +79,7 @@ class GroupStage: ModelObject, Storable { var _matches = [Match]() for i in 0..<_numberOfMatchesToBuild() { - let newMatch = Match(groupStage: id, index: i, matchFormat: matchFormat) + let newMatch = Match(groupStage: id, index: i, matchFormat: matchFormat, name: localizedMatchUpLabel(for: i)) _matches.append(newMatch) } diff --git a/PadelClub/Data/Match.swift b/PadelClub/Data/Match.swift index 4fd7b0b..ab0c4a3 100644 --- a/PadelClub/Data/Match.swift +++ b/PadelClub/Data/Match.swift @@ -12,7 +12,12 @@ import LeStorage class Match: ModelObject, Storable { static func resourceName() -> String { "matches" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - + + static func setServerTitle(upperRound: Round, matchIndex: Int) -> String { + if upperRound.index == 0 { return upperRound.roundTitle() } + return upperRound.roundTitle() + " #" + (matchIndex + 1).formatted() + } + var byeState: Bool = false var id: String = Store.randomId() @@ -27,7 +32,7 @@ class Match: ModelObject, Storable { var winningTeamId: String? var losingTeamId: String? //var broadcasted: Bool - private var name: String? + var name: String? //var order: Int var disabled: Bool = false private(set) var courtIndex: Int? diff --git a/PadelClub/Data/MatchScheduler.swift b/PadelClub/Data/MatchScheduler.swift index 801a988..023972e 100644 --- a/PadelClub/Data/MatchScheduler.swift +++ b/PadelClub/Data/MatchScheduler.swift @@ -88,7 +88,35 @@ class MatchScheduler : ModelObject, Storable { }) var lastDate : Date = tournament.startDate - groupStages.chunked(into: groupStageCourtCount).forEach { groups in + let times = Set(groupStages.compactMap { $0.startDate }).sorted() + + if let first = times.first { + if first.isEarlierThan(tournament.startDate) { + tournament.startDate = first + try? DataStore.shared.tournaments.addOrUpdate(instance: tournament) + } + } + + times.forEach({ time in + lastDate = time + let groups = groupStages.filter({ $0.startDate == time }) + let dispatch = groupStageDispatcher(numberOfCourtsAvailablePerRotation: numberOfCourtsAvailablePerRotation, groupStages: groups, startingDate: lastDate) + + dispatch.timedMatches.forEach { matchSchedule in + if let match = matches.first(where: { $0.id == matchSchedule.matchID }) { + let estimatedDuration = match.matchFormat.getEstimatedDuration(tournament.additionalEstimationDuration) + let timeIntervalToAdd = (Double(matchSchedule.rotationIndex)) * Double(estimatedDuration) * 60 + if let startDate = match.groupStageObject?.startDate { + let matchStartDate = startDate.addingTimeInterval(timeIntervalToAdd) + match.startDate = matchStartDate + lastDate = matchStartDate.addingTimeInterval(Double(estimatedDuration) * 60) + } + match.setCourt(matchSchedule.courtIndex) + } + } + }) + + groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: groupStageCourtCount).forEach { groups in groups.forEach({ $0.startDate = lastDate }) try? DataStore.shared.groupStages.addOrUpdate(contentOfs: groups) diff --git a/PadelClub/Data/Round.swift b/PadelClub/Data/Round.swift index f5b38e8..8b9da7a 100644 --- a/PadelClub/Data/Round.swift +++ b/PadelClub/Data/Round.swift @@ -431,12 +431,8 @@ class Round: ModelObject, Storable { let matches = (0.. Date { + startDate + } + + func areTeamsPublished() -> Bool { + Date() >= startDate + } + + func publishedGroupStagesDate() -> Date? { + if let first = groupStages().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() { + if first.isEarlierThan(startDate) { + return startDate + } else { + return first + } + } else { + return nil + } + } + + func areGroupStagesPublished() -> Bool { + if let publishedGroupStagesDate = publishedGroupStagesDate() { + return Date() >= publishedGroupStagesDate + } else { + return false + } + } + + func publishedBracketsDate() -> Date? { + if let first = rounds().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() { + if first.isEarlierThan(startDate) { + return startDate + } else { + return first + } + } else { + return nil + } + } + + func areBracketsPublished() -> Bool { + if let publishedBracketsDate = publishedBracketsDate() { + return Date() >= publishedBracketsDate + } else { + return false + } + } + + func shareURL() -> URL? { return URLs.main.url.appending(path: "tournament/\(id)") } @@ -1096,7 +1145,7 @@ class Tournament : ModelObject, Storable { let matches = (0.. Date: Wed, 15 May 2024 23:15:13 +0200 Subject: [PATCH 2/4] fixes --- PadelClub/Data/Tournament.swift | 5 ++++- PadelClub/Views/Tournament/Screen/BroadcastView.swift | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index a7cbc57..dae330b 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -234,7 +234,10 @@ class Tournament : ModelObject, Storable { try container.encode(additionalEstimationDuration, forKey: ._additionalEstimationDuration) try container.encode(isDeleted, forKey: ._isDeleted) try self._encodeIsCanceled(container: &container) - + try container.encode(publishTeams, forKey: ._publishTeams) + try container.encode(publishSummons, forKey: ._publishSummons) + try container.encode(publishBrackets, forKey: ._publishBrackets) + try container.encode(publishGroupStages, forKey: ._publishGroupStages) } fileprivate func _encodePayment(container: inout KeyedEncodingContainer) throws { diff --git a/PadelClub/Views/Tournament/Screen/BroadcastView.swift b/PadelClub/Views/Tournament/Screen/BroadcastView.swift index 74f33b2..0e9e3f5 100644 --- a/PadelClub/Views/Tournament/Screen/BroadcastView.swift +++ b/PadelClub/Views/Tournament/Screen/BroadcastView.swift @@ -57,7 +57,7 @@ struct BroadcastView: View { } header: { Text("Liste des équipes") } footer: { - if tournament.publishedTeamsDate() < Date() { + if Date() < tournament.publishedTeamsDate() { FooterButtonView(tournament.publishTeams ? "masquer sur le site" : "publier maintenant") { tournament.publishTeams.toggle() } @@ -81,7 +81,7 @@ struct BroadcastView: View { } header: { Text("Convocations") } footer: { - if tournament.publishedTeamsDate() < Date() { + if Date() < tournament.publishedTeamsDate() { FooterButtonView(tournament.publishSummons ? "masquer sur le site" : "publier maintenant") { tournament.publishSummons.toggle() } @@ -107,7 +107,7 @@ struct BroadcastView: View { } header: { Text("Poules") } footer: { - if publishedGroupStagesDate < Date() { + if Date() < publishedGroupStagesDate { FooterButtonView(tournament.publishGroupStages ? "masquer sur le site" : "publier maintenant") { tournament.publishGroupStages.toggle() } @@ -134,7 +134,7 @@ struct BroadcastView: View { } header: { Text("Tableau") } footer: { - if publishedBracketsDate < Date() { + if Date() < publishedBracketsDate{ FooterButtonView(tournament.publishBrackets ? "masquer sur le site" : "publier maintenant") { tournament.publishBrackets.toggle() } From cf44ce13109344756ba4109a3fc3f5dccee2e845 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Wed, 15 May 2024 23:31:36 +0200 Subject: [PATCH 3/4] build 7 --- PadelClub.xcodeproj/project.pbxproj | 4 +- PadelClub/Data/Tournament.swift | 10 ++++- .../Tournament/Screen/BroadcastView.swift | 44 ++++++++++++------- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index ab7dc72..9a82ca4 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -1830,7 +1830,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; @@ -1868,7 +1868,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index dae330b..ee99eac 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -303,9 +303,13 @@ class Tournament : ModelObject, Storable { } func areTeamsPublished() -> Bool { - Date() >= startDate + Date() >= startDate || publishTeams } - + + func areSummonsPublished() -> Bool { + Date() >= startDate || publishSummons + } + func publishedGroupStagesDate() -> Date? { if let first = groupStages().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() { if first.isEarlierThan(startDate) { @@ -319,6 +323,7 @@ class Tournament : ModelObject, Storable { } func areGroupStagesPublished() -> Bool { + if publishGroupStages { return true } if let publishedGroupStagesDate = publishedGroupStagesDate() { return Date() >= publishedGroupStagesDate } else { @@ -339,6 +344,7 @@ class Tournament : ModelObject, Storable { } func areBracketsPublished() -> Bool { + if publishBrackets { return true } if let publishedBracketsDate = publishedBracketsDate() { return Date() >= publishedBracketsDate } else { diff --git a/PadelClub/Views/Tournament/Screen/BroadcastView.swift b/PadelClub/Views/Tournament/Screen/BroadcastView.swift index 0e9e3f5..4a7499f 100644 --- a/PadelClub/Views/Tournament/Screen/BroadcastView.swift +++ b/PadelClub/Views/Tournament/Screen/BroadcastView.swift @@ -58,22 +58,25 @@ struct BroadcastView: View { Text("Liste des équipes") } footer: { if Date() < tournament.publishedTeamsDate() { - FooterButtonView(tournament.publishTeams ? "masquer sur le site" : "publier maintenant") { - tournament.publishTeams.toggle() + HStack { + Spacer() + FooterButtonView(tournament.publishTeams ? "masquer sur le site" : "publier maintenant") { + tournament.publishTeams.toggle() + } } } } Section { LabeledContent { - if tournament.areTeamsPublished() { + if tournament.areSummonsPublished() { Image(systemName:"checkmark").foregroundStyle(.green) } else { Text(tournament.publishedTeamsDate().formatted()) } } label: { - if tournament.areTeamsPublished() { - Text("Publiée") + if tournament.areSummonsPublished() { + Text("Publiées") } else { Text("Publication prévue") } @@ -82,8 +85,11 @@ struct BroadcastView: View { Text("Convocations") } footer: { if Date() < tournament.publishedTeamsDate() { - FooterButtonView(tournament.publishSummons ? "masquer sur le site" : "publier maintenant") { - tournament.publishSummons.toggle() + HStack { + Spacer() + FooterButtonView(tournament.publishSummons ? "masquer sur le site" : "publier maintenant") { + tournament.publishSummons.toggle() + } } } } @@ -99,7 +105,7 @@ struct BroadcastView: View { } } label: { if areGroupStagesPublished { - Text("Publiée") + Text("Publiées") } else { Text("Publication prévue") } @@ -108,8 +114,11 @@ struct BroadcastView: View { Text("Poules") } footer: { if Date() < publishedGroupStagesDate { - FooterButtonView(tournament.publishGroupStages ? "masquer sur le site" : "publier maintenant") { - tournament.publishGroupStages.toggle() + HStack { + Spacer() + FooterButtonView(tournament.publishGroupStages ? "masquer sur le site" : "publier maintenant") { + tournament.publishGroupStages.toggle() + } } } } @@ -126,7 +135,7 @@ struct BroadcastView: View { } } label: { if areBracketsPublished { - Text("Publiée") + Text("Publié") } else { Text("Publication prévue") } @@ -134,9 +143,12 @@ struct BroadcastView: View { } header: { Text("Tableau") } footer: { - if Date() < publishedBracketsDate{ - FooterButtonView(tournament.publishBrackets ? "masquer sur le site" : "publier maintenant") { - tournament.publishBrackets.toggle() + if Date() < publishedBracketsDate { + HStack { + Spacer() + FooterButtonView(tournament.publishBrackets ? "masquer sur le site" : "publier maintenant") { + tournament.publishBrackets.toggle() + } } } } @@ -149,7 +161,7 @@ struct BroadcastView: View { Text("Tournoi privé") } } footer: { - let footerString = "Le tournoi sera masqué sur le site [Padel Club]\(URLs.main.rawValue)" + let footerString = "Le tournoi sera masqué sur le site [Padel Club](\(URLs.main.rawValue))" Text(.init(footerString)) } @@ -204,7 +216,7 @@ struct BroadcastView: View { UIPasteboard.general.string = urlToShow } } - .onChange(of: tournament.isPrivate) { + .onChange(of: [tournament.isPrivate, tournament.publishTeams, tournament.publishSummons, tournament.publishBrackets, tournament.publishGroupStages]) { _save() } } From cf0259e50b86ecea60fe447e180985f35e65e2a4 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Thu, 16 May 2024 10:52:50 +0200 Subject: [PATCH 4/4] fix scheduler stuff add open organizer stuff --- PadelClub/Data/MatchScheduler.swift | 12 ++++++++---- PadelClub/Data/Tournament.swift | 9 ++------- PadelClub/ViewModel/NavigationViewModel.swift | 17 +++++++++++++++++ PadelClub/ViewModel/SearchViewModel.swift | 2 +- .../Navigation/Agenda/EventListView.swift | 2 +- .../Organizer/TournamentButtonView.swift | 18 ++++++------------ .../Organizer/TournamentOrganizerView.swift | 18 +++++++----------- .../Views/Planning/PlanningSettingsView.swift | 16 +++++++--------- PadelClubTests/ServerDataTests.swift | 3 +-- 9 files changed, 50 insertions(+), 47 deletions(-) diff --git a/PadelClub/Data/MatchScheduler.swift b/PadelClub/Data/MatchScheduler.swift index 023972e..28dacee 100644 --- a/PadelClub/Data/MatchScheduler.swift +++ b/PadelClub/Data/MatchScheduler.swift @@ -26,7 +26,8 @@ class MatchScheduler : ModelObject, Storable { var rotationDifferenceIsImportant: Bool var shouldHandleUpperRoundSlice: Bool var shouldEndRoundBeforeStartingNext: Bool - + var groupStageChunkCount: Int? + init(tournament: String, timeDifferenceLimit: Int = 5, loserBracketRotationDifference: Int = 0, @@ -36,7 +37,8 @@ class MatchScheduler : ModelObject, Storable { randomizeCourts: Bool = true, rotationDifferenceIsImportant: Bool = false, shouldHandleUpperRoundSlice: Bool = true, - shouldEndRoundBeforeStartingNext: Bool = true) { + shouldEndRoundBeforeStartingNext: Bool = true, + groupStageChunkCount: Int? = nil) { self.tournament = tournament self.timeDifferenceLimit = timeDifferenceLimit self.loserBracketRotationDifference = loserBracketRotationDifference @@ -47,6 +49,7 @@ class MatchScheduler : ModelObject, Storable { self.rotationDifferenceIsImportant = rotationDifferenceIsImportant self.shouldHandleUpperRoundSlice = shouldHandleUpperRoundSlice self.shouldEndRoundBeforeStartingNext = shouldEndRoundBeforeStartingNext + self.groupStageChunkCount = groupStageChunkCount } enum CodingKeys: String, CodingKey { @@ -61,6 +64,7 @@ class MatchScheduler : ModelObject, Storable { case _rotationDifferenceIsImportant = "rotationDifferenceIsImportant" case _shouldHandleUpperRoundSlice = "shouldHandleUpperRoundSlice" case _shouldEndRoundBeforeStartingNext = "shouldEndRoundBeforeStartingNext" + case _groupStageChunkCount = "groupStageChunkCount" } var courtsUnavailability: [DateInterval]? { @@ -77,7 +81,7 @@ class MatchScheduler : ModelObject, Storable { @discardableResult func updateGroupStageSchedule(tournament: Tournament) -> Date { - let groupStageCourtCount = tournament.groupStageCourtCount ?? 1 + let computedGroupStageChunkCount = groupStageChunkCount ?? 1 let groupStages = tournament.groupStages() let numberOfCourtsAvailablePerRotation: Int = tournament.courtCount @@ -116,7 +120,7 @@ class MatchScheduler : ModelObject, Storable { } }) - groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: groupStageCourtCount).forEach { groups in + groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: computedGroupStageChunkCount).forEach { groups in groups.forEach({ $0.startDate = lastDate }) try? DataStore.shared.groupStages.addOrUpdate(contentOfs: groups) diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index ee99eac..f39e06c 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -32,7 +32,6 @@ class Tournament : ModelObject, Storable { var federalCategory: TournamentCategory var federalLevelCategory: TournamentLevel var federalAgeCategory: FederalTournamentAge - var groupStageCourtCount: Int? var closedRegistrationDate: Date? var groupStageAdditionalQualified: Int var courtCount: Int = 2 @@ -74,7 +73,6 @@ class Tournament : ModelObject, Storable { case _federalCategory = "federalCategory" case _federalLevelCategory = "federalLevelCategory" case _federalAgeCategory = "federalAgeCategory" - case _groupStageCourtCount = "groupStageCourtCount" case _seedCount = "seedCount" case _closedRegistrationDate = "closedRegistrationDate" case _groupStageAdditionalQualified = "groupStageAdditionalQualified" @@ -94,7 +92,7 @@ class Tournament : ModelObject, Storable { case _publishBrackets = "publishBrackets" } - internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = false, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, groupStageCourtCount: Int? = nil, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishTeams: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false) { + internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = false, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishTeams: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false) { self.event = event self.name = name self.startDate = startDate @@ -113,7 +111,6 @@ class Tournament : ModelObject, Storable { self.federalCategory = federalCategory self.federalLevelCategory = federalLevelCategory self.federalAgeCategory = federalAgeCategory - self.groupStageCourtCount = groupStageCourtCount self.closedRegistrationDate = closedRegistrationDate self.groupStageAdditionalQualified = groupStageAdditionalQualified self.courtCount = courtCount @@ -150,7 +147,6 @@ class Tournament : ModelObject, Storable { federalCategory = try container.decode(TournamentCategory.self, forKey: ._federalCategory) federalLevelCategory = try container.decode(TournamentLevel.self, forKey: ._federalLevelCategory) federalAgeCategory = try container.decode(FederalTournamentAge.self, forKey: ._federalAgeCategory) - groupStageCourtCount = try container.decodeIfPresent(Int.self, forKey: ._groupStageCourtCount) closedRegistrationDate = try container.decodeIfPresent(Date.self, forKey: ._closedRegistrationDate) groupStageAdditionalQualified = try container.decode(Int.self, forKey: ._groupStageAdditionalQualified) courtCount = try container.decode(Int.self, forKey: ._courtCount) @@ -222,7 +218,6 @@ class Tournament : ModelObject, Storable { try container.encode(federalCategory, forKey: ._federalCategory) try container.encode(federalLevelCategory, forKey: ._federalLevelCategory) try container.encode(federalAgeCategory, forKey: ._federalAgeCategory) - try container.encodeIfPresent(groupStageCourtCount, forKey: ._groupStageCourtCount) try container.encodeIfPresent(closedRegistrationDate, forKey: ._closedRegistrationDate) try container.encode(groupStageAdditionalQualified, forKey: ._groupStageAdditionalQualified) try container.encode(courtCount, forKey: ._courtCount) @@ -1637,7 +1632,7 @@ extension Tournament { } static func fake() -> Tournament { - return Tournament(event: "Roland Garros", name: "Magic P100", startDate: Date(), endDate: Date(), creationDate: Date(), isPrivate: false, groupStageFormat: .nineGames, roundFormat: nil, loserRoundFormat: nil, groupStageSortMode: .snake, groupStageCount: 4, rankSourceDate: nil, dayDuration: 2, teamCount: 24, teamSorting: .rank, federalCategory: .men, federalLevelCategory: .p100, federalAgeCategory: .a45, groupStageCourtCount: nil, closedRegistrationDate: nil, groupStageAdditionalQualified: 0, courtCount: 4, prioritizeClubMembers: false, qualifiedPerGroupStage: 2, teamsPerGroupStage: 4, entryFee: nil) + return Tournament(event: "Roland Garros", name: "Magic P100", startDate: Date(), endDate: Date(), creationDate: Date(), isPrivate: false, groupStageFormat: .nineGames, roundFormat: nil, loserRoundFormat: nil, groupStageSortMode: .snake, groupStageCount: 4, rankSourceDate: nil, dayDuration: 2, teamCount: 24, teamSorting: .rank, federalCategory: .men, federalLevelCategory: .p100, federalAgeCategory: .a45, closedRegistrationDate: nil, groupStageAdditionalQualified: 0, courtCount: 4, prioritizeClubMembers: false, qualifiedPerGroupStage: 2, teamsPerGroupStage: 4, entryFee: nil) } } diff --git a/PadelClub/ViewModel/NavigationViewModel.swift b/PadelClub/ViewModel/NavigationViewModel.swift index dfe589c..722f686 100644 --- a/PadelClub/ViewModel/NavigationViewModel.swift +++ b/PadelClub/ViewModel/NavigationViewModel.swift @@ -16,4 +16,21 @@ class NavigationViewModel { var selectedTab: TabDestination? var agendaDestination: AgendaDestination? = .activity var tournament: Tournament? + var organizerTournament: Tournament? + + func isTournamentAlreadyOpenInOrganizer(_ tournament: Tournament) -> Bool { + organizerTournament?.id == tournament.id + } + + func closeTournamentFromOrganizer(_ tournament: Tournament) { + tournament.navigationPath.removeAll() + organizerTournament = nil + } + + func openTournamentInOrganizer(_ tournament: Tournament) { + organizerTournament = tournament + if selectedTab != .tournamentOrganizer { + selectedTab = .tournamentOrganizer + } + } } diff --git a/PadelClub/ViewModel/SearchViewModel.swift b/PadelClub/ViewModel/SearchViewModel.swift index dc5d794..cb9059d 100644 --- a/PadelClub/ViewModel/SearchViewModel.swift +++ b/PadelClub/ViewModel/SearchViewModel.swift @@ -69,7 +69,7 @@ class SearchViewModel: ObservableObject, Identifiable { } func codeClubs() -> [String] { - DataStore.shared.clubs.compactMap { $0.code } + DataStore.shared.user.clubsObjects().compactMap { $0.code } } func getCodeClub() -> String? { diff --git a/PadelClub/Views/Navigation/Agenda/EventListView.swift b/PadelClub/Views/Navigation/Agenda/EventListView.swift index 61942c7..3011b04 100644 --- a/PadelClub/Views/Navigation/Agenda/EventListView.swift +++ b/PadelClub/Views/Navigation/Agenda/EventListView.swift @@ -103,7 +103,7 @@ struct EventListView: View { } .contextMenu { Button { - + navigation.openTournamentInOrganizer(tournament) } label: { Label("Voir dans le gestionnaire", systemImage: "line.diagonal.arrow") } diff --git a/PadelClub/Views/Navigation/Organizer/TournamentButtonView.swift b/PadelClub/Views/Navigation/Organizer/TournamentButtonView.swift index ff48983..7d7a54b 100644 --- a/PadelClub/Views/Navigation/Organizer/TournamentButtonView.swift +++ b/PadelClub/Views/Navigation/Organizer/TournamentButtonView.swift @@ -8,21 +8,15 @@ import SwiftUI struct TournamentButtonView: View { + @Environment(NavigationViewModel.self) private var navigation let tournament: Tournament - @Binding var selectedId: String? - + var body: some View { Button { - if selectedId == tournament.id { - tournament.navigationPath.removeAll() - selectedId = nil -// if tournament.navigationPath.isEmpty { -// selectedId = nil -// } else { -// tournament.navigationPath.removeLast() -// } + if navigation.isTournamentAlreadyOpenInOrganizer(tournament) { + navigation.closeTournamentFromOrganizer(tournament) } else { - selectedId = tournament.id + navigation.openTournamentInOrganizer(tournament) } } label: { TournamentCellView(tournament: tournament, displayStyle: .short) @@ -34,7 +28,7 @@ struct TournamentButtonView: View { .fixedSize(horizontal: false, vertical: true) } .overlay(alignment: .top) { - if selectedId == tournament.id { + if navigation.isTournamentAlreadyOpenInOrganizer(tournament) { Image(systemName: "ellipsis") .offset(y: -10) } diff --git a/PadelClub/Views/Navigation/Organizer/TournamentOrganizerView.swift b/PadelClub/Views/Navigation/Organizer/TournamentOrganizerView.swift index 6c8f037..72f6afe 100644 --- a/PadelClub/Views/Navigation/Organizer/TournamentOrganizerView.swift +++ b/PadelClub/Views/Navigation/Organizer/TournamentOrganizerView.swift @@ -10,17 +10,13 @@ import LeStorage struct TournamentOrganizerView: View { @EnvironmentObject var dataStore: DataStore - @State private var selectedTournamentId: String? - + @Environment(NavigationViewModel.self) private var navigation + var body: some View { VStack(spacing: 0) { - ForEach(dataStore.tournaments) { tournament in - if tournament.id == selectedTournamentId { - OrganizedTournamentView(tournament: tournament) - } - } - - if selectedTournamentId == nil { + if let tournament = navigation.organizerTournament { + OrganizedTournamentView(tournament: tournament) + } else { NavigationStack { let userClubsEmpty = dataStore.user.clubs.isEmpty ContentUnavailableView( @@ -39,7 +35,7 @@ struct TournamentOrganizerView: View { ScrollView(.horizontal) { HStack { ForEach(dataStore.tournaments) { tournament in - TournamentButtonView(tournament: tournament, selectedId: $selectedTournamentId) + TournamentButtonView(tournament: tournament) } } .padding() @@ -48,7 +44,7 @@ struct TournamentOrganizerView: View { } } .onChange(of: Store.main.currentUserUUID) { - selectedTournamentId = nil + navigation.organizerTournament = nil } } } diff --git a/PadelClub/Views/Planning/PlanningSettingsView.swift b/PadelClub/Views/Planning/PlanningSettingsView.swift index d57f46a..fde3f8c 100644 --- a/PadelClub/Views/Planning/PlanningSettingsView.swift +++ b/PadelClub/Views/Planning/PlanningSettingsView.swift @@ -13,7 +13,7 @@ struct PlanningSettingsView: View { @Bindable var tournament: Tournament @Bindable var matchScheduler: MatchScheduler - @State private var groupStageCourtCount: Int + @State private var groupStageChunkCount: Int @State private var isScheduling: Bool = false @State private var schedulingDone: Bool = false @State private var showOptions: Bool = false @@ -22,10 +22,11 @@ struct PlanningSettingsView: View { self.tournament = tournament if let matchScheduler = tournament.matchScheduler() { self.matchScheduler = matchScheduler + self._groupStageChunkCount = State(wrappedValue: matchScheduler.groupStageChunkCount ?? 1) } else { self.matchScheduler = MatchScheduler(tournament: tournament.id) + self._groupStageChunkCount = State(wrappedValue: 1) } - self._groupStageCourtCount = State(wrappedValue: tournament.groupStageCourtCount ?? 1) } var body: some View { @@ -48,7 +49,7 @@ struct PlanningSettingsView: View { TournamentFieldsManagerView(localizedStringKey: "Terrains maximum", count: $tournament.courtCount) if tournament.groupStages().isEmpty == false { - TournamentFieldsManagerView(localizedStringKey: "Nombre de poule en même temps", count: $groupStageCourtCount, max: tournament.groupStageCount) + TournamentFieldsManagerView(localizedStringKey: "Nombre de poule en même temps", count: $groupStageChunkCount, max: tournament.groupStageCount) } if let event = tournament.eventObject() { @@ -73,6 +74,7 @@ struct PlanningSettingsView: View { RowButtonView("Horaire intelligent", role: .destructive) { schedulingDone = false await _setupSchedule() + _save() schedulingDone = true } } footer: { @@ -114,9 +116,8 @@ struct PlanningSettingsView: View { .deferredRendering(for: .seconds(2)) } } - .onChange(of: groupStageCourtCount) { - tournament.groupStageCourtCount = groupStageCourtCount - _save() + .onChange(of: groupStageChunkCount) { + matchScheduler.groupStageChunkCount = groupStageChunkCount } .onChange(of: tournament.startDate) { _save() @@ -124,9 +125,6 @@ struct PlanningSettingsView: View { .onChange(of: tournament.courtCount) { _save() } - .onChange(of: tournament.groupStageCourtCount) { - _save() - } .onChange(of: tournament.dayDuration) { _save() } diff --git a/PadelClubTests/ServerDataTests.swift b/PadelClubTests/ServerDataTests.swift index ed6b7f8..3fa68ca 100644 --- a/PadelClubTests/ServerDataTests.swift +++ b/PadelClubTests/ServerDataTests.swift @@ -96,7 +96,7 @@ final class ServerDataTests: XCTestCase { return } - let tournament = Tournament(event: eventId, name: "RG Homme", startDate: Date(), endDate: nil, creationDate: Date(), isPrivate: false, groupStageFormat: MatchFormat.megaTie, roundFormat: MatchFormat.nineGames, loserRoundFormat: MatchFormat.nineGamesDecisivePoint, groupStageSortMode: GroupStageOrderingMode.snake, groupStageCount: 2, rankSourceDate: Date(), dayDuration: 5, teamCount: 3, teamSorting: TeamSortingType.rank, federalCategory: TournamentCategory.mix, federalLevelCategory: TournamentLevel.p1000, federalAgeCategory: FederalTournamentAge.a45, groupStageCourtCount: 6, closedRegistrationDate: Date(), groupStageAdditionalQualified: 4, courtCount: 9, prioritizeClubMembers: true, qualifiedPerGroupStage: 1, teamsPerGroupStage: 2, entryFee: 30.0, additionalEstimationDuration: 5, isDeleted: true, publishTeams: true, publishSummons: true, publishGroupStages: true, publishBrackets: true) + let tournament = Tournament(event: eventId, name: "RG Homme", startDate: Date(), endDate: nil, creationDate: Date(), isPrivate: false, groupStageFormat: MatchFormat.megaTie, roundFormat: MatchFormat.nineGames, loserRoundFormat: MatchFormat.nineGamesDecisivePoint, groupStageSortMode: GroupStageOrderingMode.snake, groupStageCount: 2, rankSourceDate: Date(), dayDuration: 5, teamCount: 3, teamSorting: TeamSortingType.rank, federalCategory: TournamentCategory.mix, federalLevelCategory: TournamentLevel.p1000, federalAgeCategory: FederalTournamentAge.a45, closedRegistrationDate: Date(), groupStageAdditionalQualified: 4, courtCount: 9, prioritizeClubMembers: true, qualifiedPerGroupStage: 1, teamsPerGroupStage: 2, entryFee: 30.0, additionalEstimationDuration: 5, isDeleted: true, publishTeams: true, publishSummons: true, publishGroupStages: true, publishBrackets: true) let t = try await Store.main.service().post(tournament) assert(t.event == tournament.event) @@ -117,7 +117,6 @@ final class ServerDataTests: XCTestCase { assert(t.federalCategory == tournament.federalCategory) assert(t.federalLevelCategory == tournament.federalLevelCategory) assert(t.federalAgeCategory == tournament.federalAgeCategory) - assert(t.groupStageCourtCount == tournament.groupStageCourtCount) assert(t.closedRegistrationDate?.formatted() == tournament.closedRegistrationDate?.formatted()) assert(t.groupStageAdditionalQualified == tournament.groupStageAdditionalQualified) assert(t.courtCount == tournament.courtCount)