Laurent 1 year ago
commit c2ca49e9f6
  1. 8
      PadelClub.xcodeproj/project.pbxproj
  2. 10
      PadelClub/Assets.xcassets/PadelClub_logo_fondclair_transparent.imageset/Contents.json
  3. BIN
      PadelClub/Assets.xcassets/PadelClub_logo_fondclair_transparent.imageset/PadelClub_logo_fondfonce_transparent.png
  4. 6
      PadelClub/Assets.xcassets/logoBackground.colorset/Contents.json
  5. 6
      PadelClub/Assets.xcassets/logoYellow.colorset/Contents.json
  6. 1
      PadelClub/Views/Calling/CallView.swift
  7. 1
      PadelClub/Views/Calling/Components/MenuWarningView.swift
  8. 1
      PadelClub/Views/Calling/SendToAllView.swift
  9. 7
      PadelClub/Views/Cashier/CashierDetailView.swift
  10. 4
      PadelClub/Views/Cashier/Event/EventLinksView.swift
  11. 43
      PadelClub/Views/Cashier/Event/EventSettingsView.swift
  12. 18
      PadelClub/Views/Cashier/Event/EventTournamentsView.swift
  13. 21
      PadelClub/Views/Cashier/Event/EventView.swift
  14. 1
      PadelClub/Views/Match/MatchDetailView.swift
  15. 4
      PadelClub/Views/Navigation/Agenda/ActivityView.swift
  16. 3
      PadelClub/Views/Navigation/Organizer/TournamentButtonView.swift
  17. 5
      PadelClub/Views/Navigation/Umpire/PadelClubView.swift
  18. 1
      PadelClub/Views/Navigation/Umpire/UmpireView.swift
  19. 1
      PadelClub/Views/Planning/CourtAvailabilitySettingsView.swift
  20. 4
      PadelClub/Views/Planning/PlanningSettingsView.swift
  21. 64
      PadelClub/Views/Tournament/Screen/Components/EventClubSettingsView.swift
  22. 72
      PadelClub/Views/Tournament/Screen/Components/TournamentClubSettingsView.swift
  23. 20
      PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift
  24. 4
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  25. 26
      PadelClub/Views/Tournament/Screen/TournamentSettingsView.swift
  26. 2
      PadelClub/Views/Tournament/TournamentInitView.swift
  27. 10
      PadelClub/Views/Tournament/TournamentView.swift
  28. 2
      PadelClub/Views/ViewModifiers/DeferredViewModifier.swift

