multistore
Razmig Sarkissian 1 year ago
parent 568bd5ff02
commit cc4563b663
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 9
      PadelClub/Data/GroupStage.swift
  3. 18
      PadelClub/Data/Tournament.swift
  4. 14
      PadelClub/Views/Planning/PlanningSettingsView.swift
  5. 85
      PadelClub/Views/Round/RoundView.swift
  6. 9
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  7. 22
      PadelClub/Views/Tournament/Shared/TournamentCellView.swift

@ -1935,7 +1935,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 = 29; CURRENT_PROJECT_VERSION = 30;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1973,7 +1973,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 = 29; CURRENT_PROJECT_VERSION = 30;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -376,7 +376,8 @@ extension GroupStage: Selectable {
} }
func badgeValue() -> Int? { func badgeValue() -> Int? {
runningMatches(playedMatches: _matches()).count if teams().count < size { return nil }
return runningMatches(playedMatches: _matches()).count
} }
func badgeValueColor() -> Color? { func badgeValueColor() -> Color? {
@ -384,6 +385,10 @@ extension GroupStage: Selectable {
} }
func badgeImage() -> Badge? { func badgeImage() -> Badge? {
hasEnded() ? .checkmark : nil if teams().count < size {
return .xmark
} else {
return hasEnded() ? .checkmark : nil
}
} }
} }

