add tournament name in subtitle in a lot of subviews
add the ability to transfer tournaments into an event
fix broadcast view page to better display some sharing options
sync3
Razmig Sarkissian 1 month ago
parent 86c1fa26cc
commit 8602881562
  1. 16
      PadelClub.xcodeproj/project.pbxproj
  2. 22
      PadelClub/Extensions/View+Extensions.swift
  3. 15
      PadelClub/Utils/Tips.swift
  4. 29
      PadelClub/Views/Cashier/Event/EventTournamentsView.swift
  5. 91
      PadelClub/Views/Cashier/Event/TournamentPickerView.swift
  6. 25
      PadelClub/Views/Components/BarButtonView.swift
  7. 5
      PadelClub/Views/GroupStage/GroupStagesView.swift
  8. 8
      PadelClub/Views/Match/MatchDetailView.swift
  9. 14
      PadelClub/Views/Navigation/Agenda/TournamentSubscriptionView.swift
  10. 10
      PadelClub/Views/Planning/CourtAvailabilitySettingsView.swift
  11. 7
      PadelClub/Views/Round/LoserRoundsView.swift
  12. 6
      PadelClub/Views/Round/RoundsView.swift
  13. 7
      PadelClub/Views/Score/EditScoreView.swift
  14. 7
      PadelClub/Views/Score/FollowUpMatchView.swift
  15. 55
      PadelClub/Views/Tournament/Screen/BroadcastView.swift
  16. 5
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  17. 5
      PadelClub/Views/Tournament/Screen/PrintSettingsView.swift
  18. 5
      PadelClub/Views/Tournament/Screen/RegistrationSetupView.swift
  19. 6
      PadelClub/Views/Tournament/Screen/TableStructureView.swift
  20. 5
      PadelClub/Views/Tournament/Screen/TournamentCallView.swift
  21. 5
      PadelClub/Views/Tournament/Screen/TournamentCashierView.swift
  22. 5
      PadelClub/Views/Tournament/Screen/TournamentRankView.swift
  23. 6
      PadelClub/Views/Tournament/Screen/TournamentScheduleView.swift
  24. 6
      PadelClub/Views/Tournament/Screen/TournamentSettingsView.swift
  25. 20
      PadelClub/Views/Tournament/TournamentView.swift