@ -241,6 +241,7 @@
FFDB1C6D2BB2A02000F1E467 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */; }; FFDB1C6D2BB2A02000F1E467 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */; };
FFDB1C732BB2CFE900F1E467 /* MySortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C722BB2CFE900F1E467 /* MySortDescriptor.swift */; }; FFDB1C732BB2CFE900F1E467 /* MySortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C722BB2CFE900F1E467 /* MySortDescriptor.swift */; };
FFDDD40C2B93B2BB00C91A49 /* DeferredViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDDD40B2B93B2BB00C91A49 /* DeferredViewModifier.swift */; }; FFDDD40C2B93B2BB00C91A49 /* DeferredViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDDD40B2B93B2BB00C91A49 /* DeferredViewModifier.swift */; };
FFE103082C353B7600684FC9 /* EventClubSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */; };
FFE2D2E22C231BEE00D0C7BE /* SupportButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE2D2E12C231BEE00D0C7BE /* SupportButtonView.swift */; }; FFE2D2E22C231BEE00D0C7BE /* SupportButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE2D2E12C231BEE00D0C7BE /* SupportButtonView.swift */; };
FFEF7F4E2BDE69130033D0F0 /* MenuWarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEF7F4D2BDE69130033D0F0 /* MenuWarningView.swift */; }; FFEF7F4E2BDE69130033D0F0 /* MenuWarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEF7F4D2BDE69130033D0F0 /* MenuWarningView.swift */; };
FFF0241E2BF48B15001F14B4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = FFF0241D2BF48B15001F14B4 /* Localizable.strings */; }; FFF0241E2BF48B15001F14B4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = FFF0241D2BF48B15001F14B4 /* Localizable.strings */; };
@ -572,6 +573,7 @@
FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; }; FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
FFDB1C722BB2CFE900F1E467 /* MySortDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MySortDescriptor.swift; sourceTree = "<group>"; }; FFDB1C722BB2CFE900F1E467 /* MySortDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MySortDescriptor.swift; sourceTree = "<group>"; };
FFDDD40B2B93B2BB00C91A49 /* DeferredViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeferredViewModifier.swift; sourceTree = "<group>"; }; FFDDD40B2B93B2BB00C91A49 /* DeferredViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeferredViewModifier.swift; sourceTree = "<group>"; };
FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EventClubSettingsView.swift; path = PadelClub/Views/Tournament/Screen/Components/EventClubSettingsView.swift; sourceTree = SOURCE_ROOT; };
FFE2D2E12C231BEE00D0C7BE /* SupportButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportButtonView.swift; sourceTree = "<group>"; }; FFE2D2E12C231BEE00D0C7BE /* SupportButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportButtonView.swift; sourceTree = "<group>"; };
FFEF7F4D2BDE69130033D0F0 /* MenuWarningView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuWarningView.swift; sourceTree = "<group>"; }; FFEF7F4D2BDE69130033D0F0 /* MenuWarningView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuWarningView.swift; sourceTree = "<group>"; };
FFF0241C2BF48B15001F14B4 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; }; FFF0241C2BF48B15001F14B4 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
@ -1203,6 +1205,7 @@
FFBF41832BF75ED7001B24CB /* EventTournamentsView.swift */, FFBF41832BF75ED7001B24CB /* EventTournamentsView.swift */,
FFBF41852BF75FDA001B24CB /* EventSettingsView.swift */, FFBF41852BF75FDA001B24CB /* EventSettingsView.swift */,
FF8F263A2BAD528600650388 /* EventCreationView.swift */, FF8F263A2BAD528600650388 /* EventCreationView.swift */,
FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */,
FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */, FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */,
); );
name = Event; name = Event;
@ -1520,6 +1523,7 @@
FF7091682B90F79F00AB08DA /* TournamentCellView.swift in Sources */, FF7091682B90F79F00AB08DA /* TournamentCellView.swift in Sources */,
FF6EC9042B9479F500EA7F5A /* Sequence+Extensions.swift in Sources */, FF6EC9042B9479F500EA7F5A /* Sequence+Extensions.swift in Sources */,
FF9267FA2BCE78EC0080F940 /* CashierDetailView.swift in Sources */, FF9267FA2BCE78EC0080F940 /* CashierDetailView.swift in Sources */,
FFE103082C353B7600684FC9 /* EventClubSettingsView.swift in Sources */,
C4A47DB32B86387500ADC637 /* AccountView.swift in Sources */, C4A47DB32B86387500ADC637 /* AccountView.swift in Sources */,
FFCEDA4C2C2C08EA00F8C0F2 /* PlayersWithoutContactView.swift in Sources */, FFCEDA4C2C2C08EA00F8C0F2 /* PlayersWithoutContactView.swift in Sources */,
FF1CBC1D2BB53DC10036DAAB /* Calendar+Extensions.swift in Sources */, FF1CBC1D2BB53DC10036DAAB /* Calendar+Extensions.swift in Sources */,
@ -1890,7 +1894,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 80; CURRENT_PROJECT_VERSION = 83;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
@ -1933,7 +1937,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 80; CURRENT_PROJECT_VERSION = 83;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -3,6 +3,16 @@
{ {
"filename" : "PadelClub_logo_fondclair_transparent.png", "filename" : "PadelClub_logo_fondclair_transparent.png",
"idiom" : "universal" "idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "PadelClub_logo_fondfonce_transparent.png",
"idiom" : "universal"
} }
], ],
"info" : { "info" : {

@ -23,9 +23,9 @@
"color-space" : "srgb", "color-space" : "srgb",
"components" : { "components" : {
"alpha" : "1.000", "alpha" : "1.000",
"blue" : "58", "blue" : "0.808",
"green" : "35", "green" : "0.906",
"red" : "25" "red" : "0.980"
} }
}, },
"idiom" : "universal" "idiom" : "universal"