@ -1523,7 +1523,6 @@ class Tournament : ModelObject, Storable {
groupStageMatchFormat = groupStageSmartMatchFormat() groupStageMatchFormat = groupStageSmartMatchFormat()
loserBracketMatchFormat = loserBracketSmartMatchFormat(1) loserBracketMatchFormat = loserBracketSmartMatchFormat(1)
matchFormat = roundSmartMatchFormat(1) matchFormat = roundSmartMatchFormat(1)
} }
} }
@ -1538,7 +1537,8 @@ class Tournament : ModelObject, Storable {
func loserBracketSmartMatchFormat(_ roundIndex: Int) -> MatchFormat { func loserBracketSmartMatchFormat(_ roundIndex: Int) -> MatchFormat {
let format = tournamentLevel.federalFormatForLoserBracketRound(roundIndex) let format = tournamentLevel.federalFormatForLoserBracketRound(roundIndex)
if format.rank > loserBracketMatchFormat.rank { if tournamentLevel == .p25 { return .superTie }
if format.rank < loserBracketMatchFormat.rank {
return format return format
} else { } else {
return loserBracketMatchFormat return loserBracketMatchFormat
@ -1547,7 +1547,8 @@ class Tournament : ModelObject, Storable {
func groupStageSmartMatchFormat() -> MatchFormat { func groupStageSmartMatchFormat() -> MatchFormat {
let format = tournamentLevel.federalFormatForGroupStage() let format = tournamentLevel.federalFormatForGroupStage()
if format.rank > groupStageMatchFormat.rank { if tournamentLevel == .p25 { return .superTie }
if format.rank < groupStageMatchFormat.rank {
return format return format
} else { } else {
return groupStageMatchFormat return groupStageMatchFormat
@ -1563,7 +1564,8 @@ class Tournament : ModelObject, Storable {
func roundSmartMatchFormat(_ roundIndex: Int) -> MatchFormat { func roundSmartMatchFormat(_ roundIndex: Int) -> MatchFormat {
let format = tournamentLevel.federalFormatForBracketRound(roundIndex) let format = tournamentLevel.federalFormatForBracketRound(roundIndex)
if format.rank > matchFormat.rank { if tournamentLevel == .p25 { return .superTie }
if format.rank < matchFormat.rank {
return format return format
} else { } else {
return matchFormat return matchFormat
@ -1622,6 +1624,14 @@ class Tournament : ModelObject, Storable {
return final?.playedMatches().first?.winner() return final?.playedMatches().first?.winner()
} }
func getGroupStageChunkValue() -> Int {
if teamsPerGroupStage >= 2 {
return min(groupStageCount, courtCount / (teamsPerGroupStage / 2))
} else {
return 1
}
}
// MARK: - // MARK: -
func insertOnServer() throws { func insertOnServer() throws {

@ -22,10 +22,10 @@ struct PlanningSettingsView: View {
self.tournament = tournament self.tournament = tournament
if let matchScheduler = tournament.matchScheduler() { if let matchScheduler = tournament.matchScheduler() {
self.matchScheduler = matchScheduler self.matchScheduler = matchScheduler
self._groupStageChunkCount = State(wrappedValue: matchScheduler.groupStageChunkCount ?? 1) self._groupStageChunkCount = State(wrappedValue: matchScheduler.groupStageChunkCount ?? tournament.getGroupStageChunkValue())
} else { } else {
self.matchScheduler = MatchScheduler(tournament: tournament.id) self.matchScheduler = MatchScheduler(tournament: tournament.id)
self._groupStageChunkCount = State(wrappedValue: 1) self._groupStageChunkCount = State(wrappedValue: tournament.getGroupStageChunkValue())
} }
} }
@ -130,10 +130,14 @@ struct PlanningSettingsView: View {
Text("Des dates de démarrages ont été indiqué pour les manches et seront prises en compte.") Text("Des dates de démarrages ont été indiqué pour les manches et seront prises en compte.")
} }
RowButtonView("Horaire intelligent", role: .destructive) { RowButtonView("Horaire intelligent", role: .destructive) {
schedulingDone = false await MainActor.run {
schedulingDone = false
}
await _setupSchedule() await _setupSchedule()
_save() await MainActor.run {
schedulingDone = true _save()
schedulingDone = true
}
} }
} footer: { } footer: {
Text("Padel Club programmera tous les matchs de votre tournoi en fonction de différents paramètres, ") + Text("tout en tenant compte des horaires que vous avez fixé.").underline() Text("Padel Club programmera tous les matchs de votre tournoi en fonction de différents paramètres, ") + Text("tout en tenant compte des horaires que vous avez fixé.").underline()

@ -28,6 +28,7 @@ struct RoundView: View {
List { List {
let loserRounds = round.loserRounds() let loserRounds = round.loserRounds()
let availableSeeds = tournament.availableSeeds()
let availableQualifiedTeams = tournament.availableQualifiedTeams() let availableQualifiedTeams = tournament.availableQualifiedTeams()
let displayableMatches = round.displayableMatches().sorted(by: \.index) let displayableMatches = round.displayableMatches().sorted(by: \.index)
let spaceLeft = displayableMatches.filter({ $0.hasSpaceLeft() }) let spaceLeft = displayableMatches.filter({ $0.hasSpaceLeft() })
@ -76,46 +77,80 @@ struct RoundView: View {
if availableQualifiedTeams.isEmpty == false && spaceLeft.isEmpty == false { if availableQualifiedTeams.isEmpty == false && spaceLeft.isEmpty == false {
Section { Section {
ForEach(availableQualifiedTeams) { team in DisclosureGroup {
NavigationLink { ForEach(availableQualifiedTeams) { team in
SpinDrawView(drawees: [team], segments: spaceLeft) { results in NavigationLink {
Task { SpinDrawView(drawees: [team], segments: spaceLeft) { results in
results.forEach { drawResult in Task {
team.setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true) results.forEach { drawResult in
} team.setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true)
_save() }
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty { _save()
self.isEditingTournamentSeed.wrappedValue = false if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
} }
} }
} label: {
TeamRowView(team: team, displayCallDate: false)
} }
} label: {
TeamRowView(team: team, displayCallDate: false)
} }
} label: {
Text("Qualifié\(availableQualifiedTeams.count.pluralSuffix) à placer").badge(availableQualifiedTeams.count)
} }
} header: { } header: {
Text("Tirage au sort visuel d'un qualifié").font(.subheadline) Text("Tirage au sort visuel d'un qualifié").font(.subheadline)
} }
} }
if tournament.availableSeeds().isEmpty == false && seedSpaceLeft.isEmpty == false { if availableSeeds.isEmpty == false && seedSpaceLeft.isEmpty == false {
Section { Section {
ForEach(tournament.availableSeeds()) { team in DisclosureGroup {
NavigationLink { ForEach(availableSeeds) { team in
SpinDrawView(drawees: [team], segments: seedSpaceLeft) { results in NavigationLink {
Task { SpinDrawView(drawees: [team], segments: seedSpaceLeft) { results in
results.forEach { drawResult in Task {
team.setSeedPosition(inSpot: seedSpaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: false) results.forEach { drawResult in
team.setSeedPosition(inSpot: seedSpaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: false)
}
_save()
if availableSeeds.isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
} }
_save() }
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty { } label: {
self.isEditingTournamentSeed.wrappedValue = false TeamRowView(team: team, displayCallDate: false)
}
}
} label: {
Text("Tête\(availableSeeds.count.pluralSuffix) de série à placer").badge(availableSeeds.count)
}
} header: {
Text("Tirage au sort visuel d'une tête de série").font(.subheadline)
}
} else if availableSeeds.isEmpty == false && spaceLeft.isEmpty == false {
Section {
DisclosureGroup {
ForEach(availableSeeds) { team in
NavigationLink {
SpinDrawView(drawees: [team], segments: spaceLeft) { results in
Task {
results.forEach { drawResult in
team.setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: false)
}
_save()
if availableSeeds.isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
} }
} }
} label: {
TeamRowView(team: team, displayCallDate: false)
} }
} label: {
TeamRowView(team: team, displayCallDate: false)
} }
} label: {
Text("Tête\(availableSeeds.count.pluralSuffix) de série à placer").badge(availableSeeds.count)
} }
} header: { } header: {
Text("Tirage au sort visuel d'une tête de série").font(.subheadline) Text("Tirage au sort visuel d'une tête de série").font(.subheadline)

@ -147,7 +147,16 @@ struct InscriptionManagerView: View {
if self.tournament.shouldVerifyBracket == false || self.tournament.shouldVerifyGroupStage == false { if self.tournament.shouldVerifyBracket == false || self.tournament.shouldVerifyGroupStage == false {
self.tournament.shouldVerifyBracket = true self.tournament.shouldVerifyBracket = true
self.tournament.shouldVerifyGroupStage = true self.tournament.shouldVerifyGroupStage = true
let waitingList = self.tournament.waitingListTeams(in: self.tournament.selectedSortedTeams())
waitingList.forEach { team in
if team.bracketPosition != nil || team.groupStagePosition != nil {
team.resetPositions()
}
}
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: waitingList)
try dataStore.tournaments.addOrUpdate(instance: tournament) try dataStore.tournaments.addOrUpdate(instance: tournament)
} catch { } catch {
Logger.error(error) Logger.error(error)

@ -27,6 +27,16 @@ struct TournamentCellView: View {
} }
} }
var teamCount: Int? {
if let tournament = tournament as? Tournament {
let hasStarted = tournament.inscriptionClosed() || tournament.hasStarted()
let count = hasStarted ? tournament.selectedSortedTeams().count : tournament.unsortedTeamsWithoutWO().count
return count
} else {
return nil
}
}
fileprivate func _spacing() -> CGFloat { fileprivate func _spacing() -> CGFloat {
self.displayStyle == .short ? 8.0 : 16.0 self.displayStyle == .short ? 8.0 : 16.0
} }
@ -78,10 +88,8 @@ struct TournamentCellView: View {
if let tournament = tournament as? Tournament, displayStyle == .wide { if let tournament = tournament as? Tournament, displayStyle == .wide {
if tournament.isCanceled { if tournament.isCanceled {
Text("Annulé").foregroundStyle(.logoRed) Text("Annulé").foregroundStyle(.logoRed)
} else { } else if let teamCount {
let hasStarted = tournament.inscriptionClosed() || tournament.hasStarted() Text(teamCount.formatted())
let count = hasStarted ? tournament.selectedSortedTeams().count : tournament.unsortedTeamsWithoutWO().count
Text(count.formatted())
} }
} else if let federalTournament = tournament as? FederalTournament { } else if let federalTournament = tournament as? FederalTournament {
Button { Button {
@ -101,10 +109,10 @@ struct TournamentCellView: View {
HStack { HStack {
Text(tournament.durationLabel()) Text(tournament.durationLabel())
Spacer() Spacer()
if let tournament = tournament as? Tournament, tournament.isCanceled == false { if let tournament = tournament as? Tournament, tournament.isCanceled == false, let teamCount {
let hasStarted = tournament.inscriptionClosed() || tournament.hasStarted() let hasStarted = tournament.inscriptionClosed() || tournament.hasStarted()
let word = hasStarted ? "équipes" : "inscriptions" let word = hasStarted ? "équipe" : "inscription"
Text(word) Text(word + teamCount.pluralSuffix)
} }
} }
Text(tournament.subtitleLabel()) Text(tournament.subtitleLabel())

Loading…
Cancel
Save