@ -711,6 +711,12 @@
FFA252B62CDD2C6C0074E63F /* OngoingDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA252B42CDD2C630074E63F /* OngoingDestination.swift */; }; FFA252B62CDD2C6C0074E63F /* OngoingDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA252B42CDD2C630074E63F /* OngoingDestination.swift */; };
FFA252B72CDD2C6C0074E63F /* OngoingDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA252B42CDD2C630074E63F /* OngoingDestination.swift */; }; FFA252B72CDD2C6C0074E63F /* OngoingDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA252B42CDD2C630074E63F /* OngoingDestination.swift */; };
FFA6D7852BB0B795003A31F3 /* FileImportManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA6D7842BB0B795003A31F3 /* FileImportManager.swift */; }; FFA6D7852BB0B795003A31F3 /* FileImportManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA6D7842BB0B795003A31F3 /* FileImportManager.swift */; };
FFA97C8D2E8A59D00089EA22 /* TournamentPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA97C8C2E8A59D00089EA22 /* TournamentPickerView.swift */; };
FFA97C8E2E8A59D00089EA22 /* TournamentPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA97C8C2E8A59D00089EA22 /* TournamentPickerView.swift */; };
FFA97C8F2E8A59D00089EA22 /* TournamentPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA97C8C2E8A59D00089EA22 /* TournamentPickerView.swift */; };
FFA97C9E2E8A7C080089EA22 /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA97C9D2E8A7C080089EA22 /* View+Extensions.swift */; };
FFA97C9F2E8A7C080089EA22 /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA97C9D2E8A7C080089EA22 /* View+Extensions.swift */; };
FFA97CA02E8A7C080089EA22 /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA97C9D2E8A7C080089EA22 /* View+Extensions.swift */; };
FFB0FF672E81B671009EDEAC /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB0FF662E81B671009EDEAC /* OnboardingView.swift */; }; FFB0FF672E81B671009EDEAC /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB0FF662E81B671009EDEAC /* OnboardingView.swift */; };
FFB0FF682E81B671009EDEAC /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB0FF662E81B671009EDEAC /* OnboardingView.swift */; }; FFB0FF682E81B671009EDEAC /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB0FF662E81B671009EDEAC /* OnboardingView.swift */; };
FFB0FF692E81B671009EDEAC /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB0FF662E81B671009EDEAC /* OnboardingView.swift */; }; FFB0FF692E81B671009EDEAC /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB0FF662E81B671009EDEAC /* OnboardingView.swift */; };
@ -1118,6 +1124,8 @@
FFA252B42CDD2C630074E63F /* OngoingDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OngoingDestination.swift; sourceTree = "<group>"; }; FFA252B42CDD2C630074E63F /* OngoingDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OngoingDestination.swift; sourceTree = "<group>"; };
FFA6D7842BB0B795003A31F3 /* FileImportManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileImportManager.swift; sourceTree = "<group>"; }; FFA6D7842BB0B795003A31F3 /* FileImportManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileImportManager.swift; sourceTree = "<group>"; };
FFA6D78A2BB0BEB3003A31F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; FFA6D78A2BB0BEB3003A31F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
FFA97C8C2E8A59D00089EA22 /* TournamentPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentPickerView.swift; sourceTree = "<group>"; };
FFA97C9D2E8A7C080089EA22 /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
FFB0FF662E81B671009EDEAC /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; }; FFB0FF662E81B671009EDEAC /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
FFB0FF722E841042009EDEAC /* WeekdaySelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekdaySelectionView.swift; sourceTree = "<group>"; }; FFB0FF722E841042009EDEAC /* WeekdaySelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekdaySelectionView.swift; sourceTree = "<group>"; };
FFB1C98A2C10255100B154A7 /* TournamentBroadcastRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentBroadcastRowView.swift; sourceTree = "<group>"; }; FFB1C98A2C10255100B154A7 /* TournamentBroadcastRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentBroadcastRowView.swift; sourceTree = "<group>"; };
@ -1341,6 +1349,7 @@
C49771DE2DC25F04005CD239 /* Badge+Extensions.swift */, C49771DE2DC25F04005CD239 /* Badge+Extensions.swift */,
C49771DF2DC25F04005CD239 /* SpinDrawable+Extensions.swift */, C49771DF2DC25F04005CD239 /* SpinDrawable+Extensions.swift */,
C49772022DC260D3005CD239 /* Round+Extensions.swift */, C49772022DC260D3005CD239 /* Round+Extensions.swift */,
FFA97C9D2E8A7C080089EA22 /* View+Extensions.swift */,
); );
path = Extensions; path = Extensions;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1866,6 +1875,7 @@
FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */, FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */,
FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */, FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */,
FF8E52332DF01D6100099B75 /* EventStatusView.swift */, FF8E52332DF01D6100099B75 /* EventStatusView.swift */,
FFA97C8C2E8A59D00089EA22 /* TournamentPickerView.swift */,
); );
name = Event; name = Event;
path = Cashier/Event; path = Cashier/Event;
@ -2346,6 +2356,7 @@
FF5BAF6E2BE0B3C8008B4B7E /* FederalDataViewModel.swift in Sources */, FF5BAF6E2BE0B3C8008B4B7E /* FederalDataViewModel.swift in Sources */,
FF3F74FF2B91A2D4004CFE0E /* AgendaDestination.swift in Sources */, FF3F74FF2B91A2D4004CFE0E /* AgendaDestination.swift in Sources */,
FF3795622B9396D0004EA093 /* PadelClubApp.xcdatamodeld in Sources */, FF3795622B9396D0004EA093 /* PadelClubApp.xcdatamodeld in Sources */,
FFA97CA02E8A7C080089EA22 /* View+Extensions.swift in Sources */,
FFCFC0162BBC5A4C00B82851 /* SetInputView.swift in Sources */, FFCFC0162BBC5A4C00B82851 /* SetInputView.swift in Sources */,
FFF03C942BD91D0C00B516FC /* ButtonValidateView.swift in Sources */, FFF03C942BD91D0C00B516FC /* ButtonValidateView.swift in Sources */,
FF5D0D892BB4935C005CB568 /* ClubRowView.swift in Sources */, FF5D0D892BB4935C005CB568 /* ClubRowView.swift in Sources */,
@ -2434,6 +2445,7 @@
FFF527D62BC6DDD000FF4EF2 /* MatchScheduleEditorView.swift in Sources */, FFF527D62BC6DDD000FF4EF2 /* MatchScheduleEditorView.swift in Sources */,
FFC91AF92BD6A09100B29808 /* FortuneWheelView.swift in Sources */, FFC91AF92BD6A09100B29808 /* FortuneWheelView.swift in Sources */,
FFE8B5C82DAA390900BDE966 /* StripeValidationService.swift in Sources */, FFE8B5C82DAA390900BDE966 /* StripeValidationService.swift in Sources */,
FFA97C8D2E8A59D00089EA22 /* TournamentPickerView.swift in Sources */,
C493B37E2C10AD3600862481 /* LoadingViewModifier.swift in Sources */, C493B37E2C10AD3600862481 /* LoadingViewModifier.swift in Sources */,
FF089EBD2BB0287D00F0AEC7 /* PlayerView.swift in Sources */, FF089EBD2BB0287D00F0AEC7 /* PlayerView.swift in Sources */,
FF967D032BAEF0C000A9A3BD /* MatchDetailView.swift in Sources */, FF967D032BAEF0C000A9A3BD /* MatchDetailView.swift in Sources */,
@ -2613,6 +2625,7 @@
FF4CBFBF2C996C0600151637 /* SetInputView.swift in Sources */, FF4CBFBF2C996C0600151637 /* SetInputView.swift in Sources */,
FF4CBFC02C996C0600151637 /* ButtonValidateView.swift in Sources */, FF4CBFC02C996C0600151637 /* ButtonValidateView.swift in Sources */,
FF4CBFC12C996C0600151637 /* ClubRowView.swift in Sources */, FF4CBFC12C996C0600151637 /* ClubRowView.swift in Sources */,
FFA97C9E2E8A7C080089EA22 /* View+Extensions.swift in Sources */,
FF4CBFC22C996C0600151637 /* ClubDetailView.swift in Sources */, FF4CBFC22C996C0600151637 /* ClubDetailView.swift in Sources */,
FF4CBFC32C996C0600151637 /* GroupStageCallingView.swift in Sources */, FF4CBFC32C996C0600151637 /* GroupStageCallingView.swift in Sources */,
FF4CBFC52C996C0600151637 /* CashierSettingsView.swift in Sources */, FF4CBFC52C996C0600151637 /* CashierSettingsView.swift in Sources */,
@ -2701,6 +2714,7 @@
FF4CC0102C996C0600151637 /* LoadingViewModifier.swift in Sources */, FF4CC0102C996C0600151637 /* LoadingViewModifier.swift in Sources */,
FF4CC0112C996C0600151637 /* PlayerView.swift in Sources */, FF4CC0112C996C0600151637 /* PlayerView.swift in Sources */,
FF4CC0122C996C0600151637 /* MatchDetailView.swift in Sources */, FF4CC0122C996C0600151637 /* MatchDetailView.swift in Sources */,
FFA97C8F2E8A59D00089EA22 /* TournamentPickerView.swift in Sources */,
FF4CC0142C996C0600151637 /* PlayerBlockView.swift in Sources */, FF4CC0142C996C0600151637 /* PlayerBlockView.swift in Sources */,
FF4CC0172C996C0600151637 /* PointView.swift in Sources */, FF4CC0172C996C0600151637 /* PointView.swift in Sources */,
FF4CC0182C996C0600151637 /* ClubHolder.swift in Sources */, FF4CC0182C996C0600151637 /* ClubHolder.swift in Sources */,
@ -2858,6 +2872,7 @@
FF70FB3E2C90584900129CC2 /* SetInputView.swift in Sources */, FF70FB3E2C90584900129CC2 /* SetInputView.swift in Sources */,
FF70FB3F2C90584900129CC2 /* ButtonValidateView.swift in Sources */, FF70FB3F2C90584900129CC2 /* ButtonValidateView.swift in Sources */,
FF70FB402C90584900129CC2 /* ClubRowView.swift in Sources */, FF70FB402C90584900129CC2 /* ClubRowView.swift in Sources */,
FFA97C9F2E8A7C080089EA22 /* View+Extensions.swift in Sources */,
FF70FB412C90584900129CC2 /* ClubDetailView.swift in Sources */, FF70FB412C90584900129CC2 /* ClubDetailView.swift in Sources */,
FF70FB422C90584900129CC2 /* GroupStageCallingView.swift in Sources */, FF70FB422C90584900129CC2 /* GroupStageCallingView.swift in Sources */,
FF70FB442C90584900129CC2 /* CashierSettingsView.swift in Sources */, FF70FB442C90584900129CC2 /* CashierSettingsView.swift in Sources */,
@ -2946,6 +2961,7 @@
FF70FB8F2C90584900129CC2 /* LoadingViewModifier.swift in Sources */, FF70FB8F2C90584900129CC2 /* LoadingViewModifier.swift in Sources */,
FF70FB902C90584900129CC2 /* PlayerView.swift in Sources */, FF70FB902C90584900129CC2 /* PlayerView.swift in Sources */,
FF70FB912C90584900129CC2 /* MatchDetailView.swift in Sources */, FF70FB912C90584900129CC2 /* MatchDetailView.swift in Sources */,
FFA97C8E2E8A59D00089EA22 /* TournamentPickerView.swift in Sources */,
FF70FB932C90584900129CC2 /* PlayerBlockView.swift in Sources */, FF70FB932C90584900129CC2 /* PlayerBlockView.swift in Sources */,
FF70FB962C90584900129CC2 /* PointView.swift in Sources */, FF70FB962C90584900129CC2 /* PointView.swift in Sources */,
FF70FB972C90584900129CC2 /* ClubHolder.swift in Sources */, FF70FB972C90584900129CC2 /* ClubHolder.swift in Sources */,