@ -23,9 +23,9 @@
"color-space" : "srgb", "color-space" : "srgb",
"components" : { "components" : {
"alpha" : "1.000", "alpha" : "1.000",
"blue" : "1.000", "blue" : "0.808",
"green" : "1.000", "green" : "0.906",
"red" : "1.000" "red" : "0.980"
} }
}, },
"idiom" : "universal" "idiom" : "universal"

@ -173,6 +173,7 @@ struct CallView: View {
.sheet(isPresented: self.$showSubscriptionView, content: { .sheet(isPresented: self.$showSubscriptionView, content: {
NavigationStack { NavigationStack {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
} }
}) })
.sheet(isPresented: self.$showUserCreationView, content: { .sheet(isPresented: self.$showUserCreationView, content: {

@ -52,6 +52,7 @@ struct MenuWarningView: View {
.sheet(isPresented: self.$showSubscriptionView, content: { .sheet(isPresented: self.$showSubscriptionView, content: {
NavigationStack { NavigationStack {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
} }
}) })
.sheet(isPresented: self.$showUserCreationView, content: { .sheet(isPresented: self.$showUserCreationView, content: {

@ -167,6 +167,7 @@ struct SendToAllView: View {
.sheet(isPresented: self.$showSubscriptionView, content: { .sheet(isPresented: self.$showSubscriptionView, content: {
NavigationStack { NavigationStack {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
} }
}) })
.sheet(isPresented: self.$showUserCreationView, content: { .sheet(isPresented: self.$showUserCreationView, content: {

@ -67,8 +67,11 @@ struct CashierDetailView: View {
private func _getPaidCompletion() { private func _getPaidCompletion() {
let selectedPlayers = tournaments.flatMap { $0.selectedPlayers() } let selectedPlayers = tournaments.flatMap { $0.selectedPlayers() }
if selectedPlayers.isEmpty { paidCompletion = 0 } if selectedPlayers.isEmpty {
paidCompletion = Double(selectedPlayers.filter { $0.hasPaid() }.count) / Double(selectedPlayers.count) paidCompletion = 0
} else {
paidCompletion = Double(selectedPlayers.filter { $0.hasPaid() }.count) / Double(selectedPlayers.count)
}
} }
private func _tournamentsCashierDetailView(_ tournaments: [Tournament]) -> some View { private func _tournamentsCashierDetailView(_ tournaments: [Tournament]) -> some View {

@ -37,7 +37,7 @@ struct EventLinksView: View {
Text(pageLink.localizedLabel()).tag(pageLink) Text(pageLink.localizedLabel()).tag(pageLink)
} }
} label: { } label: {
Text("Choisir une page du tournoi en particulier") Text("Choisir une page en particulier")
} }
.pickerStyle(.menu) .pickerStyle(.menu)
} }
@ -49,7 +49,7 @@ struct EventLinksView: View {
.multilineTextAlignment(.leading) .multilineTextAlignment(.leading)
ShareLink("Partagez ce lien", item: eventLinksPasteData) ShareLink("Partagez ce message", item: eventLinksPasteData)
} }
} }
} }

@ -13,6 +13,28 @@ struct EventSettingsView: View {
@Bindable var event: Event @Bindable var event: Event
@State private var eventName: String = "" @State private var eventName: String = ""
@FocusState private var textFieldIsFocus: Bool @FocusState private var textFieldIsFocus: Bool
@State private var pageLink: PageLink = .teams
func eventLinksPasteData() -> String {
let tournaments = event.tournaments
var link = [String]()
link.append(event.eventTitle())
link.append("\n\n")
link.append("Retrouvez toutes les infos en suivant le\(tournaments.count.pluralSuffix) lien\(tournaments.count.pluralSuffix) ci-dessous")
link.append("\n\n")
tournaments.forEach({ tournament in
if let url = tournament.shareURL(pageLink) {
var tournamentLink = [String]()
tournamentLink.append(tournament.tournamentTitle())
tournamentLink.append(url.absoluteString)
link.append(tournamentLink.joined(separator: "\n"))
}
})
return link.joined(separator: "\n\n")
}
init(event: Event) { init(event: Event) {
self.event = event self.event = event
@ -37,6 +59,27 @@ struct EventSettingsView: View {
} }
} }
} }
let eventLinksPasteData = eventLinksPasteData()
Section {
Text(eventLinksPasteData)
.italic()
.multilineTextAlignment(.leading)
let links : [PageLink] = [.teams, .summons, .groupStages, .matches, .rankings]
Picker(selection: $pageLink) {
ForEach(links) { pageLink in
Text(pageLink.localizedLabel()).tag(pageLink)
}
} label: {
Text("Choisir une page en particulier")
}
.pickerStyle(.menu)
ShareLink("Partagez ce message", item: eventLinksPasteData)
} header: {
Text("Liens à partager")
}
} }
.toolbar { .toolbar {
if textFieldIsFocus { if textFieldIsFocus {

@ -27,14 +27,18 @@ struct EventTournamentsView: View {
let tournaments = event.tournaments let tournaments = event.tournaments
List { List {
ForEach(tournaments) { tournament in ForEach(tournaments) { tournament in
TournamentCellView(tournament: tournament) NavigationLink {
.contextMenu { TournamentStatusView(tournament: tournament)
Button { } label: {
navigation.openTournamentInOrganizer(tournament) TournamentCellView(tournament: tournament)
} label: { .contextMenu {
Label("Voir dans le gestionnaire", systemImage: "line.diagonal.arrow") Button {
navigation.openTournamentInOrganizer(tournament)
} label: {
Label("Voir dans le gestionnaire", systemImage: "line.diagonal.arrow")
}
} }
} }
} }
} }
.toolbar { .toolbar {

@ -13,6 +13,7 @@ enum EventDestination: Identifiable, Selectable, Equatable {
return lhs.id == rhs.id return lhs.id == rhs.id
} }
case club(Event)
case links case links
case tournaments(Event) case tournaments(Event)
case cashier case cashier
@ -23,6 +24,8 @@ enum EventDestination: Identifiable, Selectable, Equatable {
func selectionLabel(index: Int) -> String { func selectionLabel(index: Int) -> String {
switch self { switch self {
case .club:
return "Club"
case .links: case .links:
return "Liens" return "Liens"
case .tournaments: case .tournaments:
@ -34,7 +37,7 @@ enum EventDestination: Identifiable, Selectable, Equatable {
func badgeValue() -> Int? { func badgeValue() -> Int? {
switch self { switch self {
case .links: case .links, .club:
return nil return nil
case .tournaments(let event): case .tournaments(let event):
return event.tournaments.count return event.tournaments.count
@ -48,7 +51,17 @@ enum EventDestination: Identifiable, Selectable, Equatable {
} }
func badgeImage() -> Badge? { func badgeImage() -> Badge? {
return nil
switch self {
case .club(let event):
if event.club != nil {
return .checkmark
} else {
return .xmark
}
default:
return nil
}
} }
} }
@ -58,7 +71,7 @@ struct EventView: View {
@State private var selectedDestination: EventDestination? @State private var selectedDestination: EventDestination?
func allDestinations() -> [EventDestination] { func allDestinations() -> [EventDestination] {
[.links, .tournaments(event), .cashier] [.club(event), .tournaments(event), .cashier]
} }
var body: some View { var body: some View {
@ -69,6 +82,8 @@ struct EventView: View {
EventSettingsView(event: event) EventSettingsView(event: event)
case .some(let selectedEventDestination): case .some(let selectedEventDestination):
switch selectedEventDestination { switch selectedEventDestination {
case .club(let event):
EventClubSettingsView(event: event)
case .links: case .links:
EventLinksView(event: event) EventLinksView(event: event)
case .tournaments(let event): case .tournaments(let event):

@ -137,6 +137,7 @@ struct MatchDetailView: View {
.sheet(isPresented: self.$showSubscriptionView, content: { .sheet(isPresented: self.$showSubscriptionView, content: {
NavigationStack { NavigationStack {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
} }
}) })
.sheet(isPresented: self.$showUserCreationView, content: { .sheet(isPresented: self.$showUserCreationView, content: {

@ -335,9 +335,9 @@ struct ActivityView: View {
private func _tenupEmptyView() -> some View { private func _tenupEmptyView() -> some View {
if dataStore.user.hasTenupClubs() == false { if dataStore.user.hasTenupClubs() == false {
ContentUnavailableView { ContentUnavailableView {
Label("Aucun tournoi", systemImage: "shield.slash") Label("Aucun clubs FFT", systemImage: "shield.slash")
} description: { } description: {
Text("Pour voir vos tournois tenup ici, choisissez vos clubs.") Text("Pour voir vos tournois tenup ici, mettez en favori des clubs FFT.")
} actions: { } actions: {
RowButtonView("Choisir mes clubs") { RowButtonView("Choisir mes clubs") {
presentClubSearchView = true presentClubSearchView = true

@ -8,6 +8,7 @@
import SwiftUI import SwiftUI
struct TournamentButtonView: View { struct TournamentButtonView: View {
@Environment(\.colorScheme) var colorScheme
@Environment(NavigationViewModel.self) private var navigation @Environment(NavigationViewModel.self) private var navigation
let tournament: Tournament let tournament: Tournament
@ -23,7 +24,7 @@ struct TournamentButtonView: View {
.padding(8) .padding(8)
.overlay( .overlay(
RoundedRectangle(cornerRadius: 20) RoundedRectangle(cornerRadius: 20)
.stroke(Color.black, lineWidth: 2) .stroke(colorScheme == .light ? Color.black : Color.white, lineWidth: 2)
) )
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
} }

@ -85,7 +85,7 @@ struct PadelClubView: View {
if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, _lastDataSourceDate.isEarlierThan(mostRecentDateAvailable) { if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, _lastDataSourceDate.isEarlierThan(mostRecentDateAvailable) {
Section { Section {
RowButtonView("Importer \(URL.importDateFormatter.string(from: mostRecentDateAvailable))") { RowButtonView("Importer \(mostRecentDateAvailable.monthYearFormatted)") {
_startImporting() _startImporting()
} }
} }
@ -109,7 +109,7 @@ struct PadelClubView: View {
Text("Padel Club peut importer toutes les données publiques de la FFT concernant tous les compétiteurs et compétitrices.") Text("Padel Club peut importer toutes les données publiques de la FFT concernant tous les compétiteurs et compétitrices.")
} actions: { } actions: {
if let _mostRecentDateAvailable { if let _mostRecentDateAvailable {
RowButtonView("Démarrer l'importation de \(URL.importDateFormatter.string(from: _mostRecentDateAvailable))") { RowButtonView("Importer \(_mostRecentDateAvailable.monthYearFormatted)") {
_startImporting() _startImporting()
} }
} }
@ -222,6 +222,7 @@ struct PadelClubView: View {
await SourceFileManager.shared.fetchData() await SourceFileManager.shared.fetchData()
checkingFilesAttempt += 1 checkingFilesAttempt += 1
checkingFiles = false checkingFiles = false
uuid = UUID()
} }
private func _startImporting() { private func _startImporting() {

@ -183,6 +183,7 @@ struct UmpireView: View {
.sheet(isPresented: self.$showSubscriptions, content: { .sheet(isPresented: self.$showSubscriptions, content: {
NavigationStack { NavigationStack {
SubscriptionView(isPresented: self.$showSubscriptions) SubscriptionView(isPresented: self.$showSubscriptions)
.environment(\.colorScheme, .light)
} }
}) })
.sheet(isPresented: $presentSearchView) { .sheet(isPresented: $presentSearchView) {

@ -87,6 +87,7 @@ struct CourtAvailabilitySettingsView: View {
LabelDelete() LabelDelete()
} }
} }
.buttonStyle(.plain)
} }
} header: { } header: {
HStack { HStack {

@ -66,7 +66,7 @@ struct PlanningSettingsView: View {
CourtAvailabilitySettingsView(event: event) CourtAvailabilitySettingsView(event: event)
.environment(tournament) .environment(tournament)
} label: { } label: {
Text("Préciser la disponibilité des terrains") Text("Préciser les indisponibilités des terrains")
} }
} }
} footer: { } footer: {
@ -74,7 +74,7 @@ struct PlanningSettingsView: View {
if tournament.courtCount < club.courtCount { if tournament.courtCount < club.courtCount {
let plural = tournament.courtCount.pluralSuffix let plural = tournament.courtCount.pluralSuffix
let verb = tournament.courtCount > 1 ? "seront" : "sera" 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.") 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 gardez le nombre de terrains du club, vous pourrez plutôt préciser quel terrain n'est pas disponible.")
} else if tournament.courtCount > club.courtCount { } else if tournament.courtCount > club.courtCount {
let isCreatedByUser = club.hasBeenCreated(by: StoreCenter.main.userId) let isCreatedByUser = club.hasBeenCreated(by: StoreCenter.main.userId)
Button { Button {

@ -0,0 +1,64 @@
//
// EventClubSettingsView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 18/04/2024.
//
import SwiftUI
import LeStorage
struct EventClubSettingsView: View {
@EnvironmentObject var dataStore: DataStore
@State private var selectedCourt: Court?
@State private var showClubDetail: Club?
var event: Event
var body: some View {
List {
let selectedClub = event.clubObject()
Section {
NavigationLink {
ClubsView() { club in
event.club = club.id
do {
try dataStore.events.addOrUpdate(instance: event)
} catch {
Logger.error(error)
}
}
} label: {
if let selectedClub = event.clubObject() {
ClubRowView(club: selectedClub)
} else {
Text("Choisir un club")
}
}
} header: {
Text("Lieu de l'événement")
} footer: {
HStack {
Spacer()
FooterButtonView("détails du club") {
showClubDetail = selectedClub
}
}
}
if let selectedClub {
ClubCourtSetupView(club: selectedClub, displayContext: selectedClub.hasBeenCreated(by: StoreCenter.main.userId) ? .edition : .lockedForEditing, selectedCourt: $selectedCourt)
}
}
.navigationDestination(item: $showClubDetail) { club in
ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: StoreCenter.main.userId) ? .edition : .lockedForEditing)
}
.navigationDestination(item: $selectedCourt) { court in
CourtView(court: court)
}
}
}
//#Preview {
// TournamentClubSettingsView()
//}

@ -19,36 +19,6 @@ struct TournamentClubSettingsView: View {
List { List {
let event = tournament.eventObject() let event = tournament.eventObject()
let selectedClub = event?.clubObject() let selectedClub = event?.clubObject()
Section {
NavigationLink {
ClubsView() { club in
if let event {
event.club = club.id
do {
try dataStore.events.addOrUpdate(instance: event)
} catch {
Logger.error(error)
}
}
}
} label: {
if let selectedClub {
ClubRowView(club: selectedClub)
} else {
Text("Choisir un club")
}
}
} header: {
Text("Lieu du tournoi")
} footer: {
HStack {
Spacer()
FooterButtonView("détails du club") {
showClubDetail = selectedClub
}
}
}
Section { Section {
TournamentFieldsManagerView(localizedStringKey: "Terrains pour le tournoi", count: $tournament.courtCount) TournamentFieldsManagerView(localizedStringKey: "Terrains pour le tournoi", count: $tournament.courtCount)
@ -65,7 +35,7 @@ struct TournamentClubSettingsView: View {
CourtAvailabilitySettingsView(event: event) CourtAvailabilitySettingsView(event: event)
.environment(tournament) .environment(tournament)
} label: { } label: {
Text("Préciser la disponibilité des terrains") Text("Préciser les indisponibilités des terrains")
} }
} }
} footer: { } footer: {
@ -73,7 +43,7 @@ struct TournamentClubSettingsView: View {
if tournament.courtCount < club.courtCount { if tournament.courtCount < club.courtCount {
let plural = tournament.courtCount.pluralSuffix let plural = tournament.courtCount.pluralSuffix
let verb = tournament.courtCount > 1 ? "seront" : "sera" 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.") 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 gardez le nombre de terrains du club, vous pourrez plutôt préciser quel terrain n'est pas disponible.")
} else if tournament.courtCount > club.courtCount { } else if tournament.courtCount > club.courtCount {
let isCreatedByUser = club.hasBeenCreated(by: StoreCenter.main.userId) let isCreatedByUser = club.hasBeenCreated(by: StoreCenter.main.userId)
Button { Button {
@ -97,18 +67,38 @@ struct TournamentClubSettingsView: View {
} }
} }
Section {
NavigationLink {
ClubsView() { club in
if let event {
event.club = club.id
do {
try dataStore.events.addOrUpdate(instance: event)
} catch {
Logger.error(error)
}
}
}
} label: {
if let selectedClub {
ClubRowView(club: selectedClub)
} else {
Text("Choisir un club")
}
}
} header: {
Text("Lieu du tournoi")
} footer: {
HStack {
Spacer()
FooterButtonView("détails du club") {
showClubDetail = selectedClub
}
}
}
if let selectedClub { if let selectedClub {
ClubCourtSetupView(club: selectedClub, displayContext: selectedClub.hasBeenCreated(by: StoreCenter.main.userId) ? .edition : .lockedForEditing, selectedCourt: $selectedCourt) ClubCourtSetupView(club: selectedClub, displayContext: selectedClub.hasBeenCreated(by: StoreCenter.main.userId) ? .edition : .lockedForEditing, selectedCourt: $selectedCourt)
.onChange(of: selectedClub.courtCount) {
tournament.courtCount = max(tournament.courtCount, selectedClub.courtCount)
do {
try dataStore.tournaments.addOrUpdate(instance: tournament)
} catch {
Logger.error(error)
}
}
} }
} }
.navigationDestination(item: $showClubDetail) { club in .navigationDestination(item: $showClubDetail) { club in

@ -10,12 +10,11 @@ import LeStorage
struct TournamentStatusView: View { struct TournamentStatusView: View {
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@Environment(Tournament.self) private var tournament: Tournament
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Bindable var tournament: Tournament
var body: some View { var body: some View {
@Bindable var tournament = tournament
Form { Form {
#if DEBUG #if DEBUG
RowButtonView("debug: Un-delete le tournoi") { RowButtonView("debug: Un-delete le tournoi") {
@ -86,19 +85,20 @@ struct TournamentStatusView: View {
} }
} }
Section { // Section {
Toggle(isOn: $tournament.isPrivate) { // Toggle(isOn: $tournament.isPrivate) {
Text("Tournoi privé") // Text("Tournoi privé")
} // }
} footer: { // } footer: {
Text(.init("Le tournoi sera masqué sur le site [Padel Club](\(URLs.main.rawValue))")) // Text(.init("Le tournoi sera masqué sur le site [Padel Club](\(URLs.main.rawValue))"))
} // }
} }
.navigationTitle("Gestion du tournoi")
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.onChange(of: tournament.endDate) { .onChange(of: tournament.endDate) {
_save() _save()
} }
.onChange(of: [tournament.isDeleted, tournament.isPrivate]) { .onChange(of: tournament.isDeleted) {
_save() _save()
} }
.onChange(of: tournament.isCanceled) { .onChange(of: tournament.isCanceled) {

@ -242,6 +242,7 @@ struct InscriptionManagerView: View {
} }
} else { } else {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
} }
case .mail(_, let recipients, let bccRecipients, let body, let subject, _): case .mail(_, let recipients, let bccRecipients, let body, let subject, _):
if Guard.main.paymentForNewTournament() != nil { if Guard.main.paymentForNewTournament() != nil {
@ -263,6 +264,7 @@ struct InscriptionManagerView: View {
} }
} else { } else {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
} }
} }
} }
@ -606,7 +608,7 @@ struct InscriptionManagerView: View {
} }
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
.tint(.logoBackground) .tint(.master)
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
.padding(16) .padding(16)
} }

@ -28,29 +28,25 @@ enum TournamentSettings: Identifiable, Selectable, Equatable {
case .general: case .general:
return "Général" return "Général"
case .club: case .club:
return "Club" return "Terrains"
} }
} }
func badgeValue() -> Int? { func badgeValue() -> Int? {
nil switch self {
case .club(let tournament):
return tournament.courtCount
default:
return nil
}
} }
func badgeValueColor() -> Color? { func badgeValueColor() -> Color? {
return nil return .logoBackground
} }
func badgeImage() -> Badge? { func badgeImage() -> Badge? {
switch self { return nil
case .club(let tournament):
if tournament.club() != nil {
return .checkmark
} else {
return .xmark
}
default:
return nil
}
} }
} }
@ -59,7 +55,7 @@ struct TournamentSettingsView: View {
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
private func destinations() -> [TournamentSettings] { private func destinations() -> [TournamentSettings] {
[.status, .general, .club(tournament), .matchFormats] [.general, .club(tournament), .matchFormats]
} }
var body: some View { var body: some View {
@ -67,7 +63,7 @@ struct TournamentSettingsView: View {
GenericDestinationPickerView(selectedDestination: $selectedDestination, destinations: destinations(), nilDestinationIsValid: false) GenericDestinationPickerView(selectedDestination: $selectedDestination, destinations: destinations(), nilDestinationIsValid: false)
switch selectedDestination! { switch selectedDestination! {
case .status: case .status:
TournamentStatusView() TournamentStatusView(tournament: tournament)
case .matchFormats: case .matchFormats:
TournamentMatchFormatsSettingsView() TournamentMatchFormatsSettingsView()
case .general: case .general:

@ -44,7 +44,7 @@ struct TournamentInitView: View {
Text(tournament.localizedTournamentType()) Text(tournament.localizedTournamentType())
} label: { } label: {
LabelSettings() LabelSettings()
Text("Formats, club, prix et plus") Text("Formats, terrains, prix et plus")
} }
} }

@ -174,6 +174,7 @@ struct TournamentView: View {
Text("Gestion de l'événement") Text("Gestion de l'événement")
} }
NavigationLink(value: Screen.settings) { NavigationLink(value: Screen.settings) {
LabelSettings() LabelSettings()
} }
@ -190,6 +191,15 @@ struct TournamentView: View {
} }
} }
Divider()
NavigationLink {
TournamentStatusView(tournament: tournament)
} label: {
Text("Gestion du tournoi")
Text("Annuler, supprimer ou terminer le tournoi")
}
} label: { } label: {
LabelOptions() LabelOptions()
.popoverTip(tournamentRunningTip) .popoverTip(tournamentRunningTip)

@ -24,11 +24,13 @@ import SwiftUI
/// Stack Overflow, see https://stackoverflow.com/a/74765430/1558022 /// Stack Overflow, see https://stackoverflow.com/a/74765430/1558022
/// ///
private struct DeferredViewModifier: ViewModifier { private struct DeferredViewModifier: ViewModifier {
@Environment(\.colorScheme) var colorScheme
let delay: DispatchTimeInterval let delay: DispatchTimeInterval
func body(content: Content) -> some View { func body(content: Content) -> some View {
_content(content) _content(content)
.foregroundStyle(colorScheme == .light ? .white : .black)
.onAppear { .onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
self.shouldHide = true self.shouldHide = true

Loading…
Cancel
Save