fix pdf rules

add descritpion sharing system
fix slots setup
sync^2
Raz 8 months ago
parent 377f1eced4
commit 6ff21edba8
  1. 47
      PadelClub/Data/Tournament.swift
  2. 7
      PadelClub/Utils/URLs.swift
  3. 27
      PadelClub/Views/Match/MatchSetupView.swift
  4. 77
      PadelClub/Views/Navigation/Agenda/EventListView.swift
  5. 7
      PadelClub/Views/Navigation/Toolbox/ToolboxView.swift
  6. 21
      PadelClub/Views/Round/RoundView.swift

@ -702,17 +702,32 @@ defer {
return getRound(atRoundIndex: roundIndex)?.playedMatches().filter { $0.hasSpaceLeft() } ?? [] return getRound(atRoundIndex: roundIndex)?.playedMatches().filter { $0.hasSpaceLeft() } ?? []
} }
func availableSeedGroups() -> [SeedInterval] { func availableSeedGroups(includeAll: Bool = false) -> [SeedInterval] {
let seeds = seeds() let seeds = seeds()
var availableSeedGroup = Set<SeedInterval>() var availableSeedGroup = Set<SeedInterval>()
for (index, seed) in seeds.enumerated() { for (index, seed) in seeds.enumerated() {
if seed.isSeedable(), let seedGroup = seedGroup(for: index) { if seed.isSeedable(), let seedGroup = seedGroup(for: index) {
if includeAll {
if let chunks = seedGroup.chunks() {
chunksBy(in: chunks, availableSeedGroup: &availableSeedGroup)
}
} else {
availableSeedGroup.insert(seedGroup) availableSeedGroup.insert(seedGroup)
} }
} }
}
return availableSeedGroup.sorted(by: <) return availableSeedGroup.sorted(by: <)
} }
func chunksBy(in chunks: [SeedInterval], availableSeedGroup: inout Set<SeedInterval>) {
chunks.forEach { chunk in
availableSeedGroup.insert(chunk)
if let moreChunk = chunk.chunks() {
self.chunksBy(in: moreChunk, availableSeedGroup: &availableSeedGroup)
}
}
}
func seedGroup(for alreadySetupSeeds: Int) -> SeedInterval? { func seedGroup(for alreadySetupSeeds: Int) -> SeedInterval? {
switch alreadySetupSeeds { switch alreadySetupSeeds {
case 0...1: case 0...1:
@ -771,20 +786,24 @@ defer {
let maxSpots = max(availableSeedSpot.count, availableSeedOpponentSpot.count) let maxSpots = max(availableSeedSpot.count, availableSeedOpponentSpot.count)
if availableSeedGroup == SeedInterval(first: 3, last: 4), availableSeedSpot.count == 6 { if availableSeedGroup == SeedInterval(first: 3, last: 4), availableSeedSpot.count == 6 {
return availableSeedGroup return availableSeedGroup
} else if availableSeedGroup == SeedInterval(first: 5, last: 8), maxSpots == 6, availableSeeds.count == 2 {
return SeedInterval(first: 7, last: 12)
} }
if availableSeeds.count == availableSeedSpot.count && availableSeedGroup.count == availableSeeds.count { if availableSeeds.count == availableSeedSpot.count && availableSeedGroup.count == availableSeeds.count {
return availableSeedGroup return availableSeedGroup
} else if availableSeeds.count == availableSeedOpponentSpot.count && availableSeedGroup.count == availableSeedOpponentSpot.count { } else if availableSeeds.count == availableSeedOpponentSpot.count && availableSeedGroup.count == availableSeedOpponentSpot.count {
return availableSeedGroup return availableSeedGroup
} else if let chunks = availableSeedGroup.chunks() { } else if let chunks = availableSeedGroup.chunks() {
let seededTeamsCount = self.seededTeams().count
if let chunk = chunks.first(where: { seedInterval in if let chunk = chunks.first(where: { seedInterval in
seedInterval.first >= self.seededTeams().count return seedInterval.first == seededTeamsCount
}) { }) {
return seedGroupAvailable(atRoundIndex: roundIndex, availableSeedGroup: chunk) return seedGroupAvailable(atRoundIndex: roundIndex + 1, availableSeedGroup: chunk)
} else {
let seeds = seeds()
if let firstIndex = seeds.firstIndex(where: { $0.isSeedable() }) {
return SeedInterval(first: firstIndex + 1, last: firstIndex + maxSpots)
}
} }
} else if fullLeftSeeds.count % maxSpots == 0 { } else if fullLeftSeeds.count % maxSpots == 0 || fullLeftSeeds.count >= maxSpots {
let seeds = seeds() let seeds = seeds()
if let firstIndex = seeds.firstIndex(where: { $0.isSeedable() }) { if let firstIndex = seeds.firstIndex(where: { $0.isSeedable() }) {
return SeedInterval(first: firstIndex + 1, last: firstIndex + maxSpots) return SeedInterval(first: firstIndex + 1, last: firstIndex + maxSpots)
@ -820,14 +839,14 @@ defer {
for (index, seed) in availableSeeds.enumerated() { for (index, seed) in availableSeeds.enumerated() {
seed.setSeedPosition(inSpot: spots[index], slot: nil, opposingSeeding: false) seed.setSeedPosition(inSpot: spots[index], slot: nil, opposingSeeding: false)
} }
} else if seedGroup == SeedInterval(first: 5, last: 6), availableSeedSpot.count == 4 { // } else if seedGroup == SeedInterval(first: 5, last: 6), availableSeedSpot.count == 4 {
var spots = [Match]() // var spots = [Match]()
spots.append(availableSeedSpot[1]) // spots.append(availableSeedSpot[1])
spots.append(availableSeedSpot[2]) // spots.append(availableSeedSpot[2])
spots = spots.shuffled() // spots = spots.shuffled()
for (index, seed) in availableSeeds.enumerated() { // for (index, seed) in availableSeeds.enumerated() {
seed.setSeedPosition(inSpot: spots[index], slot: nil, opposingSeeding: false) // seed.setSeedPosition(inSpot: spots[index], slot: nil, opposingSeeding: false)
} // }
} else { } else {
if availableSeeds.count <= availableSeedSpot.count { if availableSeeds.count <= availableSeedSpot.count {
let spots = availableSeedSpot.shuffled() let spots = availableSeedSpot.shuffled()

@ -31,9 +31,10 @@ enum URLs: String, Identifiable {
case beachPadel = "https://beach-padel.app.fft.fr/beachja/index/" case beachPadel = "https://beach-padel.app.fft.fr/beachja/index/"
//case padelClub = "https://padelclub.app" //case padelClub = "https://padelclub.app"
case tenup = "https://tenup.fft.fr" case tenup = "https://tenup.fft.fr"
case padelCompetitionGeneralGuide = "https://fft-site.cdn.prismic.io/fft-site/Z2mH0ZbqstJ98yso_CHAPITREIRèglesgénérales.pdf" case padelCompetitionGeneralGuide = "https://padelclub.app/static/rules/padel-guide-general.pdf"
case padelCompetitionSpecificGuide = "https://fft-site.cdn.prismic.io/fft-site/Z2mHz5bqstJ98ysm_CHAPITREIIICahierdeschargesdestournois.pdf" case padelCompetitionSpecificGuide = "https://padelclub.app/static/rules/padel-guide-cdc.pdf"
case padelRules = "https://xlr.alwaysdata.net/static/rules/padel-rules-2024.pdf" case padelCompetitionRankingGuide = "https://padelclub.app/static/rules/padel-guide-rankings.pdf"
case padelRules = "https://padelclub.app/static/rules/padel-rules.pdf"
case restingDischarge = "https://club.fft.fr/tennisfirmidecazeville/60120370_d/data_1/pdf/fo/formlairededechargederesponsabilitetournoidepadel.pdf" case restingDischarge = "https://club.fft.fr/tennisfirmidecazeville/60120370_d/data_1/pdf/fo/formlairededechargederesponsabilitetournoidepadel.pdf"
case appReview = "https://apps.apple.com/app/padel-club/id6484163558?mt=8&action=write-review" case appReview = "https://apps.apple.com/app/padel-club/id6484163558?mt=8&action=write-review"
case appDescription = "https://padelclub.app/download/" case appDescription = "https://padelclub.app/download/"

@ -146,6 +146,33 @@ struct MatchSetupView: View {
Label(seedGroup.localizedInterval(), systemImage: "dice") Label(seedGroup.localizedInterval(), systemImage: "dice")
} }
} }
Divider()
Menu {
ForEach(tournament.availableSeedGroups(includeAll: true), id: \.self) { seedGroup in
ConfirmButtonView(shouldConfirm: shouldConfirm, message: MatchSetupView.confirmationMessage) {
if let randomTeam = tournament.randomSeed(fromSeedGroup: seedGroup) {
randomTeam.setSeedPosition(inSpot: match, slot: teamPosition, opposingSeeding: false)
do {
try tournamentStore.matches.addOrUpdate(instance: match)
} catch {
Logger.error(error)
}
do {
try tournamentStore.teamRegistrations.addOrUpdate(instance: randomTeam)
} catch {
Logger.error(error)
}
}
} label: {
Label(seedGroup.localizedInterval(), systemImage: "dice")
}
}
} label: {
Text("plus d'options")
}
} label: { } label: {
Text("Tirer au sort").tag(nil as SeedInterval?) Text("Tirer au sort").tag(nil as SeedInterval?)
.underline() .underline()

@ -107,7 +107,7 @@ struct EventListView: View {
@ViewBuilder @ViewBuilder
private func _options(_ pcTournaments: [Tournament]) -> some View { private func _options(_ pcTournaments: [Tournament]) -> some View {
if let lastDataSource, pcTournaments.anySatisfy({ $0.rankSourceShouldBeRefreshed() != nil && $0.hasEnded() == false }) { if let lastDataSource, pcTournaments.anySatisfy({ $0.rankSourceShouldBeRefreshed() != nil && $0.hasEnded() == false }) {
Section { Menu {
Button { Button {
Task { Task {
do { do {
@ -134,14 +134,14 @@ struct EventListView: View {
} }
} }
} label: { } label: {
Text("Rafraîchir les classements") Text("M-à-j des classements")
} }
} header: { } label: {
Text("Source disponible : \(lastDataSource.monthYearFormatted)") Text("Classement \(lastDataSource.monthYearFormatted)")
} }
Divider() Divider()
} }
Section { Menu {
if pcTournaments.anySatisfy({ $0.isPrivate == true }) { if pcTournaments.anySatisfy({ $0.isPrivate == true }) {
Button { Button {
pcTournaments.forEach { tournament in pcTournaments.forEach { tournament in
@ -153,7 +153,7 @@ struct EventListView: View {
Logger.error(error) Logger.error(error)
} }
} label: { } label: {
Text("Afficher ce\(pcTournaments.count.pluralSuffix) tournoi\(pcTournaments.count.pluralSuffix) sur Padel Club") Text("Afficher sur Padel Club")
} }
} }
@ -168,15 +168,15 @@ struct EventListView: View {
Logger.error(error) Logger.error(error)
} }
} label: { } label: {
Text("Masquer ce\(pcTournaments.count.pluralSuffix) tournoi\(pcTournaments.count.pluralSuffix) sur Padel Club") Text("Masquer sur Padel Club")
} }
} }
} header: { } label: {
Text("Visibilité sur Padel Club") Text("Visibilité sur Padel Club")
} }
Divider() Divider()
if pcTournaments.anySatisfy({ $0.hasEnded() == false && $0.enableOnlineRegistration == false && $0.onlineRegistrationCanBeEnabled() }) || pcTournaments.anySatisfy({ $0.enableOnlineRegistration == true && $0.hasEnded() == false }) { if pcTournaments.anySatisfy({ $0.hasEnded() == false && $0.enableOnlineRegistration == false && $0.onlineRegistrationCanBeEnabled() }) || pcTournaments.anySatisfy({ $0.enableOnlineRegistration == true && $0.hasEnded() == false }) {
Section { Menu {
if pcTournaments.anySatisfy({ $0.hasEnded() == false && $0.enableOnlineRegistration == false && $0.onlineRegistrationCanBeEnabled() }) { if pcTournaments.anySatisfy({ $0.hasEnded() == false && $0.enableOnlineRegistration == false && $0.onlineRegistrationCanBeEnabled() }) {
Button { Button {
pcTournaments.forEach { tournament in pcTournaments.forEach { tournament in
@ -188,7 +188,7 @@ struct EventListView: View {
Logger.error(error) Logger.error(error)
} }
} label: { } label: {
Text("Activer l'inscription en ligne") Text("Activer")
} }
} }
@ -201,7 +201,7 @@ struct EventListView: View {
} }
} }
} label: { } label: {
Text("Rafraîchir la liste des équipes inscrites en ligne") Text("M-à-j des inscriptions")
} }
@ -215,13 +215,64 @@ struct EventListView: View {
Logger.error(error) Logger.error(error)
} }
} label: { } label: {
Text("Désactiver l'inscription en ligne") Text("Désactiver")
} }
} }
} header: { } label: {
Text("Inscription en ligne") Text("Inscription en ligne")
} }
} }
Divider()
Menu {
Button {
pcTournaments.forEach { tournament in
tournament.information = nil
}
do {
try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
} catch {
Logger.error(error)
}
} label: {
Text("Effacer les descriptions")
}
let info = Set(pcTournaments.compactMap { tournament in
tournament.information?.trimmedMultiline
}).joined(separator: "\n")
if info.isEmpty == false {
Button {
pcTournaments.forEach { tournament in
tournament.information = info
}
do {
try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
} catch {
Logger.error(error)
}
} label: {
Text("Mettre '\(info.trunc(length: 12))'")
}
}
PasteButton(payloadType: String.self) { strings in
if let pasteboard = strings.first {
pcTournaments.forEach { tournament in
tournament.information = pasteboard
}
do {
try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
} catch {
Logger.error(error)
}
}
}
} label: {
Text("Description des tournois")
}
} }
private func _nextMonths() -> [Date] { private func _nextMonths() -> [Date] {

@ -170,9 +170,10 @@ struct ToolboxView: View {
} }
Section { Section {
Link("Accéder au guide de la compétition", destination: URLs.padelCompetitionGeneralGuide.url) Link("Guide de la compétition", destination: URLs.padelCompetitionGeneralGuide.url)
Link("Accéder aux CDC des tournois", destination: URLs.padelCompetitionSpecificGuide.url) Link("CDC des tournois", destination: URLs.padelCompetitionSpecificGuide.url)
Link("Accéder aux règles du jeu", destination: URLs.padelRules.url) Link("Barèmes et assimilations", destination: URLs.padelCompetitionRankingGuide.url)
Link("Règles du jeu", destination: URLs.padelRules.url)
Link("Décharge des temps de repos", destination: URLs.restingDischarge.url) Link("Décharge des temps de repos", destination: URLs.restingDischarge.url)
} header: { } header: {
Text("Documents fédéraux") Text("Documents fédéraux")

@ -132,9 +132,6 @@ struct RoundView: View {
if availableSeeds.isEmpty == false, let availableSeedGroup { if availableSeeds.isEmpty == false, let availableSeedGroup {
_seedGroupSection(availableSeeds: availableSeeds, availableSeedGroup: availableSeedGroup) _seedGroupSection(availableSeeds: availableSeeds, availableSeedGroup: availableSeedGroup)
if upperRound.round.index == 3, availableSeedGroup.first == 5, availableSeedGroup.last == 8, availableSeeds.count > 4, let half = availableSeedGroup.chunks()?.first {
_seedGroupSection(availableSeeds: Array(availableSeeds.prefix(2)), availableSeedGroup: half)
}
} }
if availableQualifiedTeams.isEmpty == false { if availableQualifiedTeams.isEmpty == false {
@ -295,11 +292,6 @@ struct RoundView: View {
array.append(spots[1]) array.append(spots[1])
array.append(spots[4]) array.append(spots[4])
return array return array
} else if availableSeedGroup == SeedInterval(first: 5, last: 6), spots.count == 4 {
var array = [Match]()
array.append(spots[1])
array.append(spots[2])
return array
} else { } else {
return spots return spots
} }
@ -394,6 +386,14 @@ struct RoundView: View {
_save(seeds: availableSeeds) _save(seeds: availableSeeds)
} }
} }
// if upperRound.round.index == 3, availableSeedGroup.first == 5, availableSeedGroup.last == 8, availableSeeds.count > 1, let half = availableSeedGroup.chunks()?.first {
// FooterButtonView("ou placer \(half.localizedInterval())" + ((half.isFixed() == false) ? " au hasard" : "")) {
// Task {
// tournament.setSeeds(inRoundIndex: upperRound.round.index, inSeedGroup: half)
// _save(seeds: availableSeeds)
// }
// }
// }
} footer: { } footer: {
if availableSeedGroup.isFixed() == false { if availableSeedGroup.isFixed() == false {
Text("Le tirage au sort ne sera pas visuel. Toutes les équipes de ce chapeau seront tirées.") Text("Le tirage au sort ne sera pas visuel. Toutes les équipes de ce chapeau seront tirées.")
@ -411,6 +411,11 @@ struct RoundView: View {
RowButtonView("Tirage au sort \(availableSeedGroup.localizedInterval()) visuel") { RowButtonView("Tirage au sort \(availableSeedGroup.localizedInterval()) visuel") {
self.selectedSeedGroup = availableSeedGroup self.selectedSeedGroup = availableSeedGroup
} }
// if upperRound.round.index == 3, availableSeedGroup.first == 5, availableSeedGroup.last == 8, availableSeeds.count > 1, let half = availableSeedGroup.chunks()?.first {
// FooterButtonView("ou tirage au sort \(half.localizedInterval()) visuel") {
// self.selectedSeedGroup = half
// }
// }
} footer: { } footer: {
Text("Le tirage au sort sera visuel et automatique, n'hésitez pas à enregistrer une vidéo de votre écran. Toutes les équipes de ce chapeau seront tirées les unes après les autres.") Text("Le tirage au sort sera visuel et automatique, n'hésitez pas à enregistrer une vidéo de votre écran. Toutes les équipes de ce chapeau seront tirées les unes après les autres.")
} }

Loading…
Cancel
Save