@ -0,0 +1,22 @@
//
// View+Extensions.swift
// PadelClub
//
// Created by Razmig Sarkissian on 29/09/2025.
//
import SwiftUI
extension View {
/// Runs a transform only on iOS 26+, otherwise returns self
@ViewBuilder
func ifAvailableiOS26<Content: View>(
@ViewBuilder transform: (Self) -> Content
) -> some View {
if #available(iOS 26.0, *) {
transform(self)
} else {
self
}
}
}

@ -660,6 +660,21 @@ struct UpdatePlannedDatesTip: Tip {
} }
} }
struct MergeTournamentTip: Tip {
var title: Text {
Text("Transfert de tournois")
}
var message: Text? {
Text("Vous pouvez transferer des tournois d'un autre événement dans celui-ci.")
}
var image: Image? {
Image(systemName: "square.and.arrow.down")
}
}
struct TipStyleModifier: ViewModifier { struct TipStyleModifier: ViewModifier {
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
var tint: Color? var tint: Color?

@ -15,6 +15,7 @@ struct EventTournamentsView: View {
let event: Event let event: Event
@State private var newTournament: Tournament? @State private var newTournament: Tournament?
@State private var mainTournament: Tournament? @State private var mainTournament: Tournament?
@State private var showTournamentPicker: Bool = false
var presentTournamentCreationView: Binding<Bool> { Binding( var presentTournamentCreationView: Binding<Bool> { Binding(
get: { newTournament != nil }, get: { newTournament != nil },
@ -122,13 +123,35 @@ struct EventTournamentsView: View {
} }
.toolbar { .toolbar {
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .topBarTrailing) {
BarButtonView("Ajouter un tournoi", icon: "plus.circle.fill") { BarButtonView("Importer un tournoi", icon: "square.and.arrow.down") {
let tournament = Tournament.newEmptyInstance() showTournamentPicker = true
newTournament = tournament }
}
if #available(iOS 26.0, *) {
ToolbarSpacer(placement: .topBarTrailing)
}
ToolbarItem(placement: .topBarTrailing) {
if #available(iOS 26.0, *) {
BarButtonView("Ajouter une indisponibilité", icon: "plus") {
let tournament = Tournament.newEmptyInstance()
newTournament = tournament
}
} else {
BarButtonView("Ajouter une indisponibilité", icon: "plus.circle.fill") {
let tournament = Tournament.newEmptyInstance()
newTournament = tournament
}
} }
} }
} }
.headerProminence(.increased) .headerProminence(.increased)
.sheet(isPresented: $showTournamentPicker, content: {
NavigationStack {
TournamentPickerView(event: event)
.environmentObject(dataStore)
}
})
.sheet(isPresented: presentTournamentCreationView) { .sheet(isPresented: presentTournamentCreationView) {
if let newTournament { if let newTournament {
NavigationStack { NavigationStack {

@ -0,0 +1,91 @@
//
// TournamentPickerView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 29/09/2025.
//
import SwiftUI
import LeStorage
import PadelClubData
import TipKit
struct TournamentPickerView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(\.dismiss) private var dismiss
let mergeTournamentTip = MergeTournamentTip()
let event: Event
@State private var selectedTournamentIds: Set<String> = Set()
@State private var shouldEraseEmptyEvents: Bool = false
var tournaments: [Tournament] {
dataStore.tournaments.filter({ $0.isDeleted == false && $0.event?.id != event.id }).sorted(by: \.startDate, order: .descending)
}
var body: some View {
List(selection: $selectedTournamentIds) {
Section {
TipView(mergeTournamentTip)
.tipStyle(tint: .green)
}
Section {
Toggle(isOn: $shouldEraseEmptyEvents) {
Text("Effacer les événements vides")
Text("Les événements qui n'ont plus de tournois seront effacés automatiquement.")
}
}
ForEach(tournaments) { tournament in
TournamentCellView(tournament: tournament).tag(tournament.id)
}
}
.environment(\.editMode, Binding.constant(EditMode.active))
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Annuler") {
dismiss()
}
}
ToolbarItem(placement: .topBarTrailing) {
ButtonValidateView {
_transferTournaments()
dismiss()
}
.disabled(selectedTournamentIds.isEmpty)
}
}
.navigationTitle("Transfert de tournois")
}
private func _transferTournaments() {
let tournaments = tournaments
var eventIdsToCheck = Set<String>()
var tournamentsToSave = [Tournament]()
selectedTournamentIds.forEach { id in
if let tournament = tournaments.first(where: { $0.id == id }) {
if let eventId = tournament.event{
eventIdsToCheck.insert(eventId)
}
tournament.event = event.id
tournamentsToSave.append(tournament)
}
}
dataStore.tournaments.addOrUpdate(contentOfs: tournamentsToSave)
if shouldEraseEmptyEvents {
var eventsToDelete = [Event]()
eventIdsToCheck.forEach { eventId in
if let eventToCheck = dataStore.events.first(where: { $0.id == eventId }) {
if eventToCheck.tournaments.isEmpty && shouldEraseEmptyEvents {
eventsToDelete.append(eventToCheck)
}
}
}
dataStore.events.delete(contentOfs: eventsToDelete)
}
}
}

@ -22,23 +22,14 @@ struct BarButtonView: View {
Button(action: { Button(action: {
action() action()
}) { }) {
Image(systemName: icon) if #available(iOS 26.0, *) {
.resizable() Label(accessibilityLabel, systemImage: icon)
.scaledToFit() } else {
.frame(minHeight: 28) Image(systemName: icon)
.resizable()
/* .scaledToFit()
Label { .frame(minHeight: 32)
Text(accessibilityLabel) }
} icon: {
Image(systemName: icon)
.resizable()
.scaledToFit()
.frame(minHeight: 36)
}
.labelStyle(.iconOnly)
//todo: resizing not working when label used
*/
} }
} }
} }

@ -256,5 +256,10 @@ struct GroupStagesView: View {
.environment(tournament) .environment(tournament)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
} }
} }

@ -420,7 +420,13 @@ struct MatchDetailView: View {
.navigationTitle(match.matchTitle()) .navigationTitle(match.matchTitle())
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
if let tournament = match.currentTournament() {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
}
} }
var quickLookHeader: some View { var quickLookHeader: some View {

@ -383,17 +383,3 @@ struct TournamentSubscriptionView: View {
} }
} }
extension View {
/// Runs a transform only on iOS 26+, otherwise returns self
@ViewBuilder
func ifAvailableiOS26<Content: View>(
@ViewBuilder transform: (Self) -> Content
) -> some View {
if #available(iOS 26.0, *) {
transform(self)
} else {
self
}
}
}

@ -111,8 +111,14 @@ struct CourtAvailabilitySettingsView: View {
} }
.toolbar { .toolbar {
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .topBarTrailing) {
BarButtonView("Ajouter une indisponibilité", icon: "plus.circle.fill") { if #available(iOS 26.0, *) {
showingPopover = true BarButtonView("Ajouter une indisponibilité", icon: "plus") {
showingPopover = true
}
} else {
BarButtonView("Ajouter une indisponibilité", icon: "plus.circle.fill") {
showingPopover = true
}
} }
} }
} }

@ -297,5 +297,12 @@ struct LoserRoundsView: View {
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationTitle(upperBracketRound.correspondingLoserRoundTitle) .navigationTitle(upperBracketRound.correspondingLoserRoundTitle)
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
if let tournament = upperBracketRound.round.tournamentObject() {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
}
} }
} }

@ -48,11 +48,17 @@ struct RoundsView: View {
case .some(let selectedRound): case .some(let selectedRound):
RoundView(upperRound: selectedRound).id(selectedRound.id) RoundView(upperRound: selectedRound).id(selectedRound.id)
.navigationTitle(selectedRound.round.roundTitle()) .navigationTitle(selectedRound.round.roundTitle())
} }
} }
.environment(\.isEditingTournamentSeed, $isEditingTournamentSeed) .environment(\.isEditingTournamentSeed, $isEditingTournamentSeed)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
} }
} }

@ -244,6 +244,13 @@ struct EditScoreView: View {
matchDescriptor.setDescriptors.removeAll() matchDescriptor.setDescriptors.removeAll()
matchDescriptor.addNewSet() matchDescriptor.addNewSet()
} }
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
if let tournament = matchDescriptor.match?.currentTournament() {
$0.navigationBarTitle(tournament.tournamentTitle())
}
}
}
} }
func save() { func save() {

@ -292,6 +292,13 @@ struct FollowUpMatchView: View {
} }
} }
} }
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
if let tournament = match?.currentTournament() {
$0.navigationBarTitle(tournament.tournamentTitle())
}
}
}
.onChange(of: readyMatches) { .onChange(of: readyMatches) {
dismissWhenPresentFollowUpMatchIsDismissed = true dismissWhenPresentFollowUpMatchIsDismissed = true
if autoDismiss { if autoDismiss {

@ -84,6 +84,24 @@ struct BroadcastView: View {
.tipStyle(tint: nil) .tipStyle(tint: nil)
} }
if let shareURL = tournament.shareURL(.info) {
Section {
Link(destination: shareURL) {
Text(shareURL.absoluteString)
}
} header: {
Text("Page d'information")
} footer: {
HStack {
CopyPasteButtonView(pasteValue: shareURL.absoluteString)
Spacer()
ShareLink(item: shareURL) {
Label("Partager", systemImage: "square.and.arrow.up")
}
}
}
}
if let url = tournament.shareURL(.clubBroadcast) { if let url = tournament.shareURL(.clubBroadcast) {
Section { Section {
Link(destination: url) { Link(destination: url) {
@ -113,6 +131,21 @@ struct BroadcastView: View {
} }
} }
Section {
let links : [PageLink] = [.info, .teams, .summons, .groupStages, .matches, .rankings, .broadcast, .clubBroadcast]
Picker(selection: $pageLink) {
ForEach(links) { pageLink in
Text(pageLink.localizedLabel()).tag(pageLink)
}
} label: {
Text("Page à partager")
}
.pickerStyle(.menu)
actionForURL(title: "Partager la page '" + pageLink.localizedLabel() + "'", url: tournament.shareURL(pageLink))
} header: {
Text("Lien du tournoi à partager")
}
if tournament.isPrivate == false { if tournament.isPrivate == false {
Section { Section {
@ -300,24 +333,9 @@ struct BroadcastView: View {
} }
} }
.toolbar(content: { .toolbar(content: {
if StoreCenter.main.userId != nil, tournament.isPrivate == false, tournament.club() != nil { if StoreCenter.main.userId != nil, tournament.club() != nil {
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .topBarTrailing) {
Menu { Menu {
Section {
let links : [PageLink] = [.info, .teams, .summons, .groupStages, .matches, .rankings, .broadcast, .clubBroadcast]
Picker(selection: $pageLink) {
ForEach(links) { pageLink in
Text(pageLink.localizedLabel()).tag(pageLink)
}
} label: {
Text("Choisir la page à partager")
}
.pickerStyle(.menu)
actionForURL(title: "Partager la page '" + pageLink.localizedLabel() + "'", url: tournament.shareURL(pageLink))
} header: {
Text("Lien du tournoi à partager")
}
#if DEBUG #if DEBUG
Section { Section {
actionForURL(title: "La Boutique", url: URLs.main.url.appending(path: "shop")) actionForURL(title: "La Boutique", url: URLs.main.url.appending(path: "shop"))
@ -344,6 +362,11 @@ struct BroadcastView: View {
}) })
.headerProminence(.increased) .headerProminence(.increased)
.navigationTitle("Publication") .navigationTitle("Publication")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.sheet(item: $urlToShow) { urlToShow in .sheet(item: $urlToShow) { urlToShow in

@ -485,6 +485,11 @@ struct InscriptionManagerView: View {
} }
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Inscriptions") .navigationTitle("Inscriptions")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.onChange(of: tournament.hideTeamsWeight) { .onChange(of: tournament.hideTeamsWeight) {
_save() _save()

@ -169,6 +169,11 @@ struct PrintSettingsView: View {
} }
} }
.navigationTitle("Imprimer") .navigationTitle("Imprimer")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.sheet(isPresented: $presentShareView) { .sheet(isPresented: $presentShareView) {

@ -358,6 +358,11 @@ struct RegistrationSetupView: View {
.toolbarRole(.editor) .toolbarRole(.editor)
.headerProminence(.increased) .headerProminence(.increased)
.navigationTitle("Inscription en ligne") .navigationTitle("Inscription en ligne")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationBarBackButtonHidden(hasChanges) .navigationBarBackButtonHidden(hasChanges)

@ -412,6 +412,12 @@ struct TableStructureView: View {
} }
.navigationTitle("Structure") .navigationTitle("Structure")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
} }

@ -137,6 +137,11 @@ struct TournamentCallView: View {
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Convocations") .navigationTitle("Convocations")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
} }
} }

@ -166,6 +166,11 @@ struct TournamentCashierView: View {
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationTitle(tournament.isFree() ? "Présence" : "Encaissement") .navigationTitle(tournament.isFree() ? "Présence" : "Encaissement")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
} else { } else {
Text("no store") Text("no store")
} }

@ -158,6 +158,11 @@ struct TournamentRankView: View {
} }
} }
.navigationTitle("Classement") .navigationTitle("Classement")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.toolbar { .toolbar {

@ -101,6 +101,12 @@ struct TournamentScheduleView: View {
.toolbarRole(.editor) .toolbarRole(.editor)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Horaires et formats") .navigationTitle("Horaires et formats")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
} }
} }

@ -81,6 +81,12 @@ struct TournamentSettingsView: View {
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Réglages du tournoi") .navigationTitle("Réglages du tournoi")
.ifAvailableiOS26 {
if #available(iOS 26.0, *) {
$0.navigationSubtitle(tournament.tournamentTitle())
}
}
} }
} }

@ -240,15 +240,29 @@ struct TournamentView: View {
} }
Menu { Menu {
NavigationLink(value: Screen.event) { Button {
navigation.path.append(Screen.event)
} label: {
Text("Événement") Text("Événement")
if let tournamentCount = tournament.eventObject()?.confirmedTournaments().count {
Text(tournamentCount.formatted() + " tournoi" + tournamentCount.pluralSuffix)
.foregroundStyle(.secondary)
}
} }
NavigationLink(value: Screen.settings) { Button {
navigation.path.append(Screen.settings)
} label: {
Text("Tournoi") Text("Tournoi")
Text("Inscription en ligne, pistes, formats")
.foregroundStyle(.secondary)
} }
NavigationLink(value: Screen.structure) { Button {
navigation.path.append(Screen.structure)
} label: {
LabelStructure() LabelStructure()
Text("Poules, tableau, qualifiés sortants")
.foregroundStyle(.secondary)
} }
Divider() Divider()

Loading…
Cancel
Save