diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index d0d90e0..6607922 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -79,7 +79,6 @@ FF1162872BD004AD000C4809 /* EditingTeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162862BD004AD000C4809 /* EditingTeamView.swift */; }; FF11628A2BD05247000C4809 /* DateUpdateManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162892BD05247000C4809 /* DateUpdateManagerView.swift */; }; FF11628C2BD05267000C4809 /* LoserRoundStepScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF11628B2BD05267000C4809 /* LoserRoundStepScheduleEditorView.swift */; }; - FF135BF92C2FCB8300C9247A /* LoserGroupStageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF135BF82C2FCB8300C9247A /* LoserGroupStageSettingsView.swift */; }; FF1CBC1B2BB53D1F0036DAAB /* FederalTournament.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */; }; FF1CBC1D2BB53DC10036DAAB /* Calendar+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */; }; FF1CBC1F2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */; }; @@ -147,6 +146,7 @@ FF5DA19B2BB9662200A33061 /* TournamentSeedEditing.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA19A2BB9662200A33061 /* TournamentSeedEditing.swift */; }; FF6087EA2BE25EF1004E1E47 /* TournamentStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6087E92BE25EF1004E1E47 /* TournamentStatusView.swift */; }; FF6087EC2BE26A2F004E1E47 /* BroadcastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6087EB2BE26A2F004E1E47 /* BroadcastView.swift */; }; + FF6525C32C8C61B400B9498E /* LoserBracketFromGroupStageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6525C22C8C61B400B9498E /* LoserBracketFromGroupStageView.swift */; }; FF663FBE2BE019EC0031AE83 /* TournamentFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF663FBD2BE019EC0031AE83 /* TournamentFilterView.swift */; }; FF6EC8F72B94773200EA7F5A /* RowButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */; }; FF6EC8FB2B94788600EA7F5A /* TournamentButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FA2B94788600EA7F5A /* TournamentButtonView.swift */; }; @@ -162,266 +162,269 @@ FF70916A2B90F95E00AB08DA /* DateBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091692B90F95E00AB08DA /* DateBoxView.swift */; }; FF70916C2B91005400AB08DA /* TournamentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF70916B2B91005400AB08DA /* TournamentView.swift */; }; FF70916E2B9108C600AB08DA /* InscriptionManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF70916D2B9108C600AB08DA /* InscriptionManagerView.swift */; }; - FF8044B42C90379300A49A52 /* UserCreationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D862B7BA36D00ADC637 /* UserCreationView.swift */; }; - FF8044B52C90379300A49A52 /* TabDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091652B90F0B000AB08DA /* TabDestination.swift */; }; - FF8044B62C90379300A49A52 /* CashierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267F72BCE78C70080F940 /* CashierView.swift */; }; - FF8044B72C90379300A49A52 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F263E2BAD7D5C00650388 /* Event.swift */; }; - FF8044B82C90379300A49A52 /* PlayerHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D30522BD94E2E00F2B93D /* PlayerHolder.swift */; }; - FF8044B92C90379300A49A52 /* LoserRoundStepScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF11628B2BD05267000C4809 /* LoserRoundStepScheduleEditorView.swift */; }; - FF8044BA2C90379300A49A52 /* ClubCourtSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF53FBB72BFB302B0051D4C3 /* ClubCourtSetupView.swift */; }; - FF8044BB2C90379300A49A52 /* Patcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B3A1542C2581DA0078EAA8 /* Patcher.swift */; }; - FF8044BC2C90379300A49A52 /* FileImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBE2BB0B14600F0AEC7 /* FileImportView.swift */; }; - FF8044BD2C90379300A49A52 /* StepperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D9E2B7D0BCE00ADC637 /* StepperView.swift */; }; - FF8044BE2C90379300A49A52 /* RoundsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC83D4E2BB807D100750834 /* RoundsView.swift */; }; - FF8044BF2C90379300A49A52 /* FederalTournament.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */; }; - FF8044C02C90379300A49A52 /* TournamentInitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26402BADFC8700650388 /* TournamentInitView.swift */; }; - FF8044C12C90379300A49A52 /* SubscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D892B7BBB6500ADC637 /* SubscriptionView.swift */; }; - FF8044C22C90379300A49A52 /* ClubsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5562BAB3AED00FD8220 /* ClubsView.swift */; }; - FF8044C32C90379300A49A52 /* ImagePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE103112C366E5900684FC9 /* ImagePickerView.swift */; }; - FF8044C42C90379300A49A52 /* MatchTypeSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F264E2BAE0B9600650388 /* MatchTypeSelectionView.swift */; }; - FF8044C52C90379300A49A52 /* MatchSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D052BAF3C4200A9A3BD /* MatchSetupView.swift */; }; - FF8044C62C90379300A49A52 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6B42B9248200002987F /* NetworkManager.swift */; }; - FF8044C72C90379300A49A52 /* EventLinksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2B6F5D2C036A1400835EE7 /* EventLinksView.swift */; }; - FF8044C82C90379300A49A52 /* SeedInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB9C8742BBADDF700A0EF4F /* SeedInterval.swift */; }; - FF8044C92C90379300A49A52 /* TournamentClubSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE02BD0EB9000A86CF8 /* TournamentClubSettingsView.swift */; }; - FF8044CA2C90379300A49A52 /* GroupStageTeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF065B2BBD2657009D6715 /* GroupStageTeamView.swift */; }; - FF8044CB2C90379300A49A52 /* RoundSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA1922BB9279B00A33061 /* RoundSettingsView.swift */; }; - FF8044CC2C90379300A49A52 /* SupportButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE2D2E12C231BEE00D0C7BE /* SupportButtonView.swift */; }; - FF8044CD2C90379300A49A52 /* TournamentBroadcastRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB1C98A2C10255100B154A7 /* TournamentBroadcastRowView.swift */; }; - FF8044CE2C90379300A49A52 /* TeamWeightView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADE2BD0CE0A00A86CF8 /* TeamWeightView.swift */; }; - FF8044CF2C90379300A49A52 /* SeedsCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9268002BCE94920080F940 /* SeedsCallingView.swift */; }; - FF8044D02C90379300A49A52 /* CallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9268082BCEDC2C0080F940 /* CallView.swift */; }; - FF8044D12C90379300A49A52 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D732BB41DF8005CB568 /* Color+Extensions.swift */; }; - FF8044D22C90379300A49A52 /* EditSharingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE1030F2C366DCD00684FC9 /* EditSharingView.swift */; }; - FF8044D32C90379300A49A52 /* TournamentCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091672B90F79F00AB08DA /* TournamentCellView.swift */; }; - FF8044D42C90379300A49A52 /* Sequence+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC9032B9479F500EA7F5A /* Sequence+Extensions.swift */; }; - FF8044D52C90379300A49A52 /* CashierDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267F92BCE78EB0080F940 /* CashierDetailView.swift */; }; - FF8044D62C90379300A49A52 /* EventClubSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */; }; - FF8044D72C90379300A49A52 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DB22B86387500ADC637 /* AccountView.swift */; }; - FF8044D82C90379300A49A52 /* PlayersWithoutContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCEDA4B2C2C08EA00F8C0F2 /* PlayersWithoutContactView.swift */; }; - FF8044D92C90379300A49A52 /* TeamsCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCD16B22C3E5E590092707B /* TeamsCallingView.swift */; }; - FF8044DA2C90379300A49A52 /* Calendar+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */; }; - FF8044DB2C90379300A49A52 /* TeamScore.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CEF2BAECC0A00A9A3BD /* TeamScore.swift */; }; - FF8044DC2C90379300A49A52 /* EditablePlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162822BCFBE4E000C4809 /* EditablePlayerView.swift */; }; - FF8044DD2C90379300A49A52 /* PlayerDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162842BD00279000C4809 /* PlayerDetailView.swift */; }; - FF8044DE2C90379300A49A52 /* ListRowViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D752BB428B2005CB568 /* ListRowViewModifier.swift */; }; - FF8044DF2C90379300A49A52 /* PresentationContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FF2B94794700EA7F5A /* PresentationContext.swift */; }; - FF8044E02C90379300A49A52 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */; }; - FF8044E12C90379300A49A52 /* SwiftParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0EC51D2BB16F680056B6D1 /* SwiftParser.swift */; }; - FF8044E22C90379300A49A52 /* ChangePasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DA82B85F82100ADC637 /* ChangePasswordView.swift */; }; - FF8044E32C90379300A49A52 /* RoundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC83D502BB8087E00750834 /* RoundView.swift */; }; - FF8044E42C90379300A49A52 /* RowButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */; }; - FF8044E52C90379300A49A52 /* SendToAllView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2EFBEF2BDE295E0049CE3B /* SendToAllView.swift */; }; - FF8044E62C90379300A49A52 /* EventCreationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F263A2BAD528600650388 /* EventCreationView.swift */; }; - FF8044E72C90379300A49A52 /* LoserGroupStageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF135BF82C2FCB8300C9247A /* LoserGroupStageSettingsView.swift */; }; - FF8044E82C90379300A49A52 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC1E1072BAC29FC008D6F59 /* LocationManager.swift */; }; - FF8044E92C90379300A49A52 /* CapsuleViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C01D972C481C0C0059087C /* CapsuleViewModifier.swift */; }; - FF8044EA2C90379300A49A52 /* BroadcastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6087EB2BE26A2F004E1E47 /* BroadcastView.swift */; }; - FF8044EB2C90379300A49A52 /* SchedulerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF964542BC266CF00EEF017 /* SchedulerView.swift */; }; - FF8044EC2C90379300A49A52 /* PadelClubButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA1B1282BB71773006CE248 /* PadelClubButtonView.swift */; }; - FF8044ED2C90379300A49A52 /* TournamentSeedEditing.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA19A2BB9662200A33061 /* TournamentSeedEditing.swift */; }; - FF8044EE2C90379300A49A52 /* TournamentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF70916B2B91005400AB08DA /* TournamentView.swift */; }; - FF8044EF2C90379300A49A52 /* OngoingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D30552BD95B1100F2B93D /* OngoingView.swift */; }; - FF8044F02C90379300A49A52 /* CreateClubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5542BAB36DD00FD8220 /* CreateClubView.swift */; }; - FF8044F12C90379300A49A52 /* APICallsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4607A7C2C04DDE2004CB781 /* APICallsListView.swift */; }; - FF8044F22C90379300A49A52 /* NetworkFederalService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC1E1092BAC2A77008D6F59 /* NetworkFederalService.swift */; }; - FF8044F32C90379300A49A52 /* DurationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AEE2BD1AE9400A86CF8 /* DurationSettingsView.swift */; }; - FF8044F42C90379300A49A52 /* AppScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AEC2BD1513700A86CF8 /* AppScreen.swift */; }; - FF8044F52C90379300A49A52 /* CourtView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91B022BD85E2400B29808 /* CourtView.swift */; }; - FF8044F62C90379300A49A52 /* PointSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC00D2BBC3D4600B82851 /* PointSelectionView.swift */; }; - FF8044F72C90379300A49A52 /* TeamRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EB52BB00A3800F0AEC7 /* TeamRowView.swift */; }; - FF8044F82C90379300A49A52 /* ContactManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF92680A2BCEE3E10080F940 /* ContactManager.swift */; }; - FF8044F92C90379300A49A52 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40CD2F22C412681000DBD9A /* AppDelegate.swift */; }; - FF8044FA2C90379300A49A52 /* SubscriptionInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF0252BD80AE80077B5AA /* SubscriptionInfoView.swift */; }; - FF8044FB2C90379300A49A52 /* EditScoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0012BBC39A600B82851 /* EditScoreView.swift */; }; - FF8044FC2C90379300A49A52 /* TournamentOrganizerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091612B90F04300AB08DA /* TournamentOrganizerView.swift */; }; - FF8044FD2C90379300A49A52 /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF92680C2BCEE5EA0080F940 /* NetworkMonitor.swift */; }; - FF8044FE2C90379300A49A52 /* TournamentRunningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CF52BAED51600A9A3BD /* TournamentRunningView.swift */; }; - FF8044FF2C90379300A49A52 /* TournamentDatePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F264A2BAE0B4100650388 /* TournamentDatePickerView.swift */; }; - FF8045002C90379300A49A52 /* CourtAvailabilitySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF116E22BD2AF4800A33B06 /* CourtAvailabilitySettingsView.swift */; }; - FF8045012C90379300A49A52 /* ConfirmButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE8C2BF2C7601E80046B243 /* ConfirmButtonView.swift */; }; - FF8045022C90379300A49A52 /* PasswordField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FC2E262C2AABC90021F3BF /* PasswordField.swift */; }; - FF8045032C90379300A49A52 /* MatchRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CFF2BAEEF6400A9A3BD /* MatchRowView.swift */; }; - FF8045042C90379300A49A52 /* Locale+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44B79102BBDA63A00906534 /* Locale+Extensions.swift */; }; - FF8045052C90379300A49A52 /* HtmlService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B732BFA00FC000B4573 /* HtmlService.swift */; }; - FF8045062C90379300A49A52 /* GroupStage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CE72BAEC70100A9A3BD /* GroupStage.swift */; }; - FF8045072C90379300A49A52 /* TournamentCashierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162802BCF945C000C4809 /* TournamentCashierView.swift */; }; - FF8045082C90379300A49A52 /* StoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D8D2B7BBBEC00ADC637 /* StoreManager.swift */; }; - FF8045092C90379300A49A52 /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BA2B9256D50002987F /* SearchViewModel.swift */; }; - FF80450A2C90379300A49A52 /* PlayerRegistration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CF12BAECC0B00A9A3BD /* PlayerRegistration.swift */; }; - FF80450B2C90379300A49A52 /* ImportedPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BE2B92577A0002987F /* ImportedPlayerView.swift */; }; - FF80450C2C90379300A49A52 /* EditingTeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162862BD004AD000C4809 /* EditingTeamView.swift */; }; - FF80450D2C90379300A49A52 /* NetworkManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC9052B947A1000EA7F5A /* NetworkManagerError.swift */; }; - FF80450E2C90379300A49A52 /* Tournament.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D592B6D383C00ADC637 /* Tournament.swift */; }; - FF80450F2C90379300A49A52 /* TournamentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FC2E2A2C2C0E4D0021F3BF /* TournamentStore.swift */; }; - FF8045102C90379300A49A52 /* LoserRoundSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5647122C0B6F380081F995 /* LoserRoundSettingsView.swift */; }; - FF8045112C90379300A49A52 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3795652B9399AA004EA093 /* Persistence.swift */; }; - FF8045122C90379300A49A52 /* CloseDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCF76062C3BE9BC006C8C3D /* CloseDatePicker.swift */; }; - FF8045132C90379300A49A52 /* BarButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DF49A2BD8D23900822FA0 /* BarButtonView.swift */; }; - FF8045142C90379300A49A52 /* PlanningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF9644F2BC25E3700EEF017 /* PlanningView.swift */; }; - FF8045152C90379300A49A52 /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CEB2BAECB9900A9A3BD /* Match.swift */; }; - FF8045162C90379300A49A52 /* TournamentLevelPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26492BAE0B4100650388 /* TournamentLevelPickerView.swift */; }; - FF8045172C90379300A49A52 /* FederalTournamentHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC212BB53E590036DAAB /* FederalTournamentHolder.swift */; }; - FF8045182C90379300A49A52 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D5D2B6D38EC00ADC637 /* DataStore.swift */; }; - FF8045192C90379300A49A52 /* SetDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC01B2BBC5AAA00B82851 /* SetDescriptor.swift */; }; - FF80451A2C90379300A49A52 /* TeamHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AD72BD0C10F00A86CF8 /* TeamHeaderView.swift */; }; - FF80451B2C90379300A49A52 /* OrganizedTournamentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF82CFC42B911F5B00B0CAF2 /* OrganizedTournamentView.swift */; }; - FF80451C2C90379300A49A52 /* RoundScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF964562BC26B3400EEF017 /* RoundScheduleEditorView.swift */; }; - FF80451D2C90379300A49A52 /* EventListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */; }; - FF80451E2C90379300A49A52 /* TournamentConfiguratorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */; }; - FF80451F2C90379300A49A52 /* ClubImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC1E10B2BAC7FB0008D6F59 /* ClubImportView.swift */; }; - FF8045202C90379300A49A52 /* UnderlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF558C622C6CDD020071F9AE /* UnderlineView.swift */; }; - FF8045212C90379300A49A52 /* MatchScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3B60A22BC49BBC008C2E66 /* MatchScheduler.swift */; }; - FF8045222C90379300A49A52 /* CallMessageCustomizationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162792BCF8109000C4809 /* CallMessageCustomizationView.swift */; }; - FF8045232C90379300A49A52 /* TournamentStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6087E92BE25EF1004E1E47 /* TournamentStatusView.swift */; }; - FF8045242C90379300A49A52 /* MatchTeamDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADA2BD0C2D000A86CF8 /* MatchTeamDetailView.swift */; }; - FF8045252C90379300A49A52 /* GenericDestinationPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA1942BB927E800A33061 /* GenericDestinationPickerView.swift */; }; - FF8045262C90379300A49A52 /* DateInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF116E02BD2A9B600A33B06 /* DateInterval.swift */; }; - FF8045272C90379300A49A52 /* TableStructureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26532BAE1E4400650388 /* TableStructureView.swift */; }; - FF8045282C90379300A49A52 /* Purchase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45BAE432BCA753E002EEC8A /* Purchase.swift */; }; - FF8045292C90379300A49A52 /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FD2B94792300EA7F5A /* Screen.swift */; }; - FF80452A2C90379300A49A52 /* Round.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CED2BAECBD700A9A3BD /* Round.swift */; }; - FF80452B2C90379300A49A52 /* FederalDataViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5BAF6D2BE0B3C8008B4B7E /* FederalDataViewModel.swift */; }; - FF80452C2C90379300A49A52 /* AgendaDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3F74FE2B91A2D4004CFE0E /* AgendaDestination.swift */; }; - FF80452D2C90379300A49A52 /* PadelClubApp.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FF3795602B9396D0004EA093 /* PadelClubApp.xcdatamodeld */; }; - FF80452E2C90379300A49A52 /* SetInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0152BBC5A4C00B82851 /* SetInputView.swift */; }; - FF80452F2C90379300A49A52 /* ButtonValidateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF03C932BD91D0C00B516FC /* ButtonValidateView.swift */; }; - FF8045302C90379300A49A52 /* ClubRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D882BB4935C005CB568 /* ClubRowView.swift */; }; - FF8045312C90379300A49A52 /* ClubDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5502BAB351300FD8220 /* ClubDetailView.swift */; }; - FF8045322C90379300A49A52 /* GroupStageCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9268022BCE94A30080F940 /* GroupStageCallingView.swift */; }; - FF8045332C90379300A49A52 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF0432BE286780077B5AA /* Key.swift */; }; - FF8045342C90379300A49A52 /* CashierSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF11627C2BCF941A000C4809 /* CashierSettingsView.swift */; }; - FF8045352C90379300A49A52 /* LoserRoundScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFFCDE0D2BCC833600317DEF /* LoserRoundScheduleEditorView.swift */; }; - FF8045362C90379300A49A52 /* Club.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D622B6D3D6500ADC637 /* Club.swift */; }; - FF8045372C90379300A49A52 /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC90A2B947AC000EA7F5A /* Array+Extensions.swift */; }; - FF8045382C90379300A49A52 /* ToolboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB82B90EFD70061EFF9 /* ToolboxView.swift */; }; - FF8045392C90379300A49A52 /* Alphabet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8E1CE52C006E0200184680 /* Alphabet.swift */; }; - FF80453A2C90379300A49A52 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACD82B923F3C008466FA /* String+Extensions.swift */; }; - FF80453B2C90379300A49A52 /* GroupStageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCB74122C4625BB008384D0 /* GroupStageSettingsView.swift */; }; - FF80453C2C90379300A49A52 /* TournamentGeneralSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE42BD0EBB800A86CF8 /* TournamentGeneralSettingsView.swift */; }; - FF80453D2C90379300A49A52 /* LoserRoundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC2DCB12BBE75D40046DB9F /* LoserRoundView.swift */; }; - FF80453E2C90379300A49A52 /* AddTeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF90FC1C2C44FB3E009339B2 /* AddTeamView.swift */; }; - FF80453F2C90379300A49A52 /* PlayerPayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267FB2BCE84870080F940 /* PlayerPayView.swift */; }; - FF8045402C90379300A49A52 /* PlanningByCourtView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2B51542C7A4DAF00FFF126 /* PlanningByCourtView.swift */; }; - FF8045412C90379300A49A52 /* FileImportManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA6D7842BB0B795003A31F3 /* FileImportManager.swift */; }; - FF8045422C90379300A49A52 /* TournamentButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FA2B94788600EA7F5A /* TournamentButtonView.swift */; }; - FF8045432C90379300A49A52 /* FederalPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACCC2B92367B008466FA /* FederalPlayer.swift */; }; - FF8045442C90379300A49A52 /* NavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF065F2BBD9F6D009D6715 /* NavigationViewModel.swift */; }; - FF8045452C90379300A49A52 /* FixedWidthInteger+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC9082B947A5300EA7F5A /* FixedWidthInteger+Extensions.swift */; }; - FF8045462C90379300A49A52 /* ImportedPlayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D30502BD94E1000F2B93D /* ImportedPlayer+Extensions.swift */; }; - FF8045472C90379300A49A52 /* ClubSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC1E1032BAC28C6008D6F59 /* ClubSearchView.swift */; }; - FF8045482C90379300A49A52 /* PlayerPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBA2BB0120700F0AEC7 /* PlayerPopoverView.swift */; }; - FF8045492C90379300A49A52 /* InscriptionManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF70916D2B9108C600AB08DA /* InscriptionManagerView.swift */; }; - FF80454A2C90379300A49A52 /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF82CFC82B9132AF00B0CAF2 /* ActivityView.swift */; }; - FF80454B2C90379300A49A52 /* MySortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C722BB2CFE900F1E467 /* MySortDescriptor.swift */; }; - FF80454C2C90379300A49A52 /* CalendarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D8A2BB4D1E3005CB568 /* CalendarView.swift */; }; - FF80454D2C90379300A49A52 /* FederalTournamentSearchScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */; }; - FF80454E2C90379300A49A52 /* TournamentFieldsManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26462BAE0ACB00650388 /* TournamentFieldsManagerView.swift */; }; - FF80454F2C90379300A49A52 /* PrintSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B812BFA0124000B4573 /* PrintSettingsView.swift */; }; - FF8045502C90379300A49A52 /* TournamentMatchFormatsSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE22BD0EBA900A86CF8 /* TournamentMatchFormatsSettingsView.swift */; }; - FF8045512C90379300A49A52 /* DateUpdateManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162892BD05247000C4809 /* DateUpdateManagerView.swift */; }; - FF8045522C90379300A49A52 /* MatchTypeSmallSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0192BBC5A8500B82851 /* MatchTypeSmallSelectionView.swift */; }; - FF8045532C90379300A49A52 /* MonthData.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE82BD1307E00A86CF8 /* MonthData.swift */; }; - FF8045542C90379300A49A52 /* MenuWarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEF7F4D2BDE69130033D0F0 /* MenuWarningView.swift */; }; - FF8045552C90379300A49A52 /* TournamentBuildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B6C2BF9E60B000B4573 /* TournamentBuildView.swift */; }; - FF8045562C90379300A49A52 /* TeamPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D0A2BAF3D4C00A9A3BD /* TeamPickerView.swift */; }; - FF8045572C90379300A49A52 /* CloudConvert.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA6D7862BB0B7A2003A31F3 /* CloudConvert.swift */; }; - FF8045582C90379300A49A52 /* EventTournamentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41832BF75ED7001B24CB /* EventTournamentsView.swift */; }; - FF8045592C90379300A49A52 /* DisplayContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC55A2BAB80C400FD8220 /* DisplayContext.swift */; }; - FF80455A2C90379300A49A52 /* TournamentCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9268062BCE94D90080F940 /* TournamentCallView.swift */; }; - FF80455B2C90379300A49A52 /* LoserRoundsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC2DCB32BBE9ECD0046DB9F /* LoserRoundsView.swift */; }; - FF80455C2C90379300A49A52 /* GroupStagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CFB2BAEE13900A9A3BD /* GroupStagesView.swift */; }; - FF80455D2C90379300A49A52 /* PadelClubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */; }; - FF80455E2C90379300A49A52 /* URLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF01A2BD6A1E80077B5AA /* URLs.swift */; }; - FF80455F2C90379300A49A52 /* MatchDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0132BBC59FC00B82851 /* MatchDescriptor.swift */; }; - FF8045602C90379300A49A52 /* TournamentFormatSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26482BAE0B4100650388 /* TournamentFormatSelectionView.swift */; }; - FF8045612C90379300A49A52 /* MatchListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF065D2BBD8040009D6715 /* MatchListView.swift */; }; - FF8045622C90379300A49A52 /* PadelClubApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C425D4002B6D249D002A7B48 /* PadelClubApp.swift */; }; - FF8045632C90379300A49A52 /* TournamentSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26422BADFE5B00650388 /* TournamentSettingsView.swift */; }; - FF8045642C90379300A49A52 /* String+Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF03B2BE15AF80077B5AA /* String+Crypto.swift */; }; - FF8045652C90379300A49A52 /* GroupStageTeamReplacementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9AC3942BE3627B00C2E883 /* GroupStageTeamReplacementView.swift */; }; - FF8045662C90379300A49A52 /* TabItemModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C7F012BBBD7150031B6A3 /* TabItemModifier.swift */; }; - FF8045672C90379300A49A52 /* DeferredViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDDD40B2B93B2BB00C91A49 /* DeferredViewModifier.swift */; }; - FF8045682C90379300A49A52 /* TournamentScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0E0B6C2BC254C6005F00A9 /* TournamentScheduleView.swift */; }; - FF8045692C90379300A49A52 /* MatchFormatStorageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AF02BD1AEBD00A86CF8 /* MatchFormatStorageView.swift */; }; - FF80456A2C90379300A49A52 /* UmpireView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3F74F52B919E45004CFE0E /* UmpireView.swift */; }; - FF80456B2C90379300A49A52 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DAC2B85FCCD00ADC637 /* User.swift */; }; - FF80456C2C90379300A49A52 /* MatchSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D002BAEF0B400A9A3BD /* MatchSummaryView.swift */; }; - FF80456D2C90379300A49A52 /* TournamentDurationManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26442BAE0A3400650388 /* TournamentDurationManagerView.swift */; }; - FF80456E2C90379300A49A52 /* MockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5522BAB354A00FD8220 /* MockData.swift */; }; - FF80456F2C90379300A49A52 /* TeamDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D082BAF3D4000A9A3BD /* TeamDetailView.swift */; }; - FF8045702C90379300A49A52 /* GroupStagesSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA18E2BB9268800A33061 /* GroupStagesSettingsView.swift */; }; - FF8045712C90379300A49A52 /* TournamentFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF663FBD2BE019EC0031AE83 /* TournamentFilterView.swift */; }; - FF8045722C90379300A49A52 /* HtmlGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B722BFA00FB000B4573 /* HtmlGenerator.swift */; }; - FF8045732C90379300A49A52 /* PadelRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26352BAD523300650388 /* PadelRule.swift */; }; - FF8045742C90379300A49A52 /* TeamRegistration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CF02BAECC0B00A9A3BD /* TeamRegistration.swift */; }; - FF8045752C90379300A49A52 /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACDA2B923F48008466FA /* Date+Extensions.swift */; }; - FF8045762C90379300A49A52 /* GroupStageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CFA2BAEE13800A9A3BD /* GroupStageView.swift */; }; - FF8045772C90379300A49A52 /* Tips.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5582BAB767000FD8220 /* Tips.swift */; }; - FF8045782C90379300A49A52 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB62B90EFBF0061EFF9 /* MainView.swift */; }; - FF8045792C90379300A49A52 /* MatchDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D0C2BAF3EB200A9A3BD /* MatchDateView.swift */; }; - FF80457A2C90379300A49A52 /* PlanningSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF964522BC262B000EEF017 /* PlanningSettingsView.swift */; }; - FF80457B2C90379300A49A52 /* MatchScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF527D52BC6DDD000FF4EF2 /* MatchScheduleEditorView.swift */; }; - FF80457C2C90379300A49A52 /* FortuneWheelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91AF82BD6A09100B29808 /* FortuneWheelView.swift */; }; - FF80457D2C90379300A49A52 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACD52B923960008466FA /* URL+Extensions.swift */; }; - FF80457E2C90379300A49A52 /* LoadingViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C493B37D2C10AD3600862481 /* LoadingViewModifier.swift */; }; - FF80457F2C90379300A49A52 /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBC2BB0287D00F0AEC7 /* PlayerView.swift */; }; - FF8045802C90379300A49A52 /* MatchDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D022BAEF0C000A9A3BD /* MatchDetailView.swift */; }; - FF8045812C90379300A49A52 /* ExportFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF1D2CA2C4A22B200C8D33D /* ExportFormat.swift */; }; - FF8045822C90379300A49A52 /* PlayerBlockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D0E2BAF63B000A9A3BD /* PlayerBlockView.swift */; }; - FF8045832C90379300A49A52 /* StoreItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D8F2B7BBBEC00ADC637 /* StoreItem.swift */; }; - FF8045842C90379300A49A52 /* Selectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB9C8702BBADDE200A0EF4F /* Selectable.swift */; }; - FF8045852C90379300A49A52 /* PointView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0112BBC3E1A00B82851 /* PointView.swift */; }; - FF8045862C90379300A49A52 /* ClubHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC202BB53E590036DAAB /* ClubHolder.swift */; }; - FF8045872C90379300A49A52 /* EventSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41852BF75FDA001B24CB /* EventSettingsView.swift */; }; - FF8045882C90379300A49A52 /* InscriptionInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D772BB42C5B005CB568 /* InscriptionInfoView.swift */; }; - FF8045892C90379300A49A52 /* SelectablePlayerListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BC2B9256E10002987F /* SelectablePlayerListView.swift */; }; - FF80458A2C90379300A49A52 /* MatchFormatPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26502BAE0BAD00650388 /* MatchFormatPickerView.swift */; }; - FF80458B2C90379300A49A52 /* TournamentRankView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5BAF712BE19274008B4B7E /* TournamentRankView.swift */; }; - FF80458C2C90379300A49A52 /* NumberFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D862BB48AFD005CB568 /* NumberFormatter+Extensions.swift */; }; - FF80458D2C90379300A49A52 /* SetLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0172BBC5A6800B82851 /* SetLabelView.swift */; }; - FF80458E2C90379300A49A52 /* DebugSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4489BE12C05BF5000043F3D /* DebugSettingsView.swift */; }; - FF80458F2C90379300A49A52 /* GroupStageScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF9645A2BC2D53B00EEF017 /* GroupStageScheduleEditorView.swift */; }; - FF8045902C90379300A49A52 /* EventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41812BF73EB3001B24CB /* EventView.swift */; }; - FF8045912C90379300A49A52 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DA52B83948E00ADC637 /* LoginView.swift */; }; - FF8045922C90379300A49A52 /* Court.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91B002BD85C2F00B29808 /* Court.swift */; }; - FF8045932C90379300A49A52 /* Labels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CF72BAEDF0000A9A3BD /* Labels.swift */; }; - FF8045942C90379300A49A52 /* CopyPasteButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCB74162C480411008384D0 /* CopyPasteButtonView.swift */; }; - FF8045952C90379300A49A52 /* PlayerSexPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EB32BB0020000F0AEC7 /* PlayerSexPickerView.swift */; }; - FF8045962C90379300A49A52 /* TournamentInscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B702BF9EFE9000B4573 /* TournamentInscriptionView.swift */; }; - FF8045972C90379300A49A52 /* CallSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267FE2BCE94830080F940 /* CallSettingsView.swift */; }; - FF8045982C90379300A49A52 /* FooterButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADC2BD0C94300A86CF8 /* FooterButtonView.swift */; }; - FF8045992C90379300A49A52 /* RankCalculatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D822BB48997005CB568 /* RankCalculatorView.swift */; }; - FF80459A2C90379300A49A52 /* DateBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091692B90F95E00AB08DA /* DateBoxView.swift */; }; - FF80459B2C90379300A49A52 /* LearnMoreSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D6F2BB3EFA5005CB568 /* LearnMoreSheetView.swift */; }; - FF80459C2C90379300A49A52 /* SourceFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACD32B92392C008466FA /* SourceFileManager.swift */; }; - FF80459D2C90379300A49A52 /* PListReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC6F582BE92D88000CEAB4 /* PListReader.swift */; }; - FF80459E2C90379300A49A52 /* UpdateSourceRankDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0EC5212BB173E70056B6D1 /* UpdateSourceRankDateView.swift */; }; - FF80459F2C90379300A49A52 /* GlobalSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE62BD1111000A86CF8 /* GlobalSettingsView.swift */; }; - FF8045A02C90379300A49A52 /* Guard.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D8E2B7BBBEC00ADC637 /* Guard.swift */; }; - FF8045A12C90379300A49A52 /* PurchaseListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF0182BD694290077B5AA /* PurchaseListView.swift */; }; - FF8045A32C90379300A49A52 /* Algorithms in Frameworks */ = {isa = PBXBuildFile; productRef = FF8044AF2C90379300A49A52 /* Algorithms */; }; - FF8045A42C90379300A49A52 /* Zip in Frameworks */ = {isa = PBXBuildFile; productRef = FF8044B12C90379300A49A52 /* Zip */; }; - FF8045A52C90379300A49A52 /* LeStorage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C49EF0372BDFF3000077B5AA /* LeStorage.framework */; }; - FF8045A72C90379300A49A52 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C425D4072B6D249E002A7B48 /* Preview Assets.xcassets */; }; - FF8045A82C90379300A49A52 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FFD784002B91BF79000F62A6 /* Launch Screen.storyboard */; }; - FF8045A92C90379300A49A52 /* tournament-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7F2BFA0105000B4573 /* tournament-template.html */; }; - FF8045AA2C90379300A49A52 /* local.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = FF2B51602C7E302C00FFF126 /* local.sqlite */; }; - FF8045AB2C90379300A49A52 /* groupstagescore-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7B2BFA0105000B4573 /* groupstagescore-template.html */; }; - FF8045AC2C90379300A49A52 /* player-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7E2BFA0105000B4573 /* player-template.html */; }; - FF8045AD2C90379300A49A52 /* groupstagerow-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7A2BFA0105000B4573 /* groupstagerow-template.html */; }; - FF8045AE2C90379300A49A52 /* hiddenplayer-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7C2BFA0105000B4573 /* hiddenplayer-template.html */; }; - FF8045AF2C90379300A49A52 /* bracket-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B762BFA0105000B4573 /* bracket-template.html */; }; - FF8045B02C90379300A49A52 /* groupstagecol-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B782BFA0105000B4573 /* groupstagecol-template.html */; }; - FF8045B12C90379300A49A52 /* groupstage-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B772BFA0105000B4573 /* groupstage-template.html */; }; - FF8045B22C90379300A49A52 /* groupstageentrant-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B792BFA0105000B4573 /* groupstageentrant-template.html */; }; - FF8045B32C90379300A49A52 /* match-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7D2BFA0105000B4573 /* match-template.html */; }; - FF8045B42C90379300A49A52 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = FFF0241D2BF48B15001F14B4 /* Localizable.strings */; }; - FF8045B52C90379300A49A52 /* SyncedProducts.storekit in Resources */ = {isa = PBXBuildFile; fileRef = C45BAE3A2BC6DF10002EEC8A /* SyncedProducts.storekit */; }; - FF8045B62C90379300A49A52 /* local.plist in Resources */ = {isa = PBXBuildFile; fileRef = C4EC6F562BE92CAC000CEAB4 /* local.plist */; }; - FF8045B72C90379300A49A52 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = FF0CA5742BDA4AE10080E843 /* PrivacyInfo.xcprivacy */; }; - FF8045B82C90379300A49A52 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C425D4042B6D249E002A7B48 /* Assets.xcassets */; }; - FF8045BA2C90379300A49A52 /* LeStorage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C49EF0372BDFF3000077B5AA /* LeStorage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + FF70FAC32C90584900129CC2 /* UserCreationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D862B7BA36D00ADC637 /* UserCreationView.swift */; }; + FF70FAC42C90584900129CC2 /* TabDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091652B90F0B000AB08DA /* TabDestination.swift */; }; + FF70FAC52C90584900129CC2 /* CashierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267F72BCE78C70080F940 /* CashierView.swift */; }; + FF70FAC62C90584900129CC2 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F263E2BAD7D5C00650388 /* Event.swift */; }; + FF70FAC72C90584900129CC2 /* PlayerHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D30522BD94E2E00F2B93D /* PlayerHolder.swift */; }; + FF70FAC82C90584900129CC2 /* LoserRoundStepScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF11628B2BD05267000C4809 /* LoserRoundStepScheduleEditorView.swift */; }; + FF70FAC92C90584900129CC2 /* ClubCourtSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF53FBB72BFB302B0051D4C3 /* ClubCourtSetupView.swift */; }; + FF70FACA2C90584900129CC2 /* Patcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B3A1542C2581DA0078EAA8 /* Patcher.swift */; }; + FF70FACB2C90584900129CC2 /* FileImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBE2BB0B14600F0AEC7 /* FileImportView.swift */; }; + FF70FACC2C90584900129CC2 /* StepperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D9E2B7D0BCE00ADC637 /* StepperView.swift */; }; + FF70FACD2C90584900129CC2 /* RoundsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC83D4E2BB807D100750834 /* RoundsView.swift */; }; + FF70FACE2C90584900129CC2 /* FederalTournament.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */; }; + FF70FACF2C90584900129CC2 /* TournamentInitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26402BADFC8700650388 /* TournamentInitView.swift */; }; + FF70FAD02C90584900129CC2 /* SubscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D892B7BBB6500ADC637 /* SubscriptionView.swift */; }; + FF70FAD12C90584900129CC2 /* TournamentLookUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD655D72C8DE27400E5B35E /* TournamentLookUpView.swift */; }; + FF70FAD22C90584900129CC2 /* ClubsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5562BAB3AED00FD8220 /* ClubsView.swift */; }; + FF70FAD32C90584900129CC2 /* ImagePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE103112C366E5900684FC9 /* ImagePickerView.swift */; }; + FF70FAD42C90584900129CC2 /* MatchTypeSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F264E2BAE0B9600650388 /* MatchTypeSelectionView.swift */; }; + FF70FAD52C90584900129CC2 /* MatchSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D052BAF3C4200A9A3BD /* MatchSetupView.swift */; }; + FF70FAD62C90584900129CC2 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6B42B9248200002987F /* NetworkManager.swift */; }; + FF70FAD72C90584900129CC2 /* EventLinksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2B6F5D2C036A1400835EE7 /* EventLinksView.swift */; }; + FF70FAD82C90584900129CC2 /* SeedInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB9C8742BBADDF700A0EF4F /* SeedInterval.swift */; }; + FF70FAD92C90584900129CC2 /* TournamentClubSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE02BD0EB9000A86CF8 /* TournamentClubSettingsView.swift */; }; + FF70FADA2C90584900129CC2 /* GroupStageTeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF065B2BBD2657009D6715 /* GroupStageTeamView.swift */; }; + FF70FADB2C90584900129CC2 /* RoundSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA1922BB9279B00A33061 /* RoundSettingsView.swift */; }; + FF70FADC2C90584900129CC2 /* SupportButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE2D2E12C231BEE00D0C7BE /* SupportButtonView.swift */; }; + FF70FADD2C90584900129CC2 /* TournamentBroadcastRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB1C98A2C10255100B154A7 /* TournamentBroadcastRowView.swift */; }; + FF70FADE2C90584900129CC2 /* TeamWeightView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADE2BD0CE0A00A86CF8 /* TeamWeightView.swift */; }; + FF70FADF2C90584900129CC2 /* SeedsCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9268002BCE94920080F940 /* SeedsCallingView.swift */; }; + FF70FAE02C90584900129CC2 /* CallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9268082BCEDC2C0080F940 /* CallView.swift */; }; + FF70FAE12C90584900129CC2 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D732BB41DF8005CB568 /* Color+Extensions.swift */; }; + FF70FAE22C90584900129CC2 /* EditSharingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE1030F2C366DCD00684FC9 /* EditSharingView.swift */; }; + FF70FAE32C90584900129CC2 /* TournamentCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091672B90F79F00AB08DA /* TournamentCellView.swift */; }; + FF70FAE42C90584900129CC2 /* Sequence+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC9032B9479F500EA7F5A /* Sequence+Extensions.swift */; }; + FF70FAE52C90584900129CC2 /* CashierDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267F92BCE78EB0080F940 /* CashierDetailView.swift */; }; + FF70FAE62C90584900129CC2 /* EventClubSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */; }; + FF70FAE72C90584900129CC2 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DB22B86387500ADC637 /* AccountView.swift */; }; + FF70FAE82C90584900129CC2 /* PlayersWithoutContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCEDA4B2C2C08EA00F8C0F2 /* PlayersWithoutContactView.swift */; }; + FF70FAE92C90584900129CC2 /* TeamsCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCD16B22C3E5E590092707B /* TeamsCallingView.swift */; }; + FF70FAEA2C90584900129CC2 /* Calendar+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */; }; + FF70FAEB2C90584900129CC2 /* TeamScore.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CEF2BAECC0A00A9A3BD /* TeamScore.swift */; }; + FF70FAEC2C90584900129CC2 /* EditablePlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162822BCFBE4E000C4809 /* EditablePlayerView.swift */; }; + FF70FAED2C90584900129CC2 /* PlayerDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162842BD00279000C4809 /* PlayerDetailView.swift */; }; + FF70FAEE2C90584900129CC2 /* ListRowViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D752BB428B2005CB568 /* ListRowViewModifier.swift */; }; + FF70FAEF2C90584900129CC2 /* PresentationContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FF2B94794700EA7F5A /* PresentationContext.swift */; }; + FF70FAF02C90584900129CC2 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */; }; + FF70FAF12C90584900129CC2 /* SwiftParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0EC51D2BB16F680056B6D1 /* SwiftParser.swift */; }; + FF70FAF22C90584900129CC2 /* ChangePasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DA82B85F82100ADC637 /* ChangePasswordView.swift */; }; + FF70FAF32C90584900129CC2 /* TournamentSubscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8044AB2C8F676D00A49A52 /* TournamentSubscriptionView.swift */; }; + FF70FAF42C90584900129CC2 /* RoundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC83D502BB8087E00750834 /* RoundView.swift */; }; + FF70FAF52C90584900129CC2 /* RowButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */; }; + FF70FAF62C90584900129CC2 /* SendToAllView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2EFBEF2BDE295E0049CE3B /* SendToAllView.swift */; }; + FF70FAF72C90584900129CC2 /* EventCreationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F263A2BAD528600650388 /* EventCreationView.swift */; }; + FF70FAF82C90584900129CC2 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC1E1072BAC29FC008D6F59 /* LocationManager.swift */; }; + FF70FAF92C90584900129CC2 /* CapsuleViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C01D972C481C0C0059087C /* CapsuleViewModifier.swift */; }; + FF70FAFA2C90584900129CC2 /* BroadcastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6087EB2BE26A2F004E1E47 /* BroadcastView.swift */; }; + FF70FAFB2C90584900129CC2 /* SchedulerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF964542BC266CF00EEF017 /* SchedulerView.swift */; }; + FF70FAFC2C90584900129CC2 /* PadelClubButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA1B1282BB71773006CE248 /* PadelClubButtonView.swift */; }; + FF70FAFD2C90584900129CC2 /* TournamentSeedEditing.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA19A2BB9662200A33061 /* TournamentSeedEditing.swift */; }; + FF70FAFE2C90584900129CC2 /* TournamentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF70916B2B91005400AB08DA /* TournamentView.swift */; }; + FF70FAFF2C90584900129CC2 /* OngoingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D30552BD95B1100F2B93D /* OngoingView.swift */; }; + FF70FB002C90584900129CC2 /* CreateClubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5542BAB36DD00FD8220 /* CreateClubView.swift */; }; + FF70FB012C90584900129CC2 /* APICallsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4607A7C2C04DDE2004CB781 /* APICallsListView.swift */; }; + FF70FB022C90584900129CC2 /* NetworkFederalService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC1E1092BAC2A77008D6F59 /* NetworkFederalService.swift */; }; + FF70FB032C90584900129CC2 /* DurationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AEE2BD1AE9400A86CF8 /* DurationSettingsView.swift */; }; + FF70FB042C90584900129CC2 /* AppScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AEC2BD1513700A86CF8 /* AppScreen.swift */; }; + FF70FB052C90584900129CC2 /* CourtView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91B022BD85E2400B29808 /* CourtView.swift */; }; + FF70FB062C90584900129CC2 /* PointSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC00D2BBC3D4600B82851 /* PointSelectionView.swift */; }; + FF70FB072C90584900129CC2 /* TeamRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EB52BB00A3800F0AEC7 /* TeamRowView.swift */; }; + FF70FB082C90584900129CC2 /* ContactManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF92680A2BCEE3E10080F940 /* ContactManager.swift */; }; + FF70FB092C90584900129CC2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40CD2F22C412681000DBD9A /* AppDelegate.swift */; }; + FF70FB0A2C90584900129CC2 /* SubscriptionInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF0252BD80AE80077B5AA /* SubscriptionInfoView.swift */; }; + FF70FB0B2C90584900129CC2 /* EditScoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0012BBC39A600B82851 /* EditScoreView.swift */; }; + FF70FB0C2C90584900129CC2 /* TournamentOrganizerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091612B90F04300AB08DA /* TournamentOrganizerView.swift */; }; + FF70FB0D2C90584900129CC2 /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF92680C2BCEE5EA0080F940 /* NetworkMonitor.swift */; }; + FF70FB0E2C90584900129CC2 /* TournamentRunningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CF52BAED51600A9A3BD /* TournamentRunningView.swift */; }; + FF70FB0F2C90584900129CC2 /* TournamentDatePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F264A2BAE0B4100650388 /* TournamentDatePickerView.swift */; }; + FF70FB102C90584900129CC2 /* CourtAvailabilitySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF116E22BD2AF4800A33B06 /* CourtAvailabilitySettingsView.swift */; }; + FF70FB112C90584900129CC2 /* ConfirmButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE8C2BF2C7601E80046B243 /* ConfirmButtonView.swift */; }; + FF70FB122C90584900129CC2 /* PasswordField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FC2E262C2AABC90021F3BF /* PasswordField.swift */; }; + FF70FB132C90584900129CC2 /* MatchRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CFF2BAEEF6400A9A3BD /* MatchRowView.swift */; }; + FF70FB142C90584900129CC2 /* Locale+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44B79102BBDA63A00906534 /* Locale+Extensions.swift */; }; + FF70FB152C90584900129CC2 /* HtmlService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B732BFA00FC000B4573 /* HtmlService.swift */; }; + FF70FB162C90584900129CC2 /* GroupStage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CE72BAEC70100A9A3BD /* GroupStage.swift */; }; + FF70FB172C90584900129CC2 /* TournamentCashierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162802BCF945C000C4809 /* TournamentCashierView.swift */; }; + FF70FB182C90584900129CC2 /* StoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D8D2B7BBBEC00ADC637 /* StoreManager.swift */; }; + FF70FB192C90584900129CC2 /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BA2B9256D50002987F /* SearchViewModel.swift */; }; + FF70FB1A2C90584900129CC2 /* PlayerRegistration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CF12BAECC0B00A9A3BD /* PlayerRegistration.swift */; }; + FF70FB1B2C90584900129CC2 /* ImportedPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BE2B92577A0002987F /* ImportedPlayerView.swift */; }; + FF70FB1C2C90584900129CC2 /* EditingTeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162862BD004AD000C4809 /* EditingTeamView.swift */; }; + FF70FB1D2C90584900129CC2 /* NetworkManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC9052B947A1000EA7F5A /* NetworkManagerError.swift */; }; + FF70FB1E2C90584900129CC2 /* Tournament.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D592B6D383C00ADC637 /* Tournament.swift */; }; + FF70FB1F2C90584900129CC2 /* TournamentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FC2E2A2C2C0E4D0021F3BF /* TournamentStore.swift */; }; + FF70FB202C90584900129CC2 /* LoserRoundSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5647122C0B6F380081F995 /* LoserRoundSettingsView.swift */; }; + FF70FB212C90584900129CC2 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3795652B9399AA004EA093 /* Persistence.swift */; }; + FF70FB222C90584900129CC2 /* CloseDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCF76062C3BE9BC006C8C3D /* CloseDatePicker.swift */; }; + FF70FB232C90584900129CC2 /* BarButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DF49A2BD8D23900822FA0 /* BarButtonView.swift */; }; + FF70FB242C90584900129CC2 /* PlanningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF9644F2BC25E3700EEF017 /* PlanningView.swift */; }; + FF70FB252C90584900129CC2 /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CEB2BAECB9900A9A3BD /* Match.swift */; }; + FF70FB262C90584900129CC2 /* TournamentLevelPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26492BAE0B4100650388 /* TournamentLevelPickerView.swift */; }; + FF70FB272C90584900129CC2 /* FederalTournamentHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC212BB53E590036DAAB /* FederalTournamentHolder.swift */; }; + FF70FB282C90584900129CC2 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D5D2B6D38EC00ADC637 /* DataStore.swift */; }; + FF70FB292C90584900129CC2 /* SetDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC01B2BBC5AAA00B82851 /* SetDescriptor.swift */; }; + FF70FB2A2C90584900129CC2 /* TeamHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AD72BD0C10F00A86CF8 /* TeamHeaderView.swift */; }; + FF70FB2B2C90584900129CC2 /* OrganizedTournamentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF82CFC42B911F5B00B0CAF2 /* OrganizedTournamentView.swift */; }; + FF70FB2C2C90584900129CC2 /* RoundScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF964562BC26B3400EEF017 /* RoundScheduleEditorView.swift */; }; + FF70FB2D2C90584900129CC2 /* EventListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */; }; + FF70FB2E2C90584900129CC2 /* TournamentConfiguratorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */; }; + FF70FB2F2C90584900129CC2 /* ClubImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC1E10B2BAC7FB0008D6F59 /* ClubImportView.swift */; }; + FF70FB302C90584900129CC2 /* UnderlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF558C622C6CDD020071F9AE /* UnderlineView.swift */; }; + FF70FB312C90584900129CC2 /* MatchScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3B60A22BC49BBC008C2E66 /* MatchScheduler.swift */; }; + FF70FB322C90584900129CC2 /* CallMessageCustomizationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162792BCF8109000C4809 /* CallMessageCustomizationView.swift */; }; + FF70FB332C90584900129CC2 /* TournamentStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6087E92BE25EF1004E1E47 /* TournamentStatusView.swift */; }; + FF70FB342C90584900129CC2 /* MatchTeamDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADA2BD0C2D000A86CF8 /* MatchTeamDetailView.swift */; }; + FF70FB352C90584900129CC2 /* GenericDestinationPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA1942BB927E800A33061 /* GenericDestinationPickerView.swift */; }; + FF70FB362C90584900129CC2 /* DateInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF116E02BD2A9B600A33B06 /* DateInterval.swift */; }; + FF70FB372C90584900129CC2 /* TableStructureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26532BAE1E4400650388 /* TableStructureView.swift */; }; + FF70FB382C90584900129CC2 /* Purchase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45BAE432BCA753E002EEC8A /* Purchase.swift */; }; + FF70FB392C90584900129CC2 /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FD2B94792300EA7F5A /* Screen.swift */; }; + FF70FB3A2C90584900129CC2 /* Round.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CED2BAECBD700A9A3BD /* Round.swift */; }; + FF70FB3B2C90584900129CC2 /* FederalDataViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5BAF6D2BE0B3C8008B4B7E /* FederalDataViewModel.swift */; }; + FF70FB3C2C90584900129CC2 /* AgendaDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3F74FE2B91A2D4004CFE0E /* AgendaDestination.swift */; }; + FF70FB3D2C90584900129CC2 /* PadelClubApp.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FF3795602B9396D0004EA093 /* PadelClubApp.xcdatamodeld */; }; + FF70FB3E2C90584900129CC2 /* SetInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0152BBC5A4C00B82851 /* SetInputView.swift */; }; + FF70FB3F2C90584900129CC2 /* ButtonValidateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF03C932BD91D0C00B516FC /* ButtonValidateView.swift */; }; + FF70FB402C90584900129CC2 /* ClubRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D882BB4935C005CB568 /* ClubRowView.swift */; }; + FF70FB412C90584900129CC2 /* ClubDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5502BAB351300FD8220 /* ClubDetailView.swift */; }; + FF70FB422C90584900129CC2 /* GroupStageCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9268022BCE94A30080F940 /* GroupStageCallingView.swift */; }; + FF70FB432C90584900129CC2 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF0432BE286780077B5AA /* Key.swift */; }; + FF70FB442C90584900129CC2 /* CashierSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF11627C2BCF941A000C4809 /* CashierSettingsView.swift */; }; + FF70FB452C90584900129CC2 /* LoserRoundScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFFCDE0D2BCC833600317DEF /* LoserRoundScheduleEditorView.swift */; }; + FF70FB462C90584900129CC2 /* Club.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D622B6D3D6500ADC637 /* Club.swift */; }; + FF70FB472C90584900129CC2 /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC90A2B947AC000EA7F5A /* Array+Extensions.swift */; }; + FF70FB482C90584900129CC2 /* ToolboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB82B90EFD70061EFF9 /* ToolboxView.swift */; }; + FF70FB492C90584900129CC2 /* Alphabet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8E1CE52C006E0200184680 /* Alphabet.swift */; }; + FF70FB4A2C90584900129CC2 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACD82B923F3C008466FA /* String+Extensions.swift */; }; + FF70FB4B2C90584900129CC2 /* GroupStageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCB74122C4625BB008384D0 /* GroupStageSettingsView.swift */; }; + FF70FB4C2C90584900129CC2 /* TournamentGeneralSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE42BD0EBB800A86CF8 /* TournamentGeneralSettingsView.swift */; }; + FF70FB4D2C90584900129CC2 /* LoserRoundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC2DCB12BBE75D40046DB9F /* LoserRoundView.swift */; }; + FF70FB4E2C90584900129CC2 /* AddTeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF90FC1C2C44FB3E009339B2 /* AddTeamView.swift */; }; + FF70FB4F2C90584900129CC2 /* PlayerPayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267FB2BCE84870080F940 /* PlayerPayView.swift */; }; + FF70FB502C90584900129CC2 /* PlanningByCourtView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2B51542C7A4DAF00FFF126 /* PlanningByCourtView.swift */; }; + FF70FB512C90584900129CC2 /* FileImportManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA6D7842BB0B795003A31F3 /* FileImportManager.swift */; }; + FF70FB522C90584900129CC2 /* TournamentButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FA2B94788600EA7F5A /* TournamentButtonView.swift */; }; + FF70FB532C90584900129CC2 /* FederalPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACCC2B92367B008466FA /* FederalPlayer.swift */; }; + FF70FB542C90584900129CC2 /* NavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF065F2BBD9F6D009D6715 /* NavigationViewModel.swift */; }; + FF70FB552C90584900129CC2 /* FixedWidthInteger+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC9082B947A5300EA7F5A /* FixedWidthInteger+Extensions.swift */; }; + FF70FB562C90584900129CC2 /* LoserBracketFromGroupStageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6525C22C8C61B400B9498E /* LoserBracketFromGroupStageView.swift */; }; + FF70FB572C90584900129CC2 /* ImportedPlayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D30502BD94E1000F2B93D /* ImportedPlayer+Extensions.swift */; }; + FF70FB582C90584900129CC2 /* ClubSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC1E1032BAC28C6008D6F59 /* ClubSearchView.swift */; }; + FF70FB592C90584900129CC2 /* PlayerPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBA2BB0120700F0AEC7 /* PlayerPopoverView.swift */; }; + FF70FB5A2C90584900129CC2 /* InscriptionManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF70916D2B9108C600AB08DA /* InscriptionManagerView.swift */; }; + FF70FB5B2C90584900129CC2 /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF82CFC82B9132AF00B0CAF2 /* ActivityView.swift */; }; + FF70FB5C2C90584900129CC2 /* MySortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C722BB2CFE900F1E467 /* MySortDescriptor.swift */; }; + FF70FB5D2C90584900129CC2 /* CalendarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D8A2BB4D1E3005CB568 /* CalendarView.swift */; }; + FF70FB5E2C90584900129CC2 /* FederalTournamentSearchScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */; }; + FF70FB5F2C90584900129CC2 /* TournamentFieldsManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26462BAE0ACB00650388 /* TournamentFieldsManagerView.swift */; }; + FF70FB602C90584900129CC2 /* PrintSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B812BFA0124000B4573 /* PrintSettingsView.swift */; }; + FF70FB612C90584900129CC2 /* TournamentMatchFormatsSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE22BD0EBA900A86CF8 /* TournamentMatchFormatsSettingsView.swift */; }; + FF70FB622C90584900129CC2 /* DateUpdateManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162892BD05247000C4809 /* DateUpdateManagerView.swift */; }; + FF70FB632C90584900129CC2 /* MatchTypeSmallSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0192BBC5A8500B82851 /* MatchTypeSmallSelectionView.swift */; }; + FF70FB642C90584900129CC2 /* MonthData.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE82BD1307E00A86CF8 /* MonthData.swift */; }; + FF70FB652C90584900129CC2 /* MenuWarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEF7F4D2BDE69130033D0F0 /* MenuWarningView.swift */; }; + FF70FB662C90584900129CC2 /* TournamentBuildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B6C2BF9E60B000B4573 /* TournamentBuildView.swift */; }; + FF70FB672C90584900129CC2 /* TeamPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D0A2BAF3D4C00A9A3BD /* TeamPickerView.swift */; }; + FF70FB682C90584900129CC2 /* CloudConvert.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA6D7862BB0B7A2003A31F3 /* CloudConvert.swift */; }; + FF70FB692C90584900129CC2 /* EventTournamentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41832BF75ED7001B24CB /* EventTournamentsView.swift */; }; + FF70FB6A2C90584900129CC2 /* DisplayContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC55A2BAB80C400FD8220 /* DisplayContext.swift */; }; + FF70FB6B2C90584900129CC2 /* TournamentCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9268062BCE94D90080F940 /* TournamentCallView.swift */; }; + FF70FB6C2C90584900129CC2 /* LoserRoundsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC2DCB32BBE9ECD0046DB9F /* LoserRoundsView.swift */; }; + FF70FB6D2C90584900129CC2 /* GroupStagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CFB2BAEE13900A9A3BD /* GroupStagesView.swift */; }; + FF70FB6E2C90584900129CC2 /* PadelClubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */; }; + FF70FB6F2C90584900129CC2 /* URLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF01A2BD6A1E80077B5AA /* URLs.swift */; }; + FF70FB702C90584900129CC2 /* MatchDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0132BBC59FC00B82851 /* MatchDescriptor.swift */; }; + FF70FB712C90584900129CC2 /* TournamentFormatSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26482BAE0B4100650388 /* TournamentFormatSelectionView.swift */; }; + FF70FB722C90584900129CC2 /* MatchListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF065D2BBD8040009D6715 /* MatchListView.swift */; }; + FF70FB732C90584900129CC2 /* PadelClubApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C425D4002B6D249D002A7B48 /* PadelClubApp.swift */; }; + FF70FB742C90584900129CC2 /* TournamentSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26422BADFE5B00650388 /* TournamentSettingsView.swift */; }; + FF70FB752C90584900129CC2 /* String+Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF03B2BE15AF80077B5AA /* String+Crypto.swift */; }; + FF70FB762C90584900129CC2 /* GroupStageTeamReplacementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9AC3942BE3627B00C2E883 /* GroupStageTeamReplacementView.swift */; }; + FF70FB772C90584900129CC2 /* TabItemModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C7F012BBBD7150031B6A3 /* TabItemModifier.swift */; }; + FF70FB782C90584900129CC2 /* DeferredViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDDD40B2B93B2BB00C91A49 /* DeferredViewModifier.swift */; }; + FF70FB792C90584900129CC2 /* TournamentScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0E0B6C2BC254C6005F00A9 /* TournamentScheduleView.swift */; }; + FF70FB7A2C90584900129CC2 /* MatchFormatStorageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AF02BD1AEBD00A86CF8 /* MatchFormatStorageView.swift */; }; + FF70FB7B2C90584900129CC2 /* UmpireView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3F74F52B919E45004CFE0E /* UmpireView.swift */; }; + FF70FB7C2C90584900129CC2 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DAC2B85FCCD00ADC637 /* User.swift */; }; + FF70FB7D2C90584900129CC2 /* MatchSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D002BAEF0B400A9A3BD /* MatchSummaryView.swift */; }; + FF70FB7E2C90584900129CC2 /* TournamentDurationManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26442BAE0A3400650388 /* TournamentDurationManagerView.swift */; }; + FF70FB7F2C90584900129CC2 /* MockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5522BAB354A00FD8220 /* MockData.swift */; }; + FF70FB802C90584900129CC2 /* TeamDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D082BAF3D4000A9A3BD /* TeamDetailView.swift */; }; + FF70FB812C90584900129CC2 /* GroupStagesSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA18E2BB9268800A33061 /* GroupStagesSettingsView.swift */; }; + FF70FB822C90584900129CC2 /* TournamentFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF663FBD2BE019EC0031AE83 /* TournamentFilterView.swift */; }; + FF70FB832C90584900129CC2 /* HtmlGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B722BFA00FB000B4573 /* HtmlGenerator.swift */; }; + FF70FB842C90584900129CC2 /* PadelRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26352BAD523300650388 /* PadelRule.swift */; }; + FF70FB852C90584900129CC2 /* TeamRegistration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CF02BAECC0B00A9A3BD /* TeamRegistration.swift */; }; + FF70FB862C90584900129CC2 /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACDA2B923F48008466FA /* Date+Extensions.swift */; }; + FF70FB872C90584900129CC2 /* GroupStageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CFA2BAEE13800A9A3BD /* GroupStageView.swift */; }; + FF70FB882C90584900129CC2 /* Tips.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5582BAB767000FD8220 /* Tips.swift */; }; + FF70FB892C90584900129CC2 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB62B90EFBF0061EFF9 /* MainView.swift */; }; + FF70FB8A2C90584900129CC2 /* MatchDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D0C2BAF3EB200A9A3BD /* MatchDateView.swift */; }; + FF70FB8B2C90584900129CC2 /* PlanningSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF964522BC262B000EEF017 /* PlanningSettingsView.swift */; }; + FF70FB8C2C90584900129CC2 /* MatchScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF527D52BC6DDD000FF4EF2 /* MatchScheduleEditorView.swift */; }; + FF70FB8D2C90584900129CC2 /* FortuneWheelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91AF82BD6A09100B29808 /* FortuneWheelView.swift */; }; + FF70FB8E2C90584900129CC2 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACD52B923960008466FA /* URL+Extensions.swift */; }; + FF70FB8F2C90584900129CC2 /* LoadingViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C493B37D2C10AD3600862481 /* LoadingViewModifier.swift */; }; + FF70FB902C90584900129CC2 /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBC2BB0287D00F0AEC7 /* PlayerView.swift */; }; + FF70FB912C90584900129CC2 /* MatchDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D022BAEF0C000A9A3BD /* MatchDetailView.swift */; }; + FF70FB922C90584900129CC2 /* ExportFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF1D2CA2C4A22B200C8D33D /* ExportFormat.swift */; }; + FF70FB932C90584900129CC2 /* PlayerBlockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D0E2BAF63B000A9A3BD /* PlayerBlockView.swift */; }; + FF70FB942C90584900129CC2 /* StoreItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D8F2B7BBBEC00ADC637 /* StoreItem.swift */; }; + FF70FB952C90584900129CC2 /* Selectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB9C8702BBADDE200A0EF4F /* Selectable.swift */; }; + FF70FB962C90584900129CC2 /* PointView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0112BBC3E1A00B82851 /* PointView.swift */; }; + FF70FB972C90584900129CC2 /* ClubHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC202BB53E590036DAAB /* ClubHolder.swift */; }; + FF70FB982C90584900129CC2 /* EventSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41852BF75FDA001B24CB /* EventSettingsView.swift */; }; + FF70FB992C90584900129CC2 /* InscriptionInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D772BB42C5B005CB568 /* InscriptionInfoView.swift */; }; + FF70FB9A2C90584900129CC2 /* SelectablePlayerListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BC2B9256E10002987F /* SelectablePlayerListView.swift */; }; + FF70FB9B2C90584900129CC2 /* MatchFormatPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26502BAE0BAD00650388 /* MatchFormatPickerView.swift */; }; + FF70FB9C2C90584900129CC2 /* TournamentRankView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5BAF712BE19274008B4B7E /* TournamentRankView.swift */; }; + FF70FB9D2C90584900129CC2 /* NumberFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D862BB48AFD005CB568 /* NumberFormatter+Extensions.swift */; }; + FF70FB9E2C90584900129CC2 /* SetLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0172BBC5A6800B82851 /* SetLabelView.swift */; }; + FF70FB9F2C90584900129CC2 /* DebugSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4489BE12C05BF5000043F3D /* DebugSettingsView.swift */; }; + FF70FBA02C90584900129CC2 /* GroupStageScheduleEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF9645A2BC2D53B00EEF017 /* GroupStageScheduleEditorView.swift */; }; + FF70FBA12C90584900129CC2 /* EventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41812BF73EB3001B24CB /* EventView.swift */; }; + FF70FBA22C90584900129CC2 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DA52B83948E00ADC637 /* LoginView.swift */; }; + FF70FBA32C90584900129CC2 /* Court.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91B002BD85C2F00B29808 /* Court.swift */; }; + FF70FBA42C90584900129CC2 /* Labels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967CF72BAEDF0000A9A3BD /* Labels.swift */; }; + FF70FBA52C90584900129CC2 /* CopyPasteButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCB74162C480411008384D0 /* CopyPasteButtonView.swift */; }; + FF70FBA62C90584900129CC2 /* PlayerSexPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EB32BB0020000F0AEC7 /* PlayerSexPickerView.swift */; }; + FF70FBA72C90584900129CC2 /* TournamentInscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1F4B702BF9EFE9000B4573 /* TournamentInscriptionView.swift */; }; + FF70FBA82C90584900129CC2 /* CallSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267FE2BCE94830080F940 /* CallSettingsView.swift */; }; + FF70FBA92C90584900129CC2 /* FooterButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADC2BD0C94300A86CF8 /* FooterButtonView.swift */; }; + FF70FBAA2C90584900129CC2 /* RankCalculatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D822BB48997005CB568 /* RankCalculatorView.swift */; }; + FF70FBAB2C90584900129CC2 /* DateBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7091692B90F95E00AB08DA /* DateBoxView.swift */; }; + FF70FBAC2C90584900129CC2 /* LearnMoreSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D6F2BB3EFA5005CB568 /* LearnMoreSheetView.swift */; }; + FF70FBAD2C90584900129CC2 /* SourceFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACD32B92392C008466FA /* SourceFileManager.swift */; }; + FF70FBAE2C90584900129CC2 /* PListReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC6F582BE92D88000CEAB4 /* PListReader.swift */; }; + FF70FBAF2C90584900129CC2 /* UpdateSourceRankDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0EC5212BB173E70056B6D1 /* UpdateSourceRankDateView.swift */; }; + FF70FBB02C90584900129CC2 /* GlobalSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AE62BD1111000A86CF8 /* GlobalSettingsView.swift */; }; + FF70FBB12C90584900129CC2 /* Guard.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D8E2B7BBBEC00ADC637 /* Guard.swift */; }; + FF70FBB22C90584900129CC2 /* PurchaseListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EF0182BD694290077B5AA /* PurchaseListView.swift */; }; + FF70FBB42C90584900129CC2 /* Algorithms in Frameworks */ = {isa = PBXBuildFile; productRef = FF70FABE2C90584900129CC2 /* Algorithms */; }; + FF70FBB52C90584900129CC2 /* Zip in Frameworks */ = {isa = PBXBuildFile; productRef = FF70FAC02C90584900129CC2 /* Zip */; }; + FF70FBB62C90584900129CC2 /* LeStorage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C49EF0372BDFF3000077B5AA /* LeStorage.framework */; }; + FF70FBB82C90584900129CC2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C425D4072B6D249E002A7B48 /* Preview Assets.xcassets */; }; + FF70FBB92C90584900129CC2 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FFD784002B91BF79000F62A6 /* Launch Screen.storyboard */; }; + FF70FBBA2C90584900129CC2 /* tournament-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7F2BFA0105000B4573 /* tournament-template.html */; }; + FF70FBBB2C90584900129CC2 /* local.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = FF2B51602C7E302C00FFF126 /* local.sqlite */; }; + FF70FBBC2C90584900129CC2 /* groupstagescore-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7B2BFA0105000B4573 /* groupstagescore-template.html */; }; + FF70FBBD2C90584900129CC2 /* player-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7E2BFA0105000B4573 /* player-template.html */; }; + FF70FBBE2C90584900129CC2 /* groupstagerow-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7A2BFA0105000B4573 /* groupstagerow-template.html */; }; + FF70FBBF2C90584900129CC2 /* hiddenplayer-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7C2BFA0105000B4573 /* hiddenplayer-template.html */; }; + FF70FBC02C90584900129CC2 /* bracket-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B762BFA0105000B4573 /* bracket-template.html */; }; + FF70FBC12C90584900129CC2 /* groupstagecol-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B782BFA0105000B4573 /* groupstagecol-template.html */; }; + FF70FBC22C90584900129CC2 /* groupstage-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B772BFA0105000B4573 /* groupstage-template.html */; }; + FF70FBC32C90584900129CC2 /* groupstageentrant-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B792BFA0105000B4573 /* groupstageentrant-template.html */; }; + FF70FBC42C90584900129CC2 /* match-template.html in Resources */ = {isa = PBXBuildFile; fileRef = FF1F4B7D2BFA0105000B4573 /* match-template.html */; }; + FF70FBC52C90584900129CC2 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = FFF0241D2BF48B15001F14B4 /* Localizable.strings */; }; + FF70FBC62C90584900129CC2 /* SyncedProducts.storekit in Resources */ = {isa = PBXBuildFile; fileRef = C45BAE3A2BC6DF10002EEC8A /* SyncedProducts.storekit */; }; + FF70FBC72C90584900129CC2 /* local.plist in Resources */ = {isa = PBXBuildFile; fileRef = C4EC6F562BE92CAC000CEAB4 /* local.plist */; }; + FF70FBC82C90584900129CC2 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = FF0CA5742BDA4AE10080E843 /* PrivacyInfo.xcprivacy */; }; + FF70FBC92C90584900129CC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C425D4042B6D249E002A7B48 /* Assets.xcassets */; }; + FF70FBCB2C90584900129CC2 /* LeStorage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C49EF0372BDFF3000077B5AA /* LeStorage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + FF8044AC2C8F676D00A49A52 /* TournamentSubscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8044AB2C8F676D00A49A52 /* TournamentSubscriptionView.swift */; }; FF82CFC52B911F5B00B0CAF2 /* OrganizedTournamentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF82CFC42B911F5B00B0CAF2 /* OrganizedTournamentView.swift */; }; FF82CFC92B9132AF00B0CAF2 /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF82CFC82B9132AF00B0CAF2 /* ActivityView.swift */; }; FF8E1CE62C006E0200184680 /* Alphabet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8E1CE52C006E0200184680 /* Alphabet.swift */; }; @@ -507,6 +510,7 @@ FFCFC0182BBC5A6800B82851 /* SetLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0172BBC5A6800B82851 /* SetLabelView.swift */; }; FFCFC01A2BBC5A8500B82851 /* MatchTypeSmallSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0192BBC5A8500B82851 /* MatchTypeSmallSelectionView.swift */; }; FFCFC01C2BBC5AAA00B82851 /* SetDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC01B2BBC5AAA00B82851 /* SetDescriptor.swift */; }; + FFD655D82C8DE27400E5B35E /* TournamentLookUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD655D72C8DE27400E5B35E /* TournamentLookUpView.swift */; }; FFD783FF2B91BA42000F62A6 /* PadelClubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */; }; FFDB1C6D2BB2A02000F1E467 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */; }; FFDB1C732BB2CFE900F1E467 /* MySortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C722BB2CFE900F1E467 /* MySortDescriptor.swift */; }; @@ -565,13 +569,13 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; - FF8045B92C90379300A49A52 /* Embed Frameworks */ = { + FF70FBCA2C90584900129CC2 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - FF8045BA2C90379300A49A52 /* LeStorage.framework in Embed Frameworks */, + FF70FBCB2C90584900129CC2 /* LeStorage.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -696,7 +700,6 @@ FF1162862BD004AD000C4809 /* EditingTeamView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditingTeamView.swift; sourceTree = ""; }; FF1162892BD05247000C4809 /* DateUpdateManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateUpdateManagerView.swift; sourceTree = ""; }; FF11628B2BD05267000C4809 /* LoserRoundStepScheduleEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoserRoundStepScheduleEditorView.swift; sourceTree = ""; }; - FF135BF82C2FCB8300C9247A /* LoserGroupStageSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoserGroupStageSettingsView.swift; sourceTree = ""; }; FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournament.swift; sourceTree = ""; }; FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+Extensions.swift"; sourceTree = ""; }; FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournamentSearchScope.swift; sourceTree = ""; }; @@ -764,6 +767,7 @@ FF5DA19A2BB9662200A33061 /* TournamentSeedEditing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentSeedEditing.swift; sourceTree = ""; }; FF6087E92BE25EF1004E1E47 /* TournamentStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentStatusView.swift; sourceTree = ""; }; FF6087EB2BE26A2F004E1E47 /* BroadcastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BroadcastView.swift; sourceTree = ""; }; + FF6525C22C8C61B400B9498E /* LoserBracketFromGroupStageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoserBracketFromGroupStageView.swift; sourceTree = ""; }; FF663FBD2BE019EC0031AE83 /* TournamentFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentFilterView.swift; sourceTree = ""; }; FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RowButtonView.swift; sourceTree = ""; }; FF6EC8FA2B94788600EA7F5A /* TournamentButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentButtonView.swift; sourceTree = ""; }; @@ -779,7 +783,8 @@ FF7091692B90F95E00AB08DA /* DateBoxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateBoxView.swift; sourceTree = ""; }; FF70916B2B91005400AB08DA /* TournamentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentView.swift; sourceTree = ""; }; FF70916D2B9108C600AB08DA /* InscriptionManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InscriptionManagerView.swift; sourceTree = ""; }; - FF8045BE2C90379300A49A52 /* PadelClub TestFlight.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PadelClub TestFlight.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + FF70FBCF2C90584900129CC2 /* PadelClub TestFlight.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PadelClub TestFlight.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + FF8044AB2C8F676D00A49A52 /* TournamentSubscriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentSubscriptionView.swift; sourceTree = ""; }; FF82CFC42B911F5B00B0CAF2 /* OrganizedTournamentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganizedTournamentView.swift; sourceTree = ""; }; FF82CFC82B9132AF00B0CAF2 /* ActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = ""; }; FF8E1CE52C006E0200184680 /* Alphabet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alphabet.swift; sourceTree = ""; }; @@ -865,6 +870,7 @@ FFCFC0172BBC5A6800B82851 /* SetLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetLabelView.swift; sourceTree = ""; }; FFCFC0192BBC5A8500B82851 /* MatchTypeSmallSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchTypeSmallSelectionView.swift; sourceTree = ""; }; FFCFC01B2BBC5AAA00B82851 /* SetDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDescriptor.swift; sourceTree = ""; }; + FFD655D72C8DE27400E5B35E /* TournamentLookUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentLookUpView.swift; sourceTree = ""; }; FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PadelClubView.swift; sourceTree = ""; }; FFD784002B91BF79000F62A6 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = ""; }; @@ -921,13 +927,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - FF8045A22C90379300A49A52 /* Frameworks */ = { + FF70FBB32C90584900129CC2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - FF8045A32C90379300A49A52 /* Algorithms in Frameworks */, - FF8045A42C90379300A49A52 /* Zip in Frameworks */, - FF8045A52C90379300A49A52 /* LeStorage.framework in Frameworks */, + FF70FBB42C90584900129CC2 /* Algorithms in Frameworks */, + FF70FBB52C90584900129CC2 /* Zip in Frameworks */, + FF70FBB62C90584900129CC2 /* LeStorage.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -951,7 +957,7 @@ C425D3FD2B6D249D002A7B48 /* PadelClub.app */, C425D40D2B6D249E002A7B48 /* PadelClubTests.xctest */, C425D4172B6D249E002A7B48 /* PadelClubUITests.xctest */, - FF8045BE2C90379300A49A52 /* PadelClub TestFlight.app */, + FF70FBCF2C90584900129CC2 /* PadelClub TestFlight.app */, ); name = Products; sourceTree = ""; @@ -1479,7 +1485,7 @@ FF967CFA2BAEE13800A9A3BD /* GroupStageView.swift */, FF967CFB2BAEE13900A9A3BD /* GroupStagesView.swift */, FF5DA18E2BB9268800A33061 /* GroupStagesSettingsView.swift */, - FF135BF82C2FCB8300C9247A /* LoserGroupStageSettingsView.swift */, + FF6525C22C8C61B400B9498E /* LoserBracketFromGroupStageView.swift */, FF9AC3932BE3625D00C2E883 /* Components */, FF9AC3922BE3625200C2E883 /* Shared */, ); @@ -1574,6 +1580,8 @@ FF82CFC82B9132AF00B0CAF2 /* ActivityView.swift */, FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */, FF5D0D8A2BB4D1E3005CB568 /* CalendarView.swift */, + FFD655D72C8DE27400E5B35E /* TournamentLookUpView.swift */, + FF8044AB2C8F676D00A49A52 /* TournamentSubscriptionView.swift */, ); path = Agenda; sourceTree = ""; @@ -1731,14 +1739,14 @@ productReference = C425D4172B6D249E002A7B48 /* PadelClubUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; - FF8044AE2C90379300A49A52 /* PadelClub TestFlight */ = { + FF70FABD2C90584900129CC2 /* PadelClub TestFlight */ = { isa = PBXNativeTarget; - buildConfigurationList = FF8045BB2C90379300A49A52 /* Build configuration list for PBXNativeTarget "PadelClub TestFlight" */; + buildConfigurationList = FF70FBCC2C90584900129CC2 /* Build configuration list for PBXNativeTarget "PadelClub TestFlight" */; buildPhases = ( - FF8044B32C90379300A49A52 /* Sources */, - FF8045A22C90379300A49A52 /* Frameworks */, - FF8045A62C90379300A49A52 /* Resources */, - FF8045B92C90379300A49A52 /* Embed Frameworks */, + FF70FAC22C90584900129CC2 /* Sources */, + FF70FBB32C90584900129CC2 /* Frameworks */, + FF70FBB72C90584900129CC2 /* Resources */, + FF70FBCA2C90584900129CC2 /* Embed Frameworks */, ); buildRules = ( ); @@ -1746,11 +1754,11 @@ ); name = "PadelClub TestFlight"; packageProductDependencies = ( - FF8044AF2C90379300A49A52 /* Algorithms */, - FF8044B12C90379300A49A52 /* Zip */, + FF70FABE2C90584900129CC2 /* Algorithms */, + FF70FAC02C90584900129CC2 /* Zip */, ); productName = PadelClub; - productReference = FF8045BE2C90379300A49A52 /* PadelClub TestFlight.app */; + productReference = FF70FBCF2C90584900129CC2 /* PadelClub TestFlight.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -1761,7 +1769,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1520; - LastUpgradeCheck = 1530; + LastUpgradeCheck = 1600; TargetAttributes = { C425D3FC2B6D249D002A7B48 = { CreatedOnToolsVersion = 15.2; @@ -1797,7 +1805,7 @@ C425D3FC2B6D249D002A7B48 /* PadelClub */, C425D40C2B6D249E002A7B48 /* PadelClubTests */, C425D4162B6D249E002A7B48 /* PadelClubUITests */, - FF8044AE2C90379300A49A52 /* PadelClub TestFlight */, + FF70FABD2C90584900129CC2 /* PadelClub TestFlight */, ); }; /* End PBXProject section */ @@ -1842,28 +1850,28 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - FF8045A62C90379300A49A52 /* Resources */ = { + FF70FBB72C90584900129CC2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - FF8045A72C90379300A49A52 /* Preview Assets.xcassets in Resources */, - FF8045A82C90379300A49A52 /* Launch Screen.storyboard in Resources */, - FF8045A92C90379300A49A52 /* tournament-template.html in Resources */, - FF8045AA2C90379300A49A52 /* local.sqlite in Resources */, - FF8045AB2C90379300A49A52 /* groupstagescore-template.html in Resources */, - FF8045AC2C90379300A49A52 /* player-template.html in Resources */, - FF8045AD2C90379300A49A52 /* groupstagerow-template.html in Resources */, - FF8045AE2C90379300A49A52 /* hiddenplayer-template.html in Resources */, - FF8045AF2C90379300A49A52 /* bracket-template.html in Resources */, - FF8045B02C90379300A49A52 /* groupstagecol-template.html in Resources */, - FF8045B12C90379300A49A52 /* groupstage-template.html in Resources */, - FF8045B22C90379300A49A52 /* groupstageentrant-template.html in Resources */, - FF8045B32C90379300A49A52 /* match-template.html in Resources */, - FF8045B42C90379300A49A52 /* Localizable.strings in Resources */, - FF8045B52C90379300A49A52 /* SyncedProducts.storekit in Resources */, - FF8045B62C90379300A49A52 /* local.plist in Resources */, - FF8045B72C90379300A49A52 /* PrivacyInfo.xcprivacy in Resources */, - FF8045B82C90379300A49A52 /* Assets.xcassets in Resources */, + FF70FBB82C90584900129CC2 /* Preview Assets.xcassets in Resources */, + FF70FBB92C90584900129CC2 /* Launch Screen.storyboard in Resources */, + FF70FBBA2C90584900129CC2 /* tournament-template.html in Resources */, + FF70FBBB2C90584900129CC2 /* local.sqlite in Resources */, + FF70FBBC2C90584900129CC2 /* groupstagescore-template.html in Resources */, + FF70FBBD2C90584900129CC2 /* player-template.html in Resources */, + FF70FBBE2C90584900129CC2 /* groupstagerow-template.html in Resources */, + FF70FBBF2C90584900129CC2 /* hiddenplayer-template.html in Resources */, + FF70FBC02C90584900129CC2 /* bracket-template.html in Resources */, + FF70FBC12C90584900129CC2 /* groupstagecol-template.html in Resources */, + FF70FBC22C90584900129CC2 /* groupstage-template.html in Resources */, + FF70FBC32C90584900129CC2 /* groupstageentrant-template.html in Resources */, + FF70FBC42C90584900129CC2 /* match-template.html in Resources */, + FF70FBC52C90584900129CC2 /* Localizable.strings in Resources */, + FF70FBC62C90584900129CC2 /* SyncedProducts.storekit in Resources */, + FF70FBC72C90584900129CC2 /* local.plist in Resources */, + FF70FBC82C90584900129CC2 /* PrivacyInfo.xcprivacy in Resources */, + FF70FBC92C90584900129CC2 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1888,6 +1896,7 @@ FF1CBC1B2BB53D1F0036DAAB /* FederalTournament.swift in Sources */, FF8F26412BADFC8700650388 /* TournamentInitView.swift in Sources */, C4A47D8A2B7BBB6500ADC637 /* SubscriptionView.swift in Sources */, + FFD655D82C8DE27400E5B35E /* TournamentLookUpView.swift in Sources */, FF1DC5572BAB3AED00FD8220 /* ClubsView.swift in Sources */, FFE103122C366E5900684FC9 /* ImagePickerView.swift in Sources */, FF8F264F2BAE0B9600650388 /* MatchTypeSelectionView.swift in Sources */, @@ -1921,11 +1930,11 @@ FFDB1C6D2BB2A02000F1E467 /* AppSettings.swift in Sources */, FF0EC5202BB16F680056B6D1 /* SwiftParser.swift in Sources */, C4A47DA92B85F82100ADC637 /* ChangePasswordView.swift in Sources */, + FF8044AC2C8F676D00A49A52 /* TournamentSubscriptionView.swift in Sources */, FFC83D512BB8087E00750834 /* RoundView.swift in Sources */, FF6EC8F72B94773200EA7F5A /* RowButtonView.swift in Sources */, FF2EFBF02BDE295E0049CE3B /* SendToAllView.swift in Sources */, FF8F263B2BAD528600650388 /* EventCreationView.swift in Sources */, - FF135BF92C2FCB8300C9247A /* LoserGroupStageSettingsView.swift in Sources */, FFC1E1082BAC29FC008D6F59 /* LocationManager.swift in Sources */, C4C01D982C481C0C0059087C /* CapsuleViewModifier.swift in Sources */, FF6087EC2BE26A2F004E1E47 /* BroadcastView.swift in Sources */, @@ -2020,6 +2029,7 @@ FFF8ACCD2B92367B008466FA /* FederalPlayer.swift in Sources */, FFBF06602BBD9F6D009D6715 /* NavigationViewModel.swift in Sources */, FF6EC9092B947A5300EA7F5A /* FixedWidthInteger+Extensions.swift in Sources */, + FF6525C32C8C61B400B9498E /* LoserBracketFromGroupStageView.swift in Sources */, FF5D30512BD94E1000F2B93D /* ImportedPlayer+Extensions.swift in Sources */, FFC1E1042BAC28C6008D6F59 /* ClubSearchView.swift in Sources */, FF089EBB2BB0120700F0AEC7 /* PlayerPopoverView.swift in Sources */, @@ -2136,248 +2146,250 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - FF8044B32C90379300A49A52 /* Sources */ = { + FF70FAC22C90584900129CC2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - FF8044B42C90379300A49A52 /* UserCreationView.swift in Sources */, - FF8044B52C90379300A49A52 /* TabDestination.swift in Sources */, - FF8044B62C90379300A49A52 /* CashierView.swift in Sources */, - FF8044B72C90379300A49A52 /* Event.swift in Sources */, - FF8044B82C90379300A49A52 /* PlayerHolder.swift in Sources */, - FF8044B92C90379300A49A52 /* LoserRoundStepScheduleEditorView.swift in Sources */, - FF8044BA2C90379300A49A52 /* ClubCourtSetupView.swift in Sources */, - FF8044BB2C90379300A49A52 /* Patcher.swift in Sources */, - FF8044BC2C90379300A49A52 /* FileImportView.swift in Sources */, - FF8044BD2C90379300A49A52 /* StepperView.swift in Sources */, - FF8044BE2C90379300A49A52 /* RoundsView.swift in Sources */, - FF8044BF2C90379300A49A52 /* FederalTournament.swift in Sources */, - FF8044C02C90379300A49A52 /* TournamentInitView.swift in Sources */, - FF8044C12C90379300A49A52 /* SubscriptionView.swift in Sources */, - FF8044C22C90379300A49A52 /* ClubsView.swift in Sources */, - FF8044C32C90379300A49A52 /* ImagePickerView.swift in Sources */, - FF8044C42C90379300A49A52 /* MatchTypeSelectionView.swift in Sources */, - FF8044C52C90379300A49A52 /* MatchSetupView.swift in Sources */, - FF8044C62C90379300A49A52 /* NetworkManager.swift in Sources */, - FF8044C72C90379300A49A52 /* EventLinksView.swift in Sources */, - FF8044C82C90379300A49A52 /* SeedInterval.swift in Sources */, - FF8044C92C90379300A49A52 /* TournamentClubSettingsView.swift in Sources */, - FF8044CA2C90379300A49A52 /* GroupStageTeamView.swift in Sources */, - FF8044CB2C90379300A49A52 /* RoundSettingsView.swift in Sources */, - FF8044CC2C90379300A49A52 /* SupportButtonView.swift in Sources */, - FF8044CD2C90379300A49A52 /* TournamentBroadcastRowView.swift in Sources */, - FF8044CE2C90379300A49A52 /* TeamWeightView.swift in Sources */, - FF8044CF2C90379300A49A52 /* SeedsCallingView.swift in Sources */, - FF8044D02C90379300A49A52 /* CallView.swift in Sources */, - FF8044D12C90379300A49A52 /* Color+Extensions.swift in Sources */, - FF8044D22C90379300A49A52 /* EditSharingView.swift in Sources */, - FF8044D32C90379300A49A52 /* TournamentCellView.swift in Sources */, - FF8044D42C90379300A49A52 /* Sequence+Extensions.swift in Sources */, - FF8044D52C90379300A49A52 /* CashierDetailView.swift in Sources */, - FF8044D62C90379300A49A52 /* EventClubSettingsView.swift in Sources */, - FF8044D72C90379300A49A52 /* AccountView.swift in Sources */, - FF8044D82C90379300A49A52 /* PlayersWithoutContactView.swift in Sources */, - FF8044D92C90379300A49A52 /* TeamsCallingView.swift in Sources */, - FF8044DA2C90379300A49A52 /* Calendar+Extensions.swift in Sources */, - FF8044DB2C90379300A49A52 /* TeamScore.swift in Sources */, - FF8044DC2C90379300A49A52 /* EditablePlayerView.swift in Sources */, - FF8044DD2C90379300A49A52 /* PlayerDetailView.swift in Sources */, - FF8044DE2C90379300A49A52 /* ListRowViewModifier.swift in Sources */, - FF8044DF2C90379300A49A52 /* PresentationContext.swift in Sources */, - FF8044E02C90379300A49A52 /* AppSettings.swift in Sources */, - FF8044E12C90379300A49A52 /* SwiftParser.swift in Sources */, - FF8044E22C90379300A49A52 /* ChangePasswordView.swift in Sources */, - FF8044E32C90379300A49A52 /* RoundView.swift in Sources */, - FF8044E42C90379300A49A52 /* RowButtonView.swift in Sources */, - FF8044E52C90379300A49A52 /* SendToAllView.swift in Sources */, - FF8044E62C90379300A49A52 /* EventCreationView.swift in Sources */, - FF8044E72C90379300A49A52 /* LoserGroupStageSettingsView.swift in Sources */, - FF8044E82C90379300A49A52 /* LocationManager.swift in Sources */, - FF8044E92C90379300A49A52 /* CapsuleViewModifier.swift in Sources */, - FF8044EA2C90379300A49A52 /* BroadcastView.swift in Sources */, - FF8044EB2C90379300A49A52 /* SchedulerView.swift in Sources */, - FF8044EC2C90379300A49A52 /* PadelClubButtonView.swift in Sources */, - FF8044ED2C90379300A49A52 /* TournamentSeedEditing.swift in Sources */, - FF8044EE2C90379300A49A52 /* TournamentView.swift in Sources */, - FF8044EF2C90379300A49A52 /* OngoingView.swift in Sources */, - FF8044F02C90379300A49A52 /* CreateClubView.swift in Sources */, - FF8044F12C90379300A49A52 /* APICallsListView.swift in Sources */, - FF8044F22C90379300A49A52 /* NetworkFederalService.swift in Sources */, - FF8044F32C90379300A49A52 /* DurationSettingsView.swift in Sources */, - FF8044F42C90379300A49A52 /* AppScreen.swift in Sources */, - FF8044F52C90379300A49A52 /* CourtView.swift in Sources */, - FF8044F62C90379300A49A52 /* PointSelectionView.swift in Sources */, - FF8044F72C90379300A49A52 /* TeamRowView.swift in Sources */, - FF8044F82C90379300A49A52 /* ContactManager.swift in Sources */, - FF8044F92C90379300A49A52 /* AppDelegate.swift in Sources */, - FF8044FA2C90379300A49A52 /* SubscriptionInfoView.swift in Sources */, - FF8044FB2C90379300A49A52 /* EditScoreView.swift in Sources */, - FF8044FC2C90379300A49A52 /* TournamentOrganizerView.swift in Sources */, - FF8044FD2C90379300A49A52 /* NetworkMonitor.swift in Sources */, - FF8044FE2C90379300A49A52 /* TournamentRunningView.swift in Sources */, - FF8044FF2C90379300A49A52 /* TournamentDatePickerView.swift in Sources */, - FF8045002C90379300A49A52 /* CourtAvailabilitySettingsView.swift in Sources */, - FF8045012C90379300A49A52 /* ConfirmButtonView.swift in Sources */, - FF8045022C90379300A49A52 /* PasswordField.swift in Sources */, - FF8045032C90379300A49A52 /* MatchRowView.swift in Sources */, - FF8045042C90379300A49A52 /* Locale+Extensions.swift in Sources */, - FF8045052C90379300A49A52 /* HtmlService.swift in Sources */, - FF8045062C90379300A49A52 /* GroupStage.swift in Sources */, - FF8045072C90379300A49A52 /* TournamentCashierView.swift in Sources */, - FF8045082C90379300A49A52 /* StoreManager.swift in Sources */, - FF8045092C90379300A49A52 /* SearchViewModel.swift in Sources */, - FF80450A2C90379300A49A52 /* PlayerRegistration.swift in Sources */, - FF80450B2C90379300A49A52 /* ImportedPlayerView.swift in Sources */, - FF80450C2C90379300A49A52 /* EditingTeamView.swift in Sources */, - FF80450D2C90379300A49A52 /* NetworkManagerError.swift in Sources */, - FF80450E2C90379300A49A52 /* Tournament.swift in Sources */, - FF80450F2C90379300A49A52 /* TournamentStore.swift in Sources */, - FF8045102C90379300A49A52 /* LoserRoundSettingsView.swift in Sources */, - FF8045112C90379300A49A52 /* Persistence.swift in Sources */, - FF8045122C90379300A49A52 /* CloseDatePicker.swift in Sources */, - FF8045132C90379300A49A52 /* BarButtonView.swift in Sources */, - FF8045142C90379300A49A52 /* PlanningView.swift in Sources */, - FF8045152C90379300A49A52 /* Match.swift in Sources */, - FF8045162C90379300A49A52 /* TournamentLevelPickerView.swift in Sources */, - FF8045172C90379300A49A52 /* FederalTournamentHolder.swift in Sources */, - FF8045182C90379300A49A52 /* DataStore.swift in Sources */, - FF8045192C90379300A49A52 /* SetDescriptor.swift in Sources */, - FF80451A2C90379300A49A52 /* TeamHeaderView.swift in Sources */, - FF80451B2C90379300A49A52 /* OrganizedTournamentView.swift in Sources */, - FF80451C2C90379300A49A52 /* RoundScheduleEditorView.swift in Sources */, - FF80451D2C90379300A49A52 /* EventListView.swift in Sources */, - FF80451E2C90379300A49A52 /* TournamentConfiguratorView.swift in Sources */, - FF80451F2C90379300A49A52 /* ClubImportView.swift in Sources */, - FF8045202C90379300A49A52 /* UnderlineView.swift in Sources */, - FF8045212C90379300A49A52 /* MatchScheduler.swift in Sources */, - FF8045222C90379300A49A52 /* CallMessageCustomizationView.swift in Sources */, - FF8045232C90379300A49A52 /* TournamentStatusView.swift in Sources */, - FF8045242C90379300A49A52 /* MatchTeamDetailView.swift in Sources */, - FF8045252C90379300A49A52 /* GenericDestinationPickerView.swift in Sources */, - FF8045262C90379300A49A52 /* DateInterval.swift in Sources */, - FF8045272C90379300A49A52 /* TableStructureView.swift in Sources */, - FF8045282C90379300A49A52 /* Purchase.swift in Sources */, - FF8045292C90379300A49A52 /* Screen.swift in Sources */, - FF80452A2C90379300A49A52 /* Round.swift in Sources */, - FF80452B2C90379300A49A52 /* FederalDataViewModel.swift in Sources */, - FF80452C2C90379300A49A52 /* AgendaDestination.swift in Sources */, - FF80452D2C90379300A49A52 /* PadelClubApp.xcdatamodeld in Sources */, - FF80452E2C90379300A49A52 /* SetInputView.swift in Sources */, - FF80452F2C90379300A49A52 /* ButtonValidateView.swift in Sources */, - FF8045302C90379300A49A52 /* ClubRowView.swift in Sources */, - FF8045312C90379300A49A52 /* ClubDetailView.swift in Sources */, - FF8045322C90379300A49A52 /* GroupStageCallingView.swift in Sources */, - FF8045332C90379300A49A52 /* Key.swift in Sources */, - FF8045342C90379300A49A52 /* CashierSettingsView.swift in Sources */, - FF8045352C90379300A49A52 /* LoserRoundScheduleEditorView.swift in Sources */, - FF8045362C90379300A49A52 /* Club.swift in Sources */, - FF8045372C90379300A49A52 /* Array+Extensions.swift in Sources */, - FF8045382C90379300A49A52 /* ToolboxView.swift in Sources */, - FF8045392C90379300A49A52 /* Alphabet.swift in Sources */, - FF80453A2C90379300A49A52 /* String+Extensions.swift in Sources */, - FF80453B2C90379300A49A52 /* GroupStageSettingsView.swift in Sources */, - FF80453C2C90379300A49A52 /* TournamentGeneralSettingsView.swift in Sources */, - FF80453D2C90379300A49A52 /* LoserRoundView.swift in Sources */, - FF80453E2C90379300A49A52 /* AddTeamView.swift in Sources */, - FF80453F2C90379300A49A52 /* PlayerPayView.swift in Sources */, - FF8045402C90379300A49A52 /* PlanningByCourtView.swift in Sources */, - FF8045412C90379300A49A52 /* FileImportManager.swift in Sources */, - FF8045422C90379300A49A52 /* TournamentButtonView.swift in Sources */, - FF8045432C90379300A49A52 /* FederalPlayer.swift in Sources */, - FF8045442C90379300A49A52 /* NavigationViewModel.swift in Sources */, - FF8045452C90379300A49A52 /* FixedWidthInteger+Extensions.swift in Sources */, - FF8045462C90379300A49A52 /* ImportedPlayer+Extensions.swift in Sources */, - FF8045472C90379300A49A52 /* ClubSearchView.swift in Sources */, - FF8045482C90379300A49A52 /* PlayerPopoverView.swift in Sources */, - FF8045492C90379300A49A52 /* InscriptionManagerView.swift in Sources */, - FF80454A2C90379300A49A52 /* ActivityView.swift in Sources */, - FF80454B2C90379300A49A52 /* MySortDescriptor.swift in Sources */, - FF80454C2C90379300A49A52 /* CalendarView.swift in Sources */, - FF80454D2C90379300A49A52 /* FederalTournamentSearchScope.swift in Sources */, - FF80454E2C90379300A49A52 /* TournamentFieldsManagerView.swift in Sources */, - FF80454F2C90379300A49A52 /* PrintSettingsView.swift in Sources */, - FF8045502C90379300A49A52 /* TournamentMatchFormatsSettingsView.swift in Sources */, - FF8045512C90379300A49A52 /* DateUpdateManagerView.swift in Sources */, - FF8045522C90379300A49A52 /* MatchTypeSmallSelectionView.swift in Sources */, - FF8045532C90379300A49A52 /* MonthData.swift in Sources */, - FF8045542C90379300A49A52 /* MenuWarningView.swift in Sources */, - FF8045552C90379300A49A52 /* TournamentBuildView.swift in Sources */, - FF8045562C90379300A49A52 /* TeamPickerView.swift in Sources */, - FF8045572C90379300A49A52 /* CloudConvert.swift in Sources */, - FF8045582C90379300A49A52 /* EventTournamentsView.swift in Sources */, - FF8045592C90379300A49A52 /* DisplayContext.swift in Sources */, - FF80455A2C90379300A49A52 /* TournamentCallView.swift in Sources */, - FF80455B2C90379300A49A52 /* LoserRoundsView.swift in Sources */, - FF80455C2C90379300A49A52 /* GroupStagesView.swift in Sources */, - FF80455D2C90379300A49A52 /* PadelClubView.swift in Sources */, - FF80455E2C90379300A49A52 /* URLs.swift in Sources */, - FF80455F2C90379300A49A52 /* MatchDescriptor.swift in Sources */, - FF8045602C90379300A49A52 /* TournamentFormatSelectionView.swift in Sources */, - FF8045612C90379300A49A52 /* MatchListView.swift in Sources */, - FF8045622C90379300A49A52 /* PadelClubApp.swift in Sources */, - FF8045632C90379300A49A52 /* TournamentSettingsView.swift in Sources */, - FF8045642C90379300A49A52 /* String+Crypto.swift in Sources */, - FF8045652C90379300A49A52 /* GroupStageTeamReplacementView.swift in Sources */, - FF8045662C90379300A49A52 /* TabItemModifier.swift in Sources */, - FF8045672C90379300A49A52 /* DeferredViewModifier.swift in Sources */, - FF8045682C90379300A49A52 /* TournamentScheduleView.swift in Sources */, - FF8045692C90379300A49A52 /* MatchFormatStorageView.swift in Sources */, - FF80456A2C90379300A49A52 /* UmpireView.swift in Sources */, - FF80456B2C90379300A49A52 /* User.swift in Sources */, - FF80456C2C90379300A49A52 /* MatchSummaryView.swift in Sources */, - FF80456D2C90379300A49A52 /* TournamentDurationManagerView.swift in Sources */, - FF80456E2C90379300A49A52 /* MockData.swift in Sources */, - FF80456F2C90379300A49A52 /* TeamDetailView.swift in Sources */, - FF8045702C90379300A49A52 /* GroupStagesSettingsView.swift in Sources */, - FF8045712C90379300A49A52 /* TournamentFilterView.swift in Sources */, - FF8045722C90379300A49A52 /* HtmlGenerator.swift in Sources */, - FF8045732C90379300A49A52 /* PadelRule.swift in Sources */, - FF8045742C90379300A49A52 /* TeamRegistration.swift in Sources */, - FF8045752C90379300A49A52 /* Date+Extensions.swift in Sources */, - FF8045762C90379300A49A52 /* GroupStageView.swift in Sources */, - FF8045772C90379300A49A52 /* Tips.swift in Sources */, - FF8045782C90379300A49A52 /* MainView.swift in Sources */, - FF8045792C90379300A49A52 /* MatchDateView.swift in Sources */, - FF80457A2C90379300A49A52 /* PlanningSettingsView.swift in Sources */, - FF80457B2C90379300A49A52 /* MatchScheduleEditorView.swift in Sources */, - FF80457C2C90379300A49A52 /* FortuneWheelView.swift in Sources */, - FF80457D2C90379300A49A52 /* URL+Extensions.swift in Sources */, - FF80457E2C90379300A49A52 /* LoadingViewModifier.swift in Sources */, - FF80457F2C90379300A49A52 /* PlayerView.swift in Sources */, - FF8045802C90379300A49A52 /* MatchDetailView.swift in Sources */, - FF8045812C90379300A49A52 /* ExportFormat.swift in Sources */, - FF8045822C90379300A49A52 /* PlayerBlockView.swift in Sources */, - FF8045832C90379300A49A52 /* StoreItem.swift in Sources */, - FF8045842C90379300A49A52 /* Selectable.swift in Sources */, - FF8045852C90379300A49A52 /* PointView.swift in Sources */, - FF8045862C90379300A49A52 /* ClubHolder.swift in Sources */, - FF8045872C90379300A49A52 /* EventSettingsView.swift in Sources */, - FF8045882C90379300A49A52 /* InscriptionInfoView.swift in Sources */, - FF8045892C90379300A49A52 /* SelectablePlayerListView.swift in Sources */, - FF80458A2C90379300A49A52 /* MatchFormatPickerView.swift in Sources */, - FF80458B2C90379300A49A52 /* TournamentRankView.swift in Sources */, - FF80458C2C90379300A49A52 /* NumberFormatter+Extensions.swift in Sources */, - FF80458D2C90379300A49A52 /* SetLabelView.swift in Sources */, - FF80458E2C90379300A49A52 /* DebugSettingsView.swift in Sources */, - FF80458F2C90379300A49A52 /* GroupStageScheduleEditorView.swift in Sources */, - FF8045902C90379300A49A52 /* EventView.swift in Sources */, - FF8045912C90379300A49A52 /* LoginView.swift in Sources */, - FF8045922C90379300A49A52 /* Court.swift in Sources */, - FF8045932C90379300A49A52 /* Labels.swift in Sources */, - FF8045942C90379300A49A52 /* CopyPasteButtonView.swift in Sources */, - FF8045952C90379300A49A52 /* PlayerSexPickerView.swift in Sources */, - FF8045962C90379300A49A52 /* TournamentInscriptionView.swift in Sources */, - FF8045972C90379300A49A52 /* CallSettingsView.swift in Sources */, - FF8045982C90379300A49A52 /* FooterButtonView.swift in Sources */, - FF8045992C90379300A49A52 /* RankCalculatorView.swift in Sources */, - FF80459A2C90379300A49A52 /* DateBoxView.swift in Sources */, - FF80459B2C90379300A49A52 /* LearnMoreSheetView.swift in Sources */, - FF80459C2C90379300A49A52 /* SourceFileManager.swift in Sources */, - FF80459D2C90379300A49A52 /* PListReader.swift in Sources */, - FF80459E2C90379300A49A52 /* UpdateSourceRankDateView.swift in Sources */, - FF80459F2C90379300A49A52 /* GlobalSettingsView.swift in Sources */, - FF8045A02C90379300A49A52 /* Guard.swift in Sources */, - FF8045A12C90379300A49A52 /* PurchaseListView.swift in Sources */, + FF70FAC32C90584900129CC2 /* UserCreationView.swift in Sources */, + FF70FAC42C90584900129CC2 /* TabDestination.swift in Sources */, + FF70FAC52C90584900129CC2 /* CashierView.swift in Sources */, + FF70FAC62C90584900129CC2 /* Event.swift in Sources */, + FF70FAC72C90584900129CC2 /* PlayerHolder.swift in Sources */, + FF70FAC82C90584900129CC2 /* LoserRoundStepScheduleEditorView.swift in Sources */, + FF70FAC92C90584900129CC2 /* ClubCourtSetupView.swift in Sources */, + FF70FACA2C90584900129CC2 /* Patcher.swift in Sources */, + FF70FACB2C90584900129CC2 /* FileImportView.swift in Sources */, + FF70FACC2C90584900129CC2 /* StepperView.swift in Sources */, + FF70FACD2C90584900129CC2 /* RoundsView.swift in Sources */, + FF70FACE2C90584900129CC2 /* FederalTournament.swift in Sources */, + FF70FACF2C90584900129CC2 /* TournamentInitView.swift in Sources */, + FF70FAD02C90584900129CC2 /* SubscriptionView.swift in Sources */, + FF70FAD12C90584900129CC2 /* TournamentLookUpView.swift in Sources */, + FF70FAD22C90584900129CC2 /* ClubsView.swift in Sources */, + FF70FAD32C90584900129CC2 /* ImagePickerView.swift in Sources */, + FF70FAD42C90584900129CC2 /* MatchTypeSelectionView.swift in Sources */, + FF70FAD52C90584900129CC2 /* MatchSetupView.swift in Sources */, + FF70FAD62C90584900129CC2 /* NetworkManager.swift in Sources */, + FF70FAD72C90584900129CC2 /* EventLinksView.swift in Sources */, + FF70FAD82C90584900129CC2 /* SeedInterval.swift in Sources */, + FF70FAD92C90584900129CC2 /* TournamentClubSettingsView.swift in Sources */, + FF70FADA2C90584900129CC2 /* GroupStageTeamView.swift in Sources */, + FF70FADB2C90584900129CC2 /* RoundSettingsView.swift in Sources */, + FF70FADC2C90584900129CC2 /* SupportButtonView.swift in Sources */, + FF70FADD2C90584900129CC2 /* TournamentBroadcastRowView.swift in Sources */, + FF70FADE2C90584900129CC2 /* TeamWeightView.swift in Sources */, + FF70FADF2C90584900129CC2 /* SeedsCallingView.swift in Sources */, + FF70FAE02C90584900129CC2 /* CallView.swift in Sources */, + FF70FAE12C90584900129CC2 /* Color+Extensions.swift in Sources */, + FF70FAE22C90584900129CC2 /* EditSharingView.swift in Sources */, + FF70FAE32C90584900129CC2 /* TournamentCellView.swift in Sources */, + FF70FAE42C90584900129CC2 /* Sequence+Extensions.swift in Sources */, + FF70FAE52C90584900129CC2 /* CashierDetailView.swift in Sources */, + FF70FAE62C90584900129CC2 /* EventClubSettingsView.swift in Sources */, + FF70FAE72C90584900129CC2 /* AccountView.swift in Sources */, + FF70FAE82C90584900129CC2 /* PlayersWithoutContactView.swift in Sources */, + FF70FAE92C90584900129CC2 /* TeamsCallingView.swift in Sources */, + FF70FAEA2C90584900129CC2 /* Calendar+Extensions.swift in Sources */, + FF70FAEB2C90584900129CC2 /* TeamScore.swift in Sources */, + FF70FAEC2C90584900129CC2 /* EditablePlayerView.swift in Sources */, + FF70FAED2C90584900129CC2 /* PlayerDetailView.swift in Sources */, + FF70FAEE2C90584900129CC2 /* ListRowViewModifier.swift in Sources */, + FF70FAEF2C90584900129CC2 /* PresentationContext.swift in Sources */, + FF70FAF02C90584900129CC2 /* AppSettings.swift in Sources */, + FF70FAF12C90584900129CC2 /* SwiftParser.swift in Sources */, + FF70FAF22C90584900129CC2 /* ChangePasswordView.swift in Sources */, + FF70FAF32C90584900129CC2 /* TournamentSubscriptionView.swift in Sources */, + FF70FAF42C90584900129CC2 /* RoundView.swift in Sources */, + FF70FAF52C90584900129CC2 /* RowButtonView.swift in Sources */, + FF70FAF62C90584900129CC2 /* SendToAllView.swift in Sources */, + FF70FAF72C90584900129CC2 /* EventCreationView.swift in Sources */, + FF70FAF82C90584900129CC2 /* LocationManager.swift in Sources */, + FF70FAF92C90584900129CC2 /* CapsuleViewModifier.swift in Sources */, + FF70FAFA2C90584900129CC2 /* BroadcastView.swift in Sources */, + FF70FAFB2C90584900129CC2 /* SchedulerView.swift in Sources */, + FF70FAFC2C90584900129CC2 /* PadelClubButtonView.swift in Sources */, + FF70FAFD2C90584900129CC2 /* TournamentSeedEditing.swift in Sources */, + FF70FAFE2C90584900129CC2 /* TournamentView.swift in Sources */, + FF70FAFF2C90584900129CC2 /* OngoingView.swift in Sources */, + FF70FB002C90584900129CC2 /* CreateClubView.swift in Sources */, + FF70FB012C90584900129CC2 /* APICallsListView.swift in Sources */, + FF70FB022C90584900129CC2 /* NetworkFederalService.swift in Sources */, + FF70FB032C90584900129CC2 /* DurationSettingsView.swift in Sources */, + FF70FB042C90584900129CC2 /* AppScreen.swift in Sources */, + FF70FB052C90584900129CC2 /* CourtView.swift in Sources */, + FF70FB062C90584900129CC2 /* PointSelectionView.swift in Sources */, + FF70FB072C90584900129CC2 /* TeamRowView.swift in Sources */, + FF70FB082C90584900129CC2 /* ContactManager.swift in Sources */, + FF70FB092C90584900129CC2 /* AppDelegate.swift in Sources */, + FF70FB0A2C90584900129CC2 /* SubscriptionInfoView.swift in Sources */, + FF70FB0B2C90584900129CC2 /* EditScoreView.swift in Sources */, + FF70FB0C2C90584900129CC2 /* TournamentOrganizerView.swift in Sources */, + FF70FB0D2C90584900129CC2 /* NetworkMonitor.swift in Sources */, + FF70FB0E2C90584900129CC2 /* TournamentRunningView.swift in Sources */, + FF70FB0F2C90584900129CC2 /* TournamentDatePickerView.swift in Sources */, + FF70FB102C90584900129CC2 /* CourtAvailabilitySettingsView.swift in Sources */, + FF70FB112C90584900129CC2 /* ConfirmButtonView.swift in Sources */, + FF70FB122C90584900129CC2 /* PasswordField.swift in Sources */, + FF70FB132C90584900129CC2 /* MatchRowView.swift in Sources */, + FF70FB142C90584900129CC2 /* Locale+Extensions.swift in Sources */, + FF70FB152C90584900129CC2 /* HtmlService.swift in Sources */, + FF70FB162C90584900129CC2 /* GroupStage.swift in Sources */, + FF70FB172C90584900129CC2 /* TournamentCashierView.swift in Sources */, + FF70FB182C90584900129CC2 /* StoreManager.swift in Sources */, + FF70FB192C90584900129CC2 /* SearchViewModel.swift in Sources */, + FF70FB1A2C90584900129CC2 /* PlayerRegistration.swift in Sources */, + FF70FB1B2C90584900129CC2 /* ImportedPlayerView.swift in Sources */, + FF70FB1C2C90584900129CC2 /* EditingTeamView.swift in Sources */, + FF70FB1D2C90584900129CC2 /* NetworkManagerError.swift in Sources */, + FF70FB1E2C90584900129CC2 /* Tournament.swift in Sources */, + FF70FB1F2C90584900129CC2 /* TournamentStore.swift in Sources */, + FF70FB202C90584900129CC2 /* LoserRoundSettingsView.swift in Sources */, + FF70FB212C90584900129CC2 /* Persistence.swift in Sources */, + FF70FB222C90584900129CC2 /* CloseDatePicker.swift in Sources */, + FF70FB232C90584900129CC2 /* BarButtonView.swift in Sources */, + FF70FB242C90584900129CC2 /* PlanningView.swift in Sources */, + FF70FB252C90584900129CC2 /* Match.swift in Sources */, + FF70FB262C90584900129CC2 /* TournamentLevelPickerView.swift in Sources */, + FF70FB272C90584900129CC2 /* FederalTournamentHolder.swift in Sources */, + FF70FB282C90584900129CC2 /* DataStore.swift in Sources */, + FF70FB292C90584900129CC2 /* SetDescriptor.swift in Sources */, + FF70FB2A2C90584900129CC2 /* TeamHeaderView.swift in Sources */, + FF70FB2B2C90584900129CC2 /* OrganizedTournamentView.swift in Sources */, + FF70FB2C2C90584900129CC2 /* RoundScheduleEditorView.swift in Sources */, + FF70FB2D2C90584900129CC2 /* EventListView.swift in Sources */, + FF70FB2E2C90584900129CC2 /* TournamentConfiguratorView.swift in Sources */, + FF70FB2F2C90584900129CC2 /* ClubImportView.swift in Sources */, + FF70FB302C90584900129CC2 /* UnderlineView.swift in Sources */, + FF70FB312C90584900129CC2 /* MatchScheduler.swift in Sources */, + FF70FB322C90584900129CC2 /* CallMessageCustomizationView.swift in Sources */, + FF70FB332C90584900129CC2 /* TournamentStatusView.swift in Sources */, + FF70FB342C90584900129CC2 /* MatchTeamDetailView.swift in Sources */, + FF70FB352C90584900129CC2 /* GenericDestinationPickerView.swift in Sources */, + FF70FB362C90584900129CC2 /* DateInterval.swift in Sources */, + FF70FB372C90584900129CC2 /* TableStructureView.swift in Sources */, + FF70FB382C90584900129CC2 /* Purchase.swift in Sources */, + FF70FB392C90584900129CC2 /* Screen.swift in Sources */, + FF70FB3A2C90584900129CC2 /* Round.swift in Sources */, + FF70FB3B2C90584900129CC2 /* FederalDataViewModel.swift in Sources */, + FF70FB3C2C90584900129CC2 /* AgendaDestination.swift in Sources */, + FF70FB3D2C90584900129CC2 /* PadelClubApp.xcdatamodeld in Sources */, + FF70FB3E2C90584900129CC2 /* SetInputView.swift in Sources */, + FF70FB3F2C90584900129CC2 /* ButtonValidateView.swift in Sources */, + FF70FB402C90584900129CC2 /* ClubRowView.swift in Sources */, + FF70FB412C90584900129CC2 /* ClubDetailView.swift in Sources */, + FF70FB422C90584900129CC2 /* GroupStageCallingView.swift in Sources */, + FF70FB432C90584900129CC2 /* Key.swift in Sources */, + FF70FB442C90584900129CC2 /* CashierSettingsView.swift in Sources */, + FF70FB452C90584900129CC2 /* LoserRoundScheduleEditorView.swift in Sources */, + FF70FB462C90584900129CC2 /* Club.swift in Sources */, + FF70FB472C90584900129CC2 /* Array+Extensions.swift in Sources */, + FF70FB482C90584900129CC2 /* ToolboxView.swift in Sources */, + FF70FB492C90584900129CC2 /* Alphabet.swift in Sources */, + FF70FB4A2C90584900129CC2 /* String+Extensions.swift in Sources */, + FF70FB4B2C90584900129CC2 /* GroupStageSettingsView.swift in Sources */, + FF70FB4C2C90584900129CC2 /* TournamentGeneralSettingsView.swift in Sources */, + FF70FB4D2C90584900129CC2 /* LoserRoundView.swift in Sources */, + FF70FB4E2C90584900129CC2 /* AddTeamView.swift in Sources */, + FF70FB4F2C90584900129CC2 /* PlayerPayView.swift in Sources */, + FF70FB502C90584900129CC2 /* PlanningByCourtView.swift in Sources */, + FF70FB512C90584900129CC2 /* FileImportManager.swift in Sources */, + FF70FB522C90584900129CC2 /* TournamentButtonView.swift in Sources */, + FF70FB532C90584900129CC2 /* FederalPlayer.swift in Sources */, + FF70FB542C90584900129CC2 /* NavigationViewModel.swift in Sources */, + FF70FB552C90584900129CC2 /* FixedWidthInteger+Extensions.swift in Sources */, + FF70FB562C90584900129CC2 /* LoserBracketFromGroupStageView.swift in Sources */, + FF70FB572C90584900129CC2 /* ImportedPlayer+Extensions.swift in Sources */, + FF70FB582C90584900129CC2 /* ClubSearchView.swift in Sources */, + FF70FB592C90584900129CC2 /* PlayerPopoverView.swift in Sources */, + FF70FB5A2C90584900129CC2 /* InscriptionManagerView.swift in Sources */, + FF70FB5B2C90584900129CC2 /* ActivityView.swift in Sources */, + FF70FB5C2C90584900129CC2 /* MySortDescriptor.swift in Sources */, + FF70FB5D2C90584900129CC2 /* CalendarView.swift in Sources */, + FF70FB5E2C90584900129CC2 /* FederalTournamentSearchScope.swift in Sources */, + FF70FB5F2C90584900129CC2 /* TournamentFieldsManagerView.swift in Sources */, + FF70FB602C90584900129CC2 /* PrintSettingsView.swift in Sources */, + FF70FB612C90584900129CC2 /* TournamentMatchFormatsSettingsView.swift in Sources */, + FF70FB622C90584900129CC2 /* DateUpdateManagerView.swift in Sources */, + FF70FB632C90584900129CC2 /* MatchTypeSmallSelectionView.swift in Sources */, + FF70FB642C90584900129CC2 /* MonthData.swift in Sources */, + FF70FB652C90584900129CC2 /* MenuWarningView.swift in Sources */, + FF70FB662C90584900129CC2 /* TournamentBuildView.swift in Sources */, + FF70FB672C90584900129CC2 /* TeamPickerView.swift in Sources */, + FF70FB682C90584900129CC2 /* CloudConvert.swift in Sources */, + FF70FB692C90584900129CC2 /* EventTournamentsView.swift in Sources */, + FF70FB6A2C90584900129CC2 /* DisplayContext.swift in Sources */, + FF70FB6B2C90584900129CC2 /* TournamentCallView.swift in Sources */, + FF70FB6C2C90584900129CC2 /* LoserRoundsView.swift in Sources */, + FF70FB6D2C90584900129CC2 /* GroupStagesView.swift in Sources */, + FF70FB6E2C90584900129CC2 /* PadelClubView.swift in Sources */, + FF70FB6F2C90584900129CC2 /* URLs.swift in Sources */, + FF70FB702C90584900129CC2 /* MatchDescriptor.swift in Sources */, + FF70FB712C90584900129CC2 /* TournamentFormatSelectionView.swift in Sources */, + FF70FB722C90584900129CC2 /* MatchListView.swift in Sources */, + FF70FB732C90584900129CC2 /* PadelClubApp.swift in Sources */, + FF70FB742C90584900129CC2 /* TournamentSettingsView.swift in Sources */, + FF70FB752C90584900129CC2 /* String+Crypto.swift in Sources */, + FF70FB762C90584900129CC2 /* GroupStageTeamReplacementView.swift in Sources */, + FF70FB772C90584900129CC2 /* TabItemModifier.swift in Sources */, + FF70FB782C90584900129CC2 /* DeferredViewModifier.swift in Sources */, + FF70FB792C90584900129CC2 /* TournamentScheduleView.swift in Sources */, + FF70FB7A2C90584900129CC2 /* MatchFormatStorageView.swift in Sources */, + FF70FB7B2C90584900129CC2 /* UmpireView.swift in Sources */, + FF70FB7C2C90584900129CC2 /* User.swift in Sources */, + FF70FB7D2C90584900129CC2 /* MatchSummaryView.swift in Sources */, + FF70FB7E2C90584900129CC2 /* TournamentDurationManagerView.swift in Sources */, + FF70FB7F2C90584900129CC2 /* MockData.swift in Sources */, + FF70FB802C90584900129CC2 /* TeamDetailView.swift in Sources */, + FF70FB812C90584900129CC2 /* GroupStagesSettingsView.swift in Sources */, + FF70FB822C90584900129CC2 /* TournamentFilterView.swift in Sources */, + FF70FB832C90584900129CC2 /* HtmlGenerator.swift in Sources */, + FF70FB842C90584900129CC2 /* PadelRule.swift in Sources */, + FF70FB852C90584900129CC2 /* TeamRegistration.swift in Sources */, + FF70FB862C90584900129CC2 /* Date+Extensions.swift in Sources */, + FF70FB872C90584900129CC2 /* GroupStageView.swift in Sources */, + FF70FB882C90584900129CC2 /* Tips.swift in Sources */, + FF70FB892C90584900129CC2 /* MainView.swift in Sources */, + FF70FB8A2C90584900129CC2 /* MatchDateView.swift in Sources */, + FF70FB8B2C90584900129CC2 /* PlanningSettingsView.swift in Sources */, + FF70FB8C2C90584900129CC2 /* MatchScheduleEditorView.swift in Sources */, + FF70FB8D2C90584900129CC2 /* FortuneWheelView.swift in Sources */, + FF70FB8E2C90584900129CC2 /* URL+Extensions.swift in Sources */, + FF70FB8F2C90584900129CC2 /* LoadingViewModifier.swift in Sources */, + FF70FB902C90584900129CC2 /* PlayerView.swift in Sources */, + FF70FB912C90584900129CC2 /* MatchDetailView.swift in Sources */, + FF70FB922C90584900129CC2 /* ExportFormat.swift in Sources */, + FF70FB932C90584900129CC2 /* PlayerBlockView.swift in Sources */, + FF70FB942C90584900129CC2 /* StoreItem.swift in Sources */, + FF70FB952C90584900129CC2 /* Selectable.swift in Sources */, + FF70FB962C90584900129CC2 /* PointView.swift in Sources */, + FF70FB972C90584900129CC2 /* ClubHolder.swift in Sources */, + FF70FB982C90584900129CC2 /* EventSettingsView.swift in Sources */, + FF70FB992C90584900129CC2 /* InscriptionInfoView.swift in Sources */, + FF70FB9A2C90584900129CC2 /* SelectablePlayerListView.swift in Sources */, + FF70FB9B2C90584900129CC2 /* MatchFormatPickerView.swift in Sources */, + FF70FB9C2C90584900129CC2 /* TournamentRankView.swift in Sources */, + FF70FB9D2C90584900129CC2 /* NumberFormatter+Extensions.swift in Sources */, + FF70FB9E2C90584900129CC2 /* SetLabelView.swift in Sources */, + FF70FB9F2C90584900129CC2 /* DebugSettingsView.swift in Sources */, + FF70FBA02C90584900129CC2 /* GroupStageScheduleEditorView.swift in Sources */, + FF70FBA12C90584900129CC2 /* EventView.swift in Sources */, + FF70FBA22C90584900129CC2 /* LoginView.swift in Sources */, + FF70FBA32C90584900129CC2 /* Court.swift in Sources */, + FF70FBA42C90584900129CC2 /* Labels.swift in Sources */, + FF70FBA52C90584900129CC2 /* CopyPasteButtonView.swift in Sources */, + FF70FBA62C90584900129CC2 /* PlayerSexPickerView.swift in Sources */, + FF70FBA72C90584900129CC2 /* TournamentInscriptionView.swift in Sources */, + FF70FBA82C90584900129CC2 /* CallSettingsView.swift in Sources */, + FF70FBA92C90584900129CC2 /* FooterButtonView.swift in Sources */, + FF70FBAA2C90584900129CC2 /* RankCalculatorView.swift in Sources */, + FF70FBAB2C90584900129CC2 /* DateBoxView.swift in Sources */, + FF70FBAC2C90584900129CC2 /* LearnMoreSheetView.swift in Sources */, + FF70FBAD2C90584900129CC2 /* SourceFileManager.swift in Sources */, + FF70FBAE2C90584900129CC2 /* PListReader.swift in Sources */, + FF70FBAF2C90584900129CC2 /* UpdateSourceRankDateView.swift in Sources */, + FF70FBB02C90584900129CC2 /* GlobalSettingsView.swift in Sources */, + FF70FBB12C90584900129CC2 /* Guard.swift in Sources */, + FF70FBB22C90584900129CC2 /* PurchaseListView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2414,6 +2426,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -2443,14 +2456,12 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -2468,7 +2479,6 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; @@ -2477,6 +2487,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -2506,7 +2517,6 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -2541,9 +2551,6 @@ DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; - ENABLE_MODULE_VERIFIER = YES; - ENABLE_PREVIEWS = YES; - GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PadelClub/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Padel Club"; @@ -2561,18 +2568,13 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.7; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - OTHER_SWIFT_FLAGS = "-Onone"; + MARKETING_VERSION = 1.0.8; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -2590,8 +2592,6 @@ DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; - ENABLE_MODULE_VERIFIER = YES; - ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PadelClub/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Padel Club"; @@ -2609,17 +2609,13 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.7; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=5 -Xfrontend -warn-long-expression-type-checking=20 -Xfrontend -warn-long-function-bodies=50"; + MARKETING_VERSION = 1.0.8; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -2628,7 +2624,6 @@ C425D4252B6D249E002A7B48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -2648,7 +2643,6 @@ C425D4262B6D249E002A7B48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -2668,7 +2662,6 @@ C425D4282B6D249E002A7B48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 526E96RFNP; @@ -2686,7 +2679,6 @@ C425D4292B6D249E002A7B48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 526E96RFNP; @@ -2701,7 +2693,7 @@ }; name = Release; }; - FF8045BC2C90379300A49A52 /* Debug */ = { + FF70FBCD2C90584900129CC2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -2709,16 +2701,14 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 4; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; - ENABLE_MODULE_VERIFIER = YES; - ENABLE_PREVIEWS = YES; - GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "Padel Club"; + INFOPLIST_FILE = PadelClub/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Padel Club (Beta)"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_NSCameraUsageDescription = "En autorisant l'application à utiliser la caméra, vous pourrez prendre des photos des rencontres"; @@ -2733,24 +2723,19 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.7; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - OTHER_SWIFT_FLAGS = "-Onone"; - PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; + MARKETING_VERSION = 1.0.8; + PRODUCT_BUNDLE_IDENTIFIER = app.padelclub.beta; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; - FF8045BD2C90379300A49A52 /* Release */ = { + FF70FBCE2C90584900129CC2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -2758,14 +2743,13 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 4; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; - ENABLE_MODULE_VERIFIER = YES; - ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "Padel Club"; + INFOPLIST_FILE = PadelClub/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Padel Club (Beta)"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_NSCameraUsageDescription = "En autorisant l'application à utiliser la caméra, vous pourrez prendre des photos des rencontres"; @@ -2780,18 +2764,14 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.7; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=5 -Xfrontend -warn-long-expression-type-checking=20 -Xfrontend -warn-long-function-bodies=50"; - PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; + MARKETING_VERSION = 1.0.8; + PRODUCT_BUNDLE_IDENTIFIER = app.padelclub.beta; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = TESTFLIGHT; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -2836,11 +2816,11 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - FF8045BB2C90379300A49A52 /* Build configuration list for PBXNativeTarget "PadelClub TestFlight" */ = { + FF70FBCC2C90584900129CC2 /* Build configuration list for PBXNativeTarget "PadelClub TestFlight" */ = { isa = XCConfigurationList; buildConfigurations = ( - FF8045BC2C90379300A49A52 /* Debug */, - FF8045BD2C90379300A49A52 /* Release */, + FF70FBCD2C90584900129CC2 /* Debug */, + FF70FBCE2C90584900129CC2 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -2856,7 +2836,7 @@ minimumVersion = 1.2.0; }; }; - FF8044B02C90379300A49A52 /* XCRemoteSwiftPackageReference "swift-algorithms" */ = { + FF70FABF2C90584900129CC2 /* XCRemoteSwiftPackageReference "swift-algorithms" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/apple/swift-algorithms.git"; requirement = { @@ -2864,7 +2844,7 @@ minimumVersion = 1.2.0; }; }; - FF8044B22C90379300A49A52 /* XCRemoteSwiftPackageReference "Zip" */ = { + FF70FAC12C90584900129CC2 /* XCRemoteSwiftPackageReference "Zip" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/marmelroy/Zip"; requirement = { @@ -2883,14 +2863,14 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - FF8044AF2C90379300A49A52 /* Algorithms */ = { + FF70FABE2C90584900129CC2 /* Algorithms */ = { isa = XCSwiftPackageProductDependency; - package = FF8044B02C90379300A49A52 /* XCRemoteSwiftPackageReference "swift-algorithms" */; + package = FF70FABF2C90584900129CC2 /* XCRemoteSwiftPackageReference "swift-algorithms" */; productName = Algorithms; }; - FF8044B12C90379300A49A52 /* Zip */ = { + FF70FAC02C90584900129CC2 /* Zip */ = { isa = XCSwiftPackageProductDependency; - package = FF8044B22C90379300A49A52 /* XCRemoteSwiftPackageReference "Zip" */; + package = FF70FAC12C90584900129CC2 /* XCRemoteSwiftPackageReference "Zip" */; productName = Zip; }; FF92660C2C241CE0002361A4 /* Zip */ = { diff --git a/PadelClub.xcodeproj/xcshareddata/xcschemes/PadelClub Raw.xcscheme b/PadelClub.xcodeproj/xcshareddata/xcschemes/PadelClub Raw.xcscheme index c2b6b23..ec242ea 100644 --- a/PadelClub.xcodeproj/xcshareddata/xcschemes/PadelClub Raw.xcscheme +++ b/PadelClub.xcodeproj/xcshareddata/xcschemes/PadelClub Raw.xcscheme @@ -1,6 +1,6 @@ @@ -31,7 +31,7 @@ shouldAutocreateTestPlan = "YES"> @@ -57,6 +57,16 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> + + + + diff --git a/PadelClub.xcodeproj/xcshareddata/xcschemes/PadelClub.xcscheme b/PadelClub.xcodeproj/xcshareddata/xcschemes/PadelClub.xcscheme index d92da1f..c9495dd 100644 --- a/PadelClub.xcodeproj/xcshareddata/xcschemes/PadelClub.xcscheme +++ b/PadelClub.xcodeproj/xcshareddata/xcschemes/PadelClub.xcscheme @@ -1,6 +1,6 @@ Bool { male } - + + func pasteData() -> String { + return [firstName?.capitalized, lastName?.capitalized, license?.computedLicense].compactMap({ $0 }).joined(separator: " ") + } + func isNotFromCurrentDate() -> Bool { if let importDate, importDate != SourceFileManager.shared.lastDataSourceDate() { return true diff --git a/PadelClub/Data/Federal/FederalTournament.swift b/PadelClub/Data/Federal/FederalTournament.swift index 0a473ee..a535417 100644 --- a/PadelClub/Data/Federal/FederalTournament.swift +++ b/PadelClub/Data/Federal/FederalTournament.swift @@ -7,10 +7,23 @@ import Foundation import CoreLocation import LeStorage -enum DayPeriod { +enum DayPeriod: CaseIterable, Identifiable { + var id: Self { self } + case all case weekend case week + + func localizedDayPeriodLabel() -> String { + switch self { + case .all: + return "n'importe" + case .week: + return "la semaine" + case .weekend: + return "le week-end" + } + } } // MARK: - FederalTournament @@ -126,10 +139,34 @@ struct FederalTournament: Identifiable, Codable { ?? [] } + var federalClub: FederalClub? { + if let codeClub { + return FederalClub(federalClubCode: codeClub, federalClubName: clubLabel()) + } else { + return nil + } + } + var shareMessage: String { [libelle, dateDebut?.formatted(date: .complete, time: .omitted)].compactMap({$0}).joined(separator: "\n") + "\n" } + var japMessage: String { + [nomClub, jugeArbitre?.nom, jugeArbitre?.prenom, courrielEngagement, installation?.telephone].compactMap({$0}).joined(separator: ";") + } + + func umpireLabel() -> String { + [jugeArbitre?.nom, jugeArbitre?.prenom].compactMap({$0}).joined(separator: " ") + } + + func phoneLabel() -> String { + [installation?.telephone].compactMap({$0}).joined(separator: " ") + } + + func mailLabel() -> String { + [courrielEngagement].compactMap({$0}).joined(separator: " ") + } + func validForSearch(_ searchText: String, scope: FederalTournamentSearchScope) -> Bool { var trimmedSearchText = searchText.lowercased().trimmingCharacters(in: .whitespaces).folding(options: .diacriticInsensitive, locale: .current) trimmedSearchText = trimmedSearchText.replaceCharactersFromSet(characterSet: .punctuationCharacters, replacementString: " ") @@ -156,7 +193,6 @@ extension FederalTournament: FederalTournamentHolder { // var importedId: Int { id } var holderId: String { id.string } - func clubLabel() -> String { nomClub ?? villeEngagement ?? installation?.nom ?? "" } diff --git a/PadelClub/Data/Federal/FederalTournamentHolder.swift b/PadelClub/Data/Federal/FederalTournamentHolder.swift index 4350d27..b2e3890 100644 --- a/PadelClub/Data/Federal/FederalTournamentHolder.swift +++ b/PadelClub/Data/Federal/FederalTournamentHolder.swift @@ -11,10 +11,12 @@ protocol FederalTournamentHolder { var holderId: String { get } var startDate: Date { get } var endDate: Date? { get } + var codeClub: String? { get } var tournaments: [any TournamentBuildHolder] { get } func clubLabel() -> String func subtitleLabel() -> String var dayDuration: Int { get } + var dayPeriod: DayPeriod { get } } extension FederalTournamentHolder { diff --git a/PadelClub/Data/GroupStage.swift b/PadelClub/Data/GroupStage.swift index ac2d9c7..32e07b2 100644 --- a/PadelClub/Data/GroupStage.swift +++ b/PadelClub/Data/GroupStage.swift @@ -383,6 +383,11 @@ final class GroupStage: ModelObject, Storable { return data.joined(separator: "\n") } + + func finalPosition(ofTeam team: TeamRegistration) -> Int? { + guard hasEnded() else { return nil } + return teams(true).firstIndex(of: team) + } override func deleteDependencies() throws { let matches = self._matches() diff --git a/PadelClub/Data/Match.swift b/PadelClub/Data/Match.swift index 148abb1..1e8c918 100644 --- a/PadelClub/Data/Match.swift +++ b/PadelClub/Data/Match.swift @@ -121,6 +121,10 @@ defer { print("func matchTitle", id, duration.formatted(.units(allowed: [.seconds, .milliseconds]))) } #endif + + if roundObject?.groupStageLoserBracket == true { + return "\(index)\(index.ordinalFormattedSuffix()) place" + } if let groupStageObject { return groupStageObject.localizedMatchUpLabel(for: index) } @@ -361,9 +365,17 @@ defer { return false } - func _toggleMatchDisableState(_ state: Bool, forward: Bool = false) { + func _toggleMatchDisableState(_ state: Bool, forward: Bool = false, single: Bool = false) { //if disabled == state { return } disabled = state + + if disabled { + do { + try self.tournamentStore.teamScores.delete(contentOfs: teamScores) + } catch { + Logger.error(error) + } + } if state == true { let teams = teams() for team in teams { @@ -384,12 +396,14 @@ defer { Logger.error(error) } - _toggleLoserMatchDisableState(state) - if forward { - _toggleForwardMatchDisableState(state) - } else { - topPreviousRoundMatch()?._toggleMatchDisableState(state) - bottomPreviousRoundMatch()?._toggleMatchDisableState(state) + if single == false { + _toggleLoserMatchDisableState(state) + if forward { + _toggleForwardMatchDisableState(state) + } else { + topPreviousRoundMatch()?._toggleMatchDisableState(state) + bottomPreviousRoundMatch()?._toggleMatchDisableState(state) + } } } @@ -837,7 +851,22 @@ defer { } var isLoserBracket: Bool { - return roundObject?.parent != nil + if let roundObject { + if roundObject.parent != nil || roundObject.groupStageLoserBracket { + return true + } + } + return false + } + + var matchType: MatchType { + if isLoserBracket { + return .loserBracket + } else if isGroupStage() { + return .groupStage + } else { + return .bracket + } } enum CodingKeys: String, CodingKey { diff --git a/PadelClub/Data/Round.swift b/PadelClub/Data/Round.swift index 27eee27..0cc15be 100644 --- a/PadelClub/Data/Round.swift +++ b/PadelClub/Data/Round.swift @@ -22,13 +22,15 @@ final class Round: ModelObject, Storable { var parent: String? private(set) var format: MatchFormat? var startDate: Date? + var groupStageLoserBracket: Bool = false - internal init(tournament: String, index: Int, parent: String? = nil, matchFormat: MatchFormat? = nil, startDate: Date? = nil) { + internal init(tournament: String, index: Int, parent: String? = nil, matchFormat: MatchFormat? = nil, startDate: Date? = nil, groupStageLoserBracket: Bool = false) { self.tournament = tournament self.index = index self.parent = parent self.format = matchFormat self.startDate = startDate + self.groupStageLoserBracket = groupStageLoserBracket } // MARK: - Computed dependencies @@ -67,7 +69,7 @@ final class Round: ModelObject, Storable { } func hasEnded() -> Bool { - if parent == nil { + if isUpperBracket() { return playedMatches().anySatisfy({ $0.hasEnded() == false }) == false } else { return enabledMatches().anySatisfy({ $0.hasEnded() == false }) == false @@ -184,13 +186,13 @@ defer { case .two: if let luckyLoser = match.teamScores.first(where: { $0.luckyLoser == match.index * 2 + 1 }) { return luckyLoser.team - } else if let previousMatch = bottomPreviousRoundMatch(ofMatch: match, previousRound: previousRound) { + } else if groupStageLoserBracket == false, let previousMatch = bottomPreviousRoundMatch(ofMatch: match, previousRound: previousRound) { if let teamId = previousMatch.winningTeamId { return self.tournamentStore.teamRegistrations.findById(teamId) } else if previousMatch.disabled { return previousMatch.teams().first } - } else if let parent = upperBracketBottomMatch(ofMatchIndex: match.index, previousRound: previousRound)?.losingTeamId { + } else if groupStageLoserBracket == false, let parent = upperBracketBottomMatch(ofMatchIndex: match.index, previousRound: previousRound)?.losingTeamId { return tournamentStore.findById(parent) } } @@ -292,7 +294,7 @@ defer { // } func playedMatches() -> [Match] { - if parent == nil { + if isUpperBracket() { return enabledMatches() } else { return _matches() @@ -477,15 +479,19 @@ defer { } #endif - if parent == nil { + if isUpperBracket() { if index == 0 { return SeedInterval(first: 1, last: 2) } let initialMatchIndexFromRoundIndex = RoundRule.matchIndex(fromRoundIndex: index) let seedsAfterThisRound : [TeamRegistration] = self.tournamentStore.teamRegistrations.filter { $0.bracketPosition != nil && ($0.bracketPosition! / 2) < initialMatchIndexFromRoundIndex } - let playedMatches = playedMatches() - let seedInterval = SeedInterval(first: playedMatches.count + seedsAfterThisRound.count + 1, last: playedMatches.count * 2 + seedsAfterThisRound.count) + + let playedMatches = playedMatches().count + let minimumMatches = initialMode ? RoundRule.numberOfMatches(forRoundIndex: index) : playedMatches * 2 + //print("playedMatches \(playedMatches)", initialMode, parent, parentRound?.roundTitle(), seedsAfterThisRound.count) + let seedInterval = SeedInterval(first: playedMatches + seedsAfterThisRound.count + 1, last: minimumMatches + seedsAfterThisRound.count) + //print(seedInterval.localizedLabel()) return seedInterval } @@ -496,7 +502,7 @@ defer { return previousRound.seedInterval(initialMode: initialMode) } } else if let parentRound { - if parentRound.parent == nil { + if parentRound.isUpperBracket() { return parentRound.seedInterval(initialMode: initialMode) } return parentRound.seedInterval(initialMode: initialMode)?.chunks()?.last @@ -506,6 +512,10 @@ defer { } func roundTitle(_ displayStyle: DisplayStyle = .wide, initialMode: Bool = false) -> String { + if groupStageLoserBracket { + return "Classement Poules" + } + if parent != nil { if let seedInterval = seedInterval(initialMode: initialMode) { return seedInterval.localizedLabel(displayStyle) @@ -557,11 +567,11 @@ defer { } func isUpperBracket() -> Bool { - return parent == nil + return parent == nil && groupStageLoserBracket == false } func isLoserBracket() -> Bool { - return parent != nil + return parent != nil || groupStageLoserBracket } func deleteLoserBracket() { @@ -670,6 +680,18 @@ defer { case _parent = "parent" case _format = "format" case _startDate = "startDate" + case _groupStageLoserBracket = "groupStageLoserBracket" + } + + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + id = try container.decode(String.self, forKey: ._id) + tournament = try container.decode(String.self, forKey: ._tournament) + index = try container.decode(Int.self, forKey: ._index) + parent = try container.decodeIfPresent(String.self, forKey: ._parent) + format = try container.decodeIfPresent(MatchFormat.self, forKey: ._format) + startDate = try container.decodeIfPresent(Date.self, forKey: ._startDate) + groupStageLoserBracket = try container.decodeIfPresent(Bool.self, forKey: ._groupStageLoserBracket) ?? false } func encode(to encoder: Encoder) throws { @@ -678,7 +700,8 @@ defer { try container.encode(id, forKey: ._id) try container.encode(tournament, forKey: ._tournament) try container.encode(index, forKey: ._index) - + try container.encode(groupStageLoserBracket, forKey: ._groupStageLoserBracket) + if let parent = parent { try container.encode(parent, forKey: ._parent) } else { diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index 58c1b62..1c90fef 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -503,6 +503,10 @@ final class TeamRegistration: ModelObject, Storable { else { confirmationDate = nil } } + func didConfirmSummon() -> Bool { + confirmationDate != nil + } + func tournamentObject() -> Tournament? { return Store.main.findById(tournament) } diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 7ad53ff..35c94eb 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -348,19 +348,19 @@ final class Tournament : ModelObject, Storable { override func deleteDependencies() throws { let store = self.tournamentStore - let teams = self.unsortedTeams() + let teams = self.tournamentStore.teamRegistrations for team in teams { try team.deleteDependencies() } store.teamRegistrations.deleteDependencies(teams) - let groups = self.groupStages() + let groups = self.tournamentStore.groupStages for group in groups { try group.deleteDependencies() } store.groupStages.deleteDependencies(groups) - let rounds = self.rounds() + let rounds = self.self.tournamentStore.rounds for round in rounds { try round.deleteDependencies() } @@ -809,7 +809,7 @@ defer { } func rounds() -> [Round] { - let rounds: [Round] = self.tournamentStore.rounds.filter { $0.parent == nil } + let rounds: [Round] = self.tournamentStore.rounds.filter { $0.isUpperBracket() } return rounds.sorted(by: \.index).reversed() } @@ -1151,7 +1151,7 @@ defer { return allMatches.filter({ $0.isReady() && $0.isRunning() == false && $0.hasEnded() == false }).sorted(by: \.computedStartDateForSorting) } - func finishedMatches(_ allMatches: [Match], limit: Int? = nil) -> [Match] { + func finishedMatches(_ allMatches: [Match], limit: Int?) -> [Match] { #if _DEBUG_TIME //DEBUGING TIME let start = Date() defer { @@ -1159,8 +1159,11 @@ defer { print("func tournament finishedMatches", id, duration.formatted(.units(allowed: [.seconds, .milliseconds]))) } #endif - let _limit = limit ?? courtCount - return Array(allMatches.filter({ $0.hasEnded() }).sorted(by: \.computedEndDateForSorting).reversed().prefix(_limit)) + if let limit { + return Array(allMatches.filter({ $0.hasEnded() }).sorted(by: \.computedEndDateForSorting).reversed().prefix(limit)) + } else { + return Array(allMatches.filter({ $0.hasEnded() }).sorted(by: \.computedEndDateForSorting).reversed()) + } } func teamsRanked() -> [TeamRegistration] { @@ -1224,7 +1227,7 @@ defer { _removeStrings(from: &teams, stringsToRemove: disabledIds) teams[interval.last] = disabledIds let teamNames : [String] = disabledIds.compactMap { - let t : TeamRegistration? = Store.main.findById($0) + let t : TeamRegistration? = tournamentStore.teamRegistrations.findById($0) return t }.map { $0.canonicalName } print("winners.isEmpty", "\(interval.last) : ", teamNames) @@ -1237,7 +1240,7 @@ defer { _removeStrings(from: &teams, stringsToRemove: winners) teams[interval.first + winners.count - 1] = winners let teamNames : [String] = winners.compactMap { - let t: TeamRegistration? = Store.main.findById($0) + let t: TeamRegistration? = tournamentStore.teamRegistrations.findById($0) return t }.map { $0.canonicalName } print("winners", "\(interval.last + winners.count - 1) : ", teamNames) @@ -1246,25 +1249,35 @@ defer { if losers.isEmpty == false { _removeStrings(from: &teams, stringsToRemove: losers) - teams[interval.last] = losers + teams[interval.first + winners.count] = losers let loserTeamNames : [String] = losers.compactMap { - let t: TeamRegistration? = Store.main.findById($0) + let t: TeamRegistration? = tournamentStore.teamRegistrations.findById($0) return t }.map { $0.canonicalName } - print("losers", "\(interval.last) : ", loserTeamNames) + print("losers", "\(interval.first + winners.count) : ", loserTeamNames) losers.forEach { ids.insert($0) } } } } } + if let groupStageLoserBracketPlayedMatches = groupStageLoserBracket()?.playedMatches() { + groupStageLoserBracketPlayedMatches.forEach({ match in + if match.hasEnded() { + let sameMatchIndexCount = groupStageLoserBracketPlayedMatches.filter({ $0.index == match.index }).count + teams.setOrAppend(match.winningTeamId, at: match.index) + teams.setOrAppend(match.losingTeamId, at: match.index + sameMatchIndexCount) + } + }) + } + let groupStages = groupStages() let baseRank = teamCount - groupStageSpots() + qualifiedPerGroupStage * groupStageCount + groupStageAdditionalQualified - + let alreadyPlaceTeams = Array(teams.values.flatMap({ $0 })) groupStages.forEach { groupStage in let groupStageTeams = groupStage.teams(true) for (index, team) in groupStageTeams.enumerated() { - if team.qualified == false { + if team.qualified == false && alreadyPlaceTeams.contains(team.id) == false { let groupStageWidth = max(((index == qualifiedPerGroupStage) ? groupStageCount - groupStageAdditionalQualified : groupStageCount) * (index - qualifiedPerGroupStage), 0) let _index = baseRank + groupStageWidth + 1 @@ -1934,10 +1947,7 @@ defer { } func tournamentWinner() -> TeamRegistration? { - let finals: Round? = self.tournamentStore.rounds.first(where: { $0.index == 0 && $0.parent == nil }) - -// let rounds: [Round] = Store.main.filter(isIncluded: { $0.index == 0 && $0.tournament == id && $0.parent == nil }) -// let final: Round? = .first + let finals: Round? = self.tournamentStore.rounds.first(where: { $0.index == 0 && $0.isUpperBracket() }) return finals?.playedMatches().first?.winner() } @@ -1998,19 +2008,27 @@ defer { return (Array(shouldBeInIt), Array(shouldNotBeInIt)) } + func groupStageLoserBracket() -> Round? { + tournamentStore.rounds.first(where: { $0.groupStageLoserBracket }) + } + + func groupStageLoserBracketsInitialPlace() -> Int { + return teamCount - teamsPerGroupStage * groupStageCount + qualifiedPerGroupStage * groupStageCount + groupStageAdditionalQualified + 1 + } + // MARK: - func insertOnServer() throws { DataStore.shared.tournaments.writeChangeAndInsertOnServer(instance: self) - for teamRegistration in self.unsortedTeams() { + for teamRegistration in self.tournamentStore.teamRegistrations { teamRegistration.insertOnServer() } - for groupStage in self.groupStages() { + for groupStage in self.tournamentStore.groupStages { groupStage.insertOnServer() } - for round in self.allRounds() { + for round in self.tournamentStore.rounds { round.insertOnServer() } @@ -2100,6 +2118,10 @@ extension Tournament: Hashable { } extension Tournament: FederalTournamentHolder { + var codeClub: String? { + club()?.code + } + var holderId: String { id } func clubLabel() -> String { @@ -2115,6 +2137,16 @@ extension Tournament: FederalTournamentHolder { self ] } + + var dayPeriod: DayPeriod { + let day = startDate.get(.weekday) + switch day { + case 2...6: + return .week + default: + return .weekend + } + } } extension Tournament: TournamentBuildHolder { diff --git a/PadelClub/Data/User.swift b/PadelClub/Data/User.swift index 6ce9d08..d40e126 100644 --- a/PadelClub/Data/User.swift +++ b/PadelClub/Data/User.swift @@ -75,6 +75,13 @@ class User: ModelObject, UserBase, Storable { return "Sportivement,\n\(firstName) \(lastName), votre JAP." } + func fullName() -> String? { + guard firstName.isEmpty == false && lastName.isEmpty == false else { + return nil + } + return "\(firstName) \(lastName)" + } + func hasTenupClubs() -> Bool { self.clubsObjects().filter({ $0.code != nil }).isEmpty == false } diff --git a/PadelClub/Extensions/Array+Extensions.swift b/PadelClub/Extensions/Array+Extensions.swift index 62b8d4b..baadf6c 100644 --- a/PadelClub/Extensions/Array+Extensions.swift +++ b/PadelClub/Extensions/Array+Extensions.swift @@ -18,6 +18,16 @@ extension Array { return first(where: { p($0) }) != nil //return !self.allSatisfy { !p($0) } } + + // Check if the number of elements in the sequence is even + var isEven: Bool { + return self.count % 2 == 0 + } + + // Check if the number of elements in the sequence is odd + var isOdd: Bool { + return self.count % 2 != 0 + } } extension Array where Element: Equatable { @@ -49,3 +59,38 @@ extension Array where Element: CustomStringConvertible { } } + +extension Dictionary where Key == Int, Value == [String] { + mutating func setOrAppend(_ element: String?, at key: Int) { + // Check if the element is nil; do nothing if it is + guard let element = element else { + return + } + + // Check if the key exists in the dictionary + if var array = self[key] { + // If it exists, append the element to the array + array.append(element) + self[key] = array + } else { + // If it doesn't exist, create a new array with the element + self[key] = [element] + } + } +} + + +extension Array where Element == String { + func formatList(maxDisplay: Int = 2) -> [String] { + // Check if the array has fewer or equal elements than the maximum display limit + if self.count <= maxDisplay { + // Join all elements with commas + return self + } else { + // Join only the first `maxDisplay` elements and add "et plus" + let displayedItems = self.prefix(maxDisplay) + let remainingCount = self.count - maxDisplay + return displayedItems.dropLast() + [displayedItems.last! + " et \(remainingCount) de plus"] + } + } +} diff --git a/PadelClub/Extensions/Calendar+Extensions.swift b/PadelClub/Extensions/Calendar+Extensions.swift index 3e04ff3..47971b5 100644 --- a/PadelClub/Extensions/Calendar+Extensions.swift +++ b/PadelClub/Extensions/Calendar+Extensions.swift @@ -49,3 +49,23 @@ extension Calendar { return sportYear } } + +extension Calendar { + // Add or subtract months from a date + func addMonths(_ months: Int, to date: Date) -> Date { + return self.date(byAdding: .month, value: months, to: date)! + } + + // Generate a list of month start dates between two dates + func generateMonthRange(startDate: Date, endDate: Date) -> [Date] { + var dates: [Date] = [] + var currentDate = startDate + + while currentDate <= endDate { + dates.append(currentDate) + currentDate = self.addMonths(1, to: currentDate) + } + + return dates + } +} diff --git a/PadelClub/Extensions/String+Extensions.swift b/PadelClub/Extensions/String+Extensions.swift index 92cc91a..b333e27 100644 --- a/PadelClub/Extensions/String+Extensions.swift +++ b/PadelClub/Extensions/String+Extensions.swift @@ -17,6 +17,10 @@ extension String { replaceCharactersFromSet(characterSet: .newlines).trimmingCharacters(in: .whitespacesAndNewlines) } + var trimmedMultiline: String { + self.trimmingCharacters(in: .whitespacesAndNewlines) + } + func replaceCharactersFromSet(characterSet: CharacterSet, replacementString: String = "") -> String { components(separatedBy: characterSet).joined(separator:replacementString) } diff --git a/PadelClub/Utils/ContactManager.swift b/PadelClub/Utils/ContactManager.swift index dd74dd5..07b23a2 100644 --- a/PadelClub/Utils/ContactManager.swift +++ b/PadelClub/Utils/ContactManager.swift @@ -30,7 +30,10 @@ enum ContactType: Identifiable { } extension ContactType { - static let defaultCustomMessage: String = "Il est conseillé de vous présenter 10 minutes avant de jouer.\nMerci de me confirmer votre présence avec votre nom et de prévenir votre partenaire." + static let defaultCustomMessage: String = +""" +Il est conseillé de vous présenter 10 minutes avant de jouer.\n\nMerci de me confirmer votre présence avec votre nom et de prévenir votre partenaire. +""" static let defaultAvailablePaymentMethods: String = "Règlement possible par chèque ou espèces." static func callingCustomMessage(source: String? = nil, tournament: Tournament?, startDate: Date?, roundLabel: String) -> String { @@ -77,7 +80,7 @@ extension ContactType { } var computedMessage: String { - [entryFeeMessage, message].compacted().map { $0.trimmed }.joined(separator: "\n\n") + [entryFeeMessage, message].compacted().map { $0.trimmedMultiline }.joined(separator: "\n\n") } let intro = reSummon ? "Suite à des forfaits, vous êtes finalement" : "Vous êtes" diff --git a/PadelClub/Utils/Network/NetworkFederalService.swift b/PadelClub/Utils/Network/NetworkFederalService.swift index 666b049..7933f55 100644 --- a/PadelClub/Utils/Network/NetworkFederalService.swift +++ b/PadelClub/Utils/Network/NetworkFederalService.swift @@ -194,4 +194,64 @@ recherche_type=club&club[autocomplete][value_container][value_field]=\(codeClub. print("no data found in html") } } + + func getAllFederalTournaments(sortingOption: String, page: Int, startDate: Date, endDate: Date, city: String, distance: Double, categories: [TournamentCategory], levels: [TournamentLevel], lat: String?, lng: String?, ages: [FederalTournamentAge], types: [FederalTournamentType], nationalCup: Bool) async throws -> [HttpCommand] { + + var cityParameter = "" + var searchType = "ligue" + if city.trimmed.isEmpty == false { + searchType = "ville" + cityParameter = city + } + + var levelsParameter = "" + if levels.isEmpty == false { + levelsParameter = levels.map { "categorie_tournoi[\($0.localizedLabel)]=\($0.localizedLabel)" }.joined(separator: "&") + "&" + } + + var categoriesParameter = "" + if categories.isEmpty == false { + categoriesParameter = categories.map { "epreuve[\($0.requestLabel)]=\($0.requestLabel)" }.joined(separator: "&") + "&" + } + + var agesParameter = "" + if ages.isEmpty == false { + agesParameter = ages.map { "categorie_age[\($0.rawValue)]=\($0.rawValue)" }.joined(separator: "&") + "&" + } + + var typesParameter = "" + if types.isEmpty == false { + typesParameter = types.map { "type[\($0.rawValue.capitalized)]=\($0.rawValue.capitalized)" }.joined(separator: "&") + "&" + } + + var npc = "" + if nationalCup { + npc = "&tournoi_npc=1" + } + + let parameters = """ +recherche_type=\(searchType)&ville%5Bautocomplete%5D%5Bcountry%5D=fr&ville%5Bautocomplete%5D%5Btextfield%5D=&ville%5Bautocomplete%5D%5Bvalue_container%5D%5Bvalue_field%5D=\(cityParameter)&ville%5Bautocomplete%5D%5Bvalue_container%5D%5Blabel_field%5D=\(cityParameter)&ville%5Bautocomplete%5D%5Bvalue_container%5D%5Blat_field%5D=\(lat ?? "")&ville%5Bautocomplete%5D%5Bvalue_container%5D%5Blng_field%5D=\(lng ?? "")&ville%5Bdistance%5D%5Bvalue_field%5D=\(Int(distance))&club%5Bautocomplete%5D%5Btextfield%5D=&club%5Bautocomplete%5D%5Bvalue_container%5D%5Bvalue_field%5D=&club%5Bautocomplete%5D%5Bvalue_container%5D%5Blabel_field%5D=&pratique=PADEL&date%5Bstart%5D=\(startDate.twoDigitsYearFormatted)&date%5Bend%5D=\(endDate.twoDigitsYearFormatted)&\(categoriesParameter)\(levelsParameter)\(agesParameter)\(typesParameter)\(npc)&page=\(page)&sort=\(sortingOption)&form_build_id=\(formId)&form_id=recherche_tournois_form&_triggering_element_name=submit_page&_triggering_element_value=Submit+page +""" + let postData = parameters.data(using: .utf8) + + var request = URLRequest(url: URL(string: "https://tenup.fft.fr/system/ajax")!,timeoutInterval: Double.infinity) + request.addValue("application/json, text/javascript, */*; q=0.01", forHTTPHeaderField: "Accept") + request.addValue("fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3", forHTTPHeaderField: "Accept-Language") + request.addValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding") + request.addValue("application/x-www-form-urlencoded; charset=UTF-8", forHTTPHeaderField: "Content-Type") + request.addValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With") + request.addValue("https://tenup.fft.fr", forHTTPHeaderField: "Origin") + request.addValue("keep-alive", forHTTPHeaderField: "Connection") + request.addValue("https://tenup.fft.fr/recherche/tournois", forHTTPHeaderField: "Referer") + request.addValue("empty", forHTTPHeaderField: "Sec-Fetch-Dest") + request.addValue("cors", forHTTPHeaderField: "Sec-Fetch-Mode") + request.addValue("same-origin", forHTTPHeaderField: "Sec-Fetch-Site") + + request.httpMethod = "POST" + request.httpBody = postData + + + return try await runTenupTask(request: request) + } + } diff --git a/PadelClub/Utils/PadelRule.swift b/PadelClub/Utils/PadelRule.swift index 8c65472..a30fd68 100644 --- a/PadelClub/Utils/PadelRule.swift +++ b/PadelClub/Utils/PadelRule.swift @@ -6,6 +6,7 @@ // import Foundation +import LeStorage enum RankSource: Hashable { case national @@ -33,7 +34,8 @@ protocol TournamentBuildHolder: Identifiable { } struct TournamentBuild: TournamentBuildHolder, Hashable, Codable, Identifiable { - var id: String { identifier } + var uniqueId: String = Store.randomId() + var id: String { uniqueId } let category: TournamentCategory let level: TournamentLevel let age: FederalTournamentAge @@ -42,7 +44,7 @@ struct TournamentBuild: TournamentBuildHolder, Hashable, Codable, Identifiable { // var japLastName: String? = nil func buildHolderTitle() -> String { - localizedLabel() + computedLabel } var identifier: String { @@ -291,6 +293,13 @@ enum TournamentLevel: Int, Hashable, Codable, CaseIterable, Identifiable { self.init(rawValue: value) } + + func pointsRange(first: Int, last: Int, teamsCount: Int) -> String { + let range = [points(for: first - 1, count: teamsCount), + points(for: last - 1, count: teamsCount)] + return range.map { $0.formatted(.number.sign(strategy: .always())) }.joined(separator: " / ") + " pts" + } + func hideWeight() -> Bool { switch self { case .unlisted: diff --git a/PadelClub/ViewModel/AgendaDestination.swift b/PadelClub/ViewModel/AgendaDestination.swift index 3708e3d..abe2126 100644 --- a/PadelClub/ViewModel/AgendaDestination.swift +++ b/PadelClub/ViewModel/AgendaDestination.swift @@ -18,12 +18,8 @@ enum AgendaDestination: Int, CaseIterable, Identifiable, Selectable, Equatable { case activity case history case tenup + case around - enum ViewStyle { - case list - case calendar - } - var localizedTitleKey: String { switch self { case .activity: @@ -32,6 +28,8 @@ enum AgendaDestination: Int, CaseIterable, Identifiable, Selectable, Equatable { return "Terminé" case .tenup: return "Tenup" + case .around: + return "Autour" } } @@ -39,14 +37,12 @@ enum AgendaDestination: Int, CaseIterable, Identifiable, Selectable, Equatable { localizedTitleKey } - var systemImage: String { + func systemImage() -> String? { switch self { - case .activity: - return "squares.leading.rectangle" - case .history: - return "book.closed" - case .tenup: - return "tennisball" + case .around: + return "location.magnifyingglass" + default: + return nil } } @@ -58,6 +54,9 @@ enum AgendaDestination: Int, CaseIterable, Identifiable, Selectable, Equatable { DataStore.shared.tournaments.filter { $0.endDate != nil && FederalDataViewModel.shared.isTournamentValidForFilters($0) }.count case .tenup: FederalDataViewModel.shared.filteredFederalTournaments.map { $0.tournaments.count }.reduce(0,+) + case .around: + nil + } } @@ -84,6 +83,25 @@ enum AgendaDestination: Int, CaseIterable, Identifiable, Selectable, Equatable { } else { return nil } + case .around: + return nil } } } + + +enum ViewStyle { + case list + case calendar +} + +struct ViewStyleKey: EnvironmentKey { + static let defaultValue: ViewStyle = .list +} + +extension EnvironmentValues { + var viewStyle: ViewStyle { + get { self[ViewStyleKey.self] } + set { self[ViewStyleKey.self] = newValue } + } +} diff --git a/PadelClub/ViewModel/FederalDataViewModel.swift b/PadelClub/ViewModel/FederalDataViewModel.swift index 387dc0a..010b211 100644 --- a/PadelClub/ViewModel/FederalDataViewModel.swift +++ b/PadelClub/ViewModel/FederalDataViewModel.swift @@ -13,26 +13,44 @@ class FederalDataViewModel { static let shared = FederalDataViewModel() var federalTournaments: [FederalTournament] = [] + var searchedFederalTournaments: [FederalTournament] = [] var levels: Set = Set() var categories: Set = Set() var ageCategories: Set = Set() var selectedClubs: Set = Set() var id: UUID = UUID() - + var searchAttemptCount: Int = 0 + var dayDuration: Int? + var dayPeriod: DayPeriod = .all + func filterStatus() -> String { var labels: [String] = [] - labels.append(contentsOf: levels.map { $0.localizedLabel() }) - labels.append(contentsOf: categories.map { $0.localizedLabel() }) - labels.append(contentsOf: ageCategories.map { $0.localizedLabel() }) + labels.append(contentsOf: levels.map { $0.localizedLabel() }.formatList()) + labels.append(contentsOf: categories.map { $0.localizedLabel() }.formatList()) + labels.append(contentsOf: ageCategories.map { $0.localizedLabel() }.formatList()) let clubNames = selectedClubs.compactMap { codeClub in let club: Club? = DataStore.shared.clubs.first(where: { $0.code == codeClub }) return club?.clubTitle(.short) } - labels.append(contentsOf: clubNames) + labels.append(contentsOf: clubNames.formatList()) + if dayPeriod != .all { + labels.append(dayPeriod.localizedDayPeriodLabel()) + } + if let dayDuration { + labels.append("max " + dayDuration.formatted() + " jour" + dayDuration.pluralSuffix) + } return labels.joined(separator: ", ") } + var searchedClubs: [FederalClub] { + searchedFederalTournaments.compactMap { ft in + ft.federalClub + }.uniqued { fc in + fc.federalClubCode + }.sorted(by: \.federalClubName) + } + func selectedClub() -> Club? { if selectedClubs.isEmpty == false { return DataStore.shared.clubs.first(where: { $0.code == selectedClubs.first! }) @@ -46,15 +64,25 @@ class FederalDataViewModel { categories.removeAll() ageCategories.removeAll() selectedClubs.removeAll() + dayPeriod = .all + dayDuration = nil id = UUID() } func areFiltersEnabled() -> Bool { - (levels.isEmpty && categories.isEmpty && ageCategories.isEmpty && selectedClubs.isEmpty) == false + (levels.isEmpty && categories.isEmpty && ageCategories.isEmpty && selectedClubs.isEmpty && dayPeriod == .all && dayDuration == nil) == false + } + + var filteredFederalTournaments: [FederalTournamentHolder] { + filteredFederalTournaments(from: federalTournaments) + } + + var filteredSearchedFederalTournaments: [FederalTournamentHolder] { + filteredFederalTournaments(from: searchedFederalTournaments) } - var filteredFederalTournaments: [FederalTournament] { - federalTournaments.filter({ tournament in + func filteredFederalTournaments(from tournaments: [any FederalTournamentHolder]) -> [FederalTournamentHolder] { + tournaments.filter({ tournament in (levels.isEmpty || tournament.tournaments.anySatisfy({ levels.contains($0.level) })) && (categories.isEmpty || tournament.tournaments.anySatisfy({ categories.contains($0.category) })) @@ -62,6 +90,10 @@ class FederalDataViewModel { (ageCategories.isEmpty || tournament.tournaments.anySatisfy({ ageCategories.contains($0.age) })) && (selectedClubs.isEmpty || selectedClubs.contains(tournament.codeClub!)) + && + (dayPeriod == .all || (dayPeriod != .all && dayPeriod == tournament.dayPeriod)) + && + (dayDuration == nil || (dayDuration != nil && dayDuration == tournament.dayDuration)) }) } @@ -72,7 +104,11 @@ class FederalDataViewModel { (categories.isEmpty || categories.contains(tournament.category)) && (ageCategories.isEmpty || ageCategories.contains(tournament.age)) - + && + (dayPeriod == .all || (dayPeriod != .all && dayPeriod == tournament.dayPeriod)) + && + (dayDuration == nil || (dayDuration != nil && dayDuration == tournament.dayDuration)) + if let codeClub = tournament.club()?.code { return firstPart && (selectedClubs.isEmpty || selectedClubs.contains(codeClub)) } else { @@ -88,6 +124,10 @@ class FederalDataViewModel { (ageCategories.isEmpty || ageCategories.contains(build.age)) && (selectedClubs.isEmpty || selectedClubs.contains(tournament.codeClub!)) + && + (dayPeriod == .all || (dayPeriod != .all && dayPeriod == tournament.dayPeriod)) + && + (dayDuration == nil || (dayDuration != nil && dayDuration == tournament.dayDuration)) } func gatherTournaments(clubs: [Club], startDate: Date, endDate: Date? = nil) async throws { @@ -103,3 +143,8 @@ class FederalDataViewModel { } } +struct FederalClub: Identifiable { + var id: String { federalClubCode } + var federalClubCode: String + var federalClubName: String +} diff --git a/PadelClub/ViewModel/SeedInterval.swift b/PadelClub/ViewModel/SeedInterval.swift index 01e7519..32ab726 100644 --- a/PadelClub/ViewModel/SeedInterval.swift +++ b/PadelClub/ViewModel/SeedInterval.swift @@ -12,9 +12,7 @@ struct SeedInterval: Hashable, Comparable { let last: Int func pointsRange(tournamentLevel: TournamentLevel, teamsCount: Int) -> String { - let range = [tournamentLevel.points(for: last - 1, count: teamsCount), - tournamentLevel.points(for: first - 1, count: teamsCount)] - return range.map { $0.formatted(.number.sign(strategy: .always())) }.joined(separator: " / ") + " pts" + tournamentLevel.pointsRange(first: first, last: last, teamsCount: teamsCount) } static func <(lhs: SeedInterval, rhs: SeedInterval) -> Bool { diff --git a/PadelClub/ViewModel/Selectable.swift b/PadelClub/ViewModel/Selectable.swift index e29e072..6734828 100644 --- a/PadelClub/ViewModel/Selectable.swift +++ b/PadelClub/ViewModel/Selectable.swift @@ -14,9 +14,14 @@ protocol Selectable { func badgeImage() -> Badge? func badgeValueColor() -> Color? func displayImageIfValueZero() -> Bool + func systemImage() -> String? } extension Selectable { + func systemImage() -> String? { + return nil + } + func displayImageIfValueZero() -> Bool { return false } diff --git a/PadelClub/Views/Calling/CallMessageCustomizationView.swift b/PadelClub/Views/Calling/CallMessageCustomizationView.swift index e2f8999..93a1779 100644 --- a/PadelClub/Views/Calling/CallMessageCustomizationView.swift +++ b/PadelClub/Views/Calling/CallMessageCustomizationView.swift @@ -43,7 +43,7 @@ struct CallMessageCustomizationView: View { } var computedMessage: String { - [entryFeeMessage, customCallMessageBody].compacted().map { $0.trimmed }.joined(separator: "\n") + [entryFeeMessage, customCallMessageBody].compacted().map { $0.trimmedMultiline }.joined(separator: "\n") } var finalMessage: String? { diff --git a/PadelClub/Views/Cashier/Event/EventCreationView.swift b/PadelClub/Views/Cashier/Event/EventCreationView.swift index 913862f..5ba6f87 100644 --- a/PadelClub/Views/Cashier/Event/EventCreationView.swift +++ b/PadelClub/Views/Cashier/Event/EventCreationView.swift @@ -64,7 +64,7 @@ struct EventCreationView: View { } } - TextField("Nom de l'événement", text: $eventName, axis: .vertical) + TextField("Description de l'événement", text: $eventName, axis: .vertical) .lineLimit(2) .keyboardType(.alphabet) .multilineTextAlignment(.leading) diff --git a/PadelClub/Views/Cashier/Event/EventSettingsView.swift b/PadelClub/Views/Cashier/Event/EventSettingsView.swift index 593cfe8..58b5428 100644 --- a/PadelClub/Views/Cashier/Event/EventSettingsView.swift +++ b/PadelClub/Views/Cashier/Event/EventSettingsView.swift @@ -46,7 +46,7 @@ struct EventSettingsView: View { var body: some View { Form { Section { - TextField("Nom de l'événement", text: $eventName, axis: .vertical) + TextField("Description de l'événement", text: $eventName, axis: .vertical) .lineLimit(2) .keyboardType(.alphabet) .multilineTextAlignment(.leading) diff --git a/PadelClub/Views/Components/GenericDestinationPickerView.swift b/PadelClub/Views/Components/GenericDestinationPickerView.swift index 999a564..a7f4871 100644 --- a/PadelClub/Views/Components/GenericDestinationPickerView.swift +++ b/PadelClub/Views/Components/GenericDestinationPickerView.swift @@ -23,6 +23,7 @@ struct GenericDestinationPickerView: } label: { Image(systemName: "wrench.and.screwdriver") .foregroundColor(selectedDestination == nil ? .white : .black) + .contentShape(Capsule()) } .padding() .background { @@ -38,8 +39,15 @@ struct GenericDestinationPickerView: Button { selectedDestination = destination } label: { - Text(destination.selectionLabel(index: index)) - .foregroundStyle(selectedDestination?.id == destination.id ? .white : .black) + if let systemImage = destination.systemImage() { + Image(systemName: systemImage) + .foregroundStyle(selectedDestination?.id == destination.id ? .white : .black) + .contentShape(Capsule()) + } else { + Text(destination.selectionLabel(index: index)) + .foregroundStyle(selectedDestination?.id == destination.id ? .white : .black) + .contentShape(Capsule()) + } } .padding() .background { diff --git a/PadelClub/Views/GroupStage/GroupStageView.swift b/PadelClub/Views/GroupStage/GroupStageView.swift index c82bdab..5b04f71 100644 --- a/PadelClub/Views/GroupStage/GroupStageView.swift +++ b/PadelClub/Views/GroupStage/GroupStageView.swift @@ -197,12 +197,12 @@ struct GroupStageView: View { } } .listRowView(isActive: team.qualified, color: .master) - .listRowView(isActive: team.isHere(), color: .green, hideColorVariation: true) + .listRowView(isActive: team.isHere() && groupStage.hasEnded() == false, color: .green, hideColorVariation: true) } else { VStack(alignment: .leading, spacing: 0) { Text("#\(index + 1)") .font(.caption) - TeamPickerView(groupStagePosition: index, teamPicked: { team in + TeamPickerView(groupStagePosition: index, matchTypeContext: .groupStage, teamPicked: { team in print(team.pasteData()) team.groupStage = groupStage.id team.groupStagePosition = index diff --git a/PadelClub/Views/GroupStage/GroupStagesSettingsView.swift b/PadelClub/Views/GroupStage/GroupStagesSettingsView.swift index 8b3770c..e0f29dc 100644 --- a/PadelClub/Views/GroupStage/GroupStagesSettingsView.swift +++ b/PadelClub/Views/GroupStage/GroupStagesSettingsView.swift @@ -72,6 +72,30 @@ struct GroupStagesSettingsView: View { Text("Suite à un changement dans votre liste d'inscrits, veuillez vérifier l'intégrité de vos poules et valider que tout est ok.") } } + + Section { + if tournament.groupStageLoserBracket() == nil { + RowButtonView("Ajouter des matchs de classements", role: .destructive) { + let round = Round(tournament: tournament.id, index: 0, matchFormat: tournament.loserRoundFormat, groupStageLoserBracket: true) + + do { + try tournamentStore.rounds.addOrUpdate(instance: round) + } catch { + Logger.error(error) + } + + } + } else if let groupStageLoserBracket = tournament.groupStageLoserBracket() { + RowButtonView("Supprimer les matchs de classements", role: .destructive) { + do { + try groupStageLoserBracket.deleteDependencies() + try tournamentStore.rounds.delete(instance: groupStageLoserBracket) + } catch { + Logger.error(error) + } + } + } + } #if DEBUG Section { @@ -81,12 +105,6 @@ struct GroupStagesSettingsView: View { } #endif -// NavigationLink { -// LoserGroupStageSettingsView(tournament: tournament) -// } label: { -// Text("Match de perdant de poules") -// } - Section { RowButtonView("Retirer tous les horaires", role: .destructive) { let matches = tournament.groupStages().flatMap({ $0._matches() }) @@ -155,6 +173,26 @@ struct GroupStagesSettingsView: View { } } } + + Section { + RowButtonView("Retirer tout le monde", role: .destructive) { + tournament.groupStages().forEach { groupStage in + let teams = groupStage.teams() + teams.forEach { team in + team.groupStagePosition = nil + team.groupStage = nil + groupStage._matches().forEach({ $0.updateTeamScores() }) + } + do { + try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams) + } catch { + Logger.error(error) + } + } + } + } footer: { + Text("Toutes les équipes seront retirées et les scores des matchs seront perdus.") + } } .overlay(alignment: .bottom) { diff --git a/PadelClub/Views/GroupStage/GroupStagesView.swift b/PadelClub/Views/GroupStage/GroupStagesView.swift index 2260f7d..7274171 100644 --- a/PadelClub/Views/GroupStage/GroupStagesView.swift +++ b/PadelClub/Views/GroupStage/GroupStagesView.swift @@ -9,21 +9,25 @@ import SwiftUI import LeStorage struct GroupStagesView: View { - var tournament: Tournament + @State var tournament: Tournament @State private var selectedDestination: GroupStageDestination? - + @EnvironmentObject var dataStore: DataStore + enum GroupStageDestination: Selectable, Identifiable, Equatable { static func == (lhs: GroupStagesView.GroupStageDestination, rhs: GroupStagesView.GroupStageDestination) -> Bool { lhs.id == rhs.id } case all(Tournament) + case loserBracket(Round) case groupStage(GroupStage) var id: String { switch self { case .all: return "all-group-stage" + case .loserBracket(let loserBracket): + return loserBracket.id case .groupStage(let groupStage): return groupStage.id } @@ -33,6 +37,8 @@ struct GroupStagesView: View { switch self { case .all: return "Tout" + case .loserBracket: + return "Classement" case .groupStage(let groupStage): return groupStage.groupStageTitle() } @@ -42,6 +48,8 @@ struct GroupStagesView: View { switch self { case .all: return nil + case .loserBracket(let loserBracket): + return loserBracket.badgeValue() case .groupStage(let groupStage): return groupStage.badgeValue() } @@ -59,6 +67,9 @@ struct GroupStagesView: View { } else { return nil } + case .loserBracket(let loserBracket): + if loserBracket._matches().isEmpty { return nil } + return loserBracket.badgeImage() case .groupStage(let groupStage): return groupStage.badgeImage() } @@ -68,10 +79,9 @@ struct GroupStagesView: View { var allMatches: [Match] { tournament.groupStagesMatches() } - + init(tournament: Tournament) { self.tournament = tournament - if tournament.shouldVerifyGroupStage { _selectedDestination = State(wrappedValue: nil) } else if tournament.unsortedTeams().filter({ $0.groupStagePosition != nil }).isEmpty { @@ -87,6 +97,9 @@ struct GroupStagesView: View { func allDestinations() -> [GroupStageDestination] { var allDestinations : [GroupStageDestination] = [.all(tournament)] let groupStageDestinations : [GroupStageDestination] = tournament.groupStages().map { GroupStageDestination.groupStage($0) } + if let loserBracket = tournament.groupStageLoserBracket() { + allDestinations.insert(.loserBracket(loserBracket), at: 0) + } allDestinations.append(contentsOf: groupStageDestinations) return allDestinations } @@ -96,7 +109,7 @@ struct GroupStagesView: View { GenericDestinationPickerView(selectedDestination: $selectedDestination, destinations: allDestinations(), nilDestinationIsValid: true) switch selectedDestination { case .all: - let finishedMatches = tournament.finishedMatches(allMatches) + let finishedMatches = tournament.finishedMatches(allMatches, limit: nil) List { if tournament.groupStageAdditionalQualified > 0 { @@ -142,6 +155,8 @@ struct GroupStagesView: View { .navigationTitle("Toutes les poules") case .groupStage(let groupStage): GroupStageView(groupStage: groupStage).id(groupStage.id) + case .loserBracket(let loserBracket): + LoserBracketFromGroupStageView(loserBracket: loserBracket).id(loserBracket.id) case nil: GroupStagesSettingsView() .navigationTitle("Réglages") diff --git a/PadelClub/Views/GroupStage/LoserBracketFromGroupStageView.swift b/PadelClub/Views/GroupStage/LoserBracketFromGroupStageView.swift new file mode 100644 index 0000000..08efa0e --- /dev/null +++ b/PadelClub/Views/GroupStage/LoserBracketFromGroupStageView.swift @@ -0,0 +1,206 @@ +// +// LoserBracketFromGroupStageView.swift +// PadelClub +// +// Created by razmig on 07/09/2024. +// + +import SwiftUI +import LeStorage + +struct LoserBracketFromGroupStageView: View { + + @Environment(Tournament.self) var tournament: Tournament + @EnvironmentObject var dataStore: DataStore + @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel + @State var loserBracket: Round + @State private var isEditingLoserBracketGroupStage: Bool + + init(loserBracket: Round) { + self.loserBracket = loserBracket + _isEditingLoserBracketGroupStage = .init(wrappedValue: loserBracket._matches().isEmpty) + } + + var tournamentStore: TournamentStore { + return self.tournament.tournamentStore + } + + var displayableMatches: [Match] { + loserBracket.playedMatches().sorted(by: \.index) + } + + var body: some View { + List { + if isEditingLoserBracketGroupStage == true && displayableMatches.isEmpty == false { + Section { + RowButtonView("Ajouter un match", role: .destructive) { + _addNewMatch() + } + } + } + + ForEach(displayableMatches) { match in + Section { + MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle) + .environment(\.isEditingTournamentSeed, $isEditingLoserBracketGroupStage) + } header: { + let tournamentTeamCount = tournament.teamCount + let seedIntervalPointRange = tournament.tournamentLevel.pointsRange(first: match.index, last: match.index + displayableMatches.filter({ $0.index == match.index }).count, teamsCount: tournamentTeamCount) + HStack { + Text(match.matchTitle(.wide)) + Spacer() + Text(seedIntervalPointRange) + .font(.caption) + } + } footer: { + if isEditingLoserBracketGroupStage == true { + GroupStageLoserBracketMatchFooterView(match: match, samePlaceThanAboveOption: displayableMatches.count > 1) + } + } + } + Section { + if displayableMatches.count > 1 && isEditingLoserBracketGroupStage == true { + Section { + RowButtonView("Effacer tous les matchs", role: .destructive) { + _deleteAllMatches() + } + } footer: { + Text("Efface tous les matchs de classement de poules ci-dessus.") + } + } + } + } + .overlay { + if displayableMatches.isEmpty { + ContentUnavailableView { + Label("Aucun match de classement", systemImage: "figure.tennis") + } description: { + Text("Vous n'avez créé aucun match de classement entre les perdants de poules.") + } actions: { + RowButtonView("Ajouter un match") { + isEditingLoserBracketGroupStage = true + _addNewMatch() + } + .padding(.horizontal) + } + } + } + .headerProminence(.increased) + .navigationTitle("Classement de poules") + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + if displayableMatches.isEmpty == false { + Button(isEditingLoserBracketGroupStage == true ? "Valider" : "Modifier") { + if isEditingLoserBracketGroupStage == true { + isEditingLoserBracketGroupStage = false + } else { + isEditingLoserBracketGroupStage = true + } + } + } + } + } + } + + private func _addNewMatch() { + let currentGroupStageLoserBracketsInitialPlace = tournament.groupStageLoserBracketsInitialPlace() + let placeCount = displayableMatches.isEmpty ? currentGroupStageLoserBracketsInitialPlace : max(currentGroupStageLoserBracketsInitialPlace, displayableMatches.map({ $0.index }).max()! + 2) + let match = Match(round: loserBracket.id, index: placeCount, matchFormat: loserBracket.matchFormat) + match.name = "\(placeCount)\(placeCount.ordinalFormattedSuffix()) place" + do { + try tournamentStore.matches.addOrUpdate(instance: match) + } catch { + Logger.error(error) + } + } + + private func _deleteAllMatches() { + let displayableMatches = loserBracket.playedMatches().sorted(by: \.index) + + do { + for match in displayableMatches { + try match.deleteDependencies() + } + try tournamentStore.matches.delete(contentOfs: displayableMatches) + } catch { + Logger.error(error) + } + + } +} + +struct GroupStageLoserBracketMatchFooterView: View { + @Environment(Tournament.self) var tournament: Tournament + @Bindable var match: Match + let samePlaceThanAboveOption: Bool + @State private var selectPlacePlayed: Bool = false + @State private var index: Int = 0 + + var body: some View { + HStack { + Menu { + if samePlaceThanAboveOption { + Button("Même place qu'au-dessus") { + _updateIndex(match.index-2) + } + } + Button("Choisir la place") { + index = match.index + selectPlacePlayed = true + } + } label: { + Text("Éditer la place jouée") + .underline() + } + + Spacer() + FooterButtonView("Effacer", role: .destructive) { + do { + try match.deleteDependencies() + try match.tournamentStore.matches.delete(instance: match) + } catch { + Logger.error(error) + } + } + } + .alert("Place jouée", isPresented: $selectPlacePlayed) { + TextField("Place jouée", value: $index, format: .number) + .keyboardType(.numberPad) + .multilineTextAlignment(.trailing) + .onSubmit { + _updateIndex(index) + } + Button("Confirmer") { + _updateIndex(index) + } + Button("Annuler", role: .cancel) { + } + } + } + + private func _updateIndex(_ newIndex: Int) { + let newIndexValidated = max(1,abs(newIndex)) + let teamScores = match.teamScores + teamScores.forEach { ts in + if let luckyLoser = ts.luckyLoser { + ts.luckyLoser = (luckyLoser - match.index * 2) % 2 + newIndexValidated * 2 + } + } + + match.index = newIndexValidated + + match.name = "\(newIndexValidated)\(newIndexValidated.ordinalFormattedSuffix()) place" + + + do { + try match.tournamentStore.teamScores.addOrUpdate(contentOfs: teamScores) + } catch { + Logger.error(error) + } + do { + try match.tournamentStore.matches.addOrUpdate(instance: match) + } catch { + Logger.error(error) + } + } +} diff --git a/PadelClub/Views/GroupStage/LoserGroupStageSettingsView.swift b/PadelClub/Views/GroupStage/LoserGroupStageSettingsView.swift deleted file mode 100644 index 78ccdd0..0000000 --- a/PadelClub/Views/GroupStage/LoserGroupStageSettingsView.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// LoserGroupStageSettingsView.swift -// PadelClub -// -// Created by Razmig Sarkissian on 29/06/2024. -// - -import SwiftUI - -extension Round { - var isGroupStageLoserBracket: Bool { - return false - } -} - -extension Tournament { - func groupStageLoserBrackets() -> [Round] { - [] - } - - func removeGroupStageLoserBrackets() { - - } -} - -struct LoserGroupStageSettingsView: View { - var tournament: Tournament - @State private var loserGroupStageBracketType: Int? = nil - @State private var losers : Set = Set() - @Environment(\.editMode) private var editMode - - var body: some View { - List(selection: $losers) { - if tournament.groupStageLoserBrackets().isEmpty == false { - //for each all rounds without parent and loserGroupStage, ability to delete them - Section { - RowButtonView("Effacer", role: .destructive) { - tournament.removeGroupStageLoserBrackets() - } - } - } - - if self.editMode?.wrappedValue == .active { - Section { - //rajouter + toolbar valider / cancel - ForEach(tournament.groupStageTeams().filter({ $0.qualified == false })) { team in - TeamRowView(team: team).tag(team) - } - } header: { - Text("Sélection des perdants de poules") - } - } else { - Section { - RowButtonView("Ajouter un match de perdant") { - self.editMode?.wrappedValue = .active - } - } footer: { - Text("Permet d'ajouter un match de perdant de poules.") - } - } - } - .toolbar { - if self.editMode?.wrappedValue == .active { - ToolbarItem(placement: .topBarLeading) { - Button("Annuler") { - self.editMode?.wrappedValue = .inactive - } - } - - ToolbarItem(placement: .topBarTrailing) { - Button("Valider") { - self.editMode?.wrappedValue = .inactive - //tournament.createGroupStageLoserBracket() - } - } - } - } - .navigationTitle("Match de perdant de poules") - .navigationBarBackButtonHidden(self.editMode?.wrappedValue == .active) - .navigationBarTitleDisplayMode(.inline) - .toolbar(.visible, for: .navigationBar) - .headerProminence(.increased) - .toolbarBackground(.visible, for: .navigationBar) - } -} diff --git a/PadelClub/Views/Match/Components/PlayerBlockView.swift b/PadelClub/Views/Match/Components/PlayerBlockView.swift index cc3ea7b..444aa94 100644 --- a/PadelClub/Views/Match/Components/PlayerBlockView.swift +++ b/PadelClub/Views/Match/Components/PlayerBlockView.swift @@ -8,7 +8,7 @@ import SwiftUI struct PlayerBlockView: View { - var match: Match + @State var match: Match let teamPosition: TeamPosition let team: TeamRegistration? let color: Color @@ -52,7 +52,7 @@ struct PlayerBlockView: View { HStack { VStack(alignment: .leading) { if let names { - if let teamScore, teamScore.luckyLoser != nil { + if let teamScore, teamScore.luckyLoser != nil, match.isLoserBracket == false { Text("Repêchée").italic().font(.caption) } diff --git a/PadelClub/Views/Match/EditSharingView.swift b/PadelClub/Views/Match/EditSharingView.swift index 33c0116..651e419 100644 --- a/PadelClub/Views/Match/EditSharingView.swift +++ b/PadelClub/Views/Match/EditSharingView.swift @@ -24,17 +24,19 @@ struct EditSharingView: View { func shareMessage(displayRank: Bool, displayTeamName: Bool) -> String { var messageData: [String] = [] - var locAndTime: String = "" - if let courtName = match.courtName() { - locAndTime.append("\(courtName)") - } - - if let startDate = match.startDate { - locAndTime = locAndTime + " à " + startDate.formattedAsHourMinute() - } - - if locAndTime.isEmpty == false { - messageData.append(locAndTime) + if match.hasEnded() == false { + var locAndTime: String? + if let courtName = match.courtName() { + locAndTime = "\(courtName)" + } + + if let startDate = match.startDate { + locAndTime = [locAndTime, startDate.formattedAsHourMinute()].compactMap({ $0 }).joined(separator: " à ") + } + + if let locAndTime, locAndTime.isEmpty == false { + messageData.append(locAndTime) + } } if let tournament = match.currentTournament() { @@ -52,6 +54,8 @@ struct EditSharingView: View { let players = "\(labelOne)\ncontre\n\(labelTwo)" messageData.append(players) + messageData.append(match.scoreLabel()) + return messageData.joined(separator: "\n") } diff --git a/PadelClub/Views/Match/MatchRowView.swift b/PadelClub/Views/Match/MatchRowView.swift index 3c486a8..954da7f 100644 --- a/PadelClub/Views/Match/MatchRowView.swift +++ b/PadelClub/Views/Match/MatchRowView.swift @@ -9,7 +9,8 @@ import SwiftUI struct MatchRowView: View { - var match: Match + @EnvironmentObject var dataStore: DataStore + @State var match: Match let matchViewStyle: MatchViewStyle var title: String? = nil diff --git a/PadelClub/Views/Match/MatchSetupView.swift b/PadelClub/Views/Match/MatchSetupView.swift index 65a98f7..1998374 100644 --- a/PadelClub/Views/Match/MatchSetupView.swift +++ b/PadelClub/Views/Match/MatchSetupView.swift @@ -13,13 +13,17 @@ struct MatchSetupView: View { @EnvironmentObject var dataStore: DataStore - var match: Match + @State var match: Match @State private var seedGroup: SeedInterval? var tournamentStore: TournamentStore { return match.tournamentStore } + var matchTypeContext: MatchType { + match.matchType + } + @ViewBuilder var body: some View { ForEach(TeamPosition.allCases) { teamPosition in @@ -38,7 +42,7 @@ struct MatchSetupView: View { if let team, teamScore?.walkOut == nil { VStack(alignment: .leading, spacing: 0) { - if let teamScore, teamScore.luckyLoser != nil { + if let teamScore, teamScore.luckyLoser != nil, match.isLoserBracket == false { Text("Repêchée").italic().font(.caption) } Menu { @@ -59,9 +63,9 @@ struct MatchSetupView: View { } HStack { let luckyLosers = walkOutSpot ? match.luckyLosers() : [] - TeamPickerView(shouldConfirm: shouldConfirm, groupStagePosition: nil, luckyLosers: luckyLosers, teamPicked: { team in + TeamPickerView(shouldConfirm: shouldConfirm, groupStagePosition: nil, matchTypeContext: matchTypeContext, luckyLosers: luckyLosers, teamPicked: { team in print(team.pasteData()) - if walkOutSpot || team.bracketPosition != nil { + if walkOutSpot || team.bracketPosition != nil || matchTypeContext == .loserBracket { match.setLuckyLoser(team: team, teamPosition: teamPosition) do { try tournamentStore.matches.addOrUpdate(instance: match) @@ -82,7 +86,7 @@ struct MatchSetupView: View { } } }) - if let tournament = match.currentTournament() { + if matchTypeContext == .bracket, let tournament = match.currentTournament() { let availableQualifiedTeams = tournament.availableQualifiedTeams() let availableSeedGroups = tournament.availableSeedGroups() Text("ou") @@ -146,30 +150,33 @@ struct MatchSetupView: View { .underline() } .disabled(availableSeedGroups.isEmpty && walkOutSpot == false && availableQualifiedTeams.isEmpty) - Spacer() - if match.isSeedLocked(atTeamPosition: teamPosition) { - Button { - match.unlockSeedPosition(atTeamPosition: teamPosition) - do { - try tournamentStore.matches.addOrUpdate(instance: match) - } catch { - Logger.error(error) + + if matchTypeContext == .bracket { + Spacer() + if match.isSeedLocked(atTeamPosition: teamPosition) { + Button { + match.unlockSeedPosition(atTeamPosition: teamPosition) + do { + try tournamentStore.matches.addOrUpdate(instance: match) + } catch { + Logger.error(error) + } + } label: { + Text("Libérer") + .underline() } - } label: { - Text("Libérer") - .underline() - } - } else { - ConfirmButtonView(shouldConfirm: shouldConfirm, message: MatchSetupView.confirmationMessage) { - _ = match.lockAndGetSeedPosition(atTeamPosition: teamPosition) - do { - try tournamentStore.matches.addOrUpdate(instance: match) - } catch { - Logger.error(error) + } else { + ConfirmButtonView(shouldConfirm: shouldConfirm, message: MatchSetupView.confirmationMessage) { + _ = match.lockAndGetSeedPosition(atTeamPosition: teamPosition) + do { + try tournamentStore.matches.addOrUpdate(instance: match) + } catch { + Logger.error(error) + } + } label: { + Text("Réserver") + .underline() } - } label: { - Text("Réserver") - .underline() } } } @@ -207,6 +214,14 @@ struct MatchSetupView: View { } catch { Logger.error(error) } + } else if match.isLoserBracket { + if let score = match.teamScore(ofTeam: team) { + do { + try tournamentStore.teamScores.delete(instance: score) + } catch { + Logger.error(error) + } + } } else { match.teamWillBeWalkOut(team) do { diff --git a/PadelClub/Views/Match/MatchSummaryView.swift b/PadelClub/Views/Match/MatchSummaryView.swift index 16fd9bf..1e4bda1 100644 --- a/PadelClub/Views/Match/MatchSummaryView.swift +++ b/PadelClub/Views/Match/MatchSummaryView.swift @@ -8,7 +8,8 @@ import SwiftUI struct MatchSummaryView: View { - var match: Match + @EnvironmentObject var dataStore: DataStore + @State var match: Match let matchViewStyle: MatchViewStyle let matchTitle: String let roundTitle: String? diff --git a/PadelClub/Views/Navigation/Agenda/ActivityView.swift b/PadelClub/Views/Navigation/Agenda/ActivityView.swift index 09ac9c4..596b360 100644 --- a/PadelClub/Views/Navigation/Agenda/ActivityView.swift +++ b/PadelClub/Views/Navigation/Agenda/ActivityView.swift @@ -16,12 +16,13 @@ struct ActivityView: View { @State private var presentFilterView: Bool = false @State private var presentToolbar: Bool = false @State private var newTournament: Tournament? - @State private var viewStyle: AgendaDestination.ViewStyle = .list + @State private var viewStyle: ViewStyle = .list @State private var isGatheringFederalTournaments: Bool = false @State private var error: Error? @State private var uuid: UUID = UUID() @State private var presentClubSearchView: Bool = false @State private var quickAccessScreen: QuickAccessScreen? = nil + @State private var displaySearchView: Bool = false enum QuickAccessScreen : Identifiable, Hashable { case inscription(pasteString: String) @@ -67,6 +68,8 @@ struct ActivityView: View { return endedTournaments case .tenup: return federalDataViewModel.filteredFederalTournaments + case .around: + return federalDataViewModel.filteredSearchedFederalTournaments } } @@ -87,17 +90,27 @@ struct ActivityView: View { VStack(spacing: 0) { GenericDestinationPickerView(selectedDestination: $navigation.agendaDestination, destinations: AgendaDestination.allCases, nilDestinationIsValid: false) - List { - switch navigation.agendaDestination! { - case .activity: - EventListView(tournaments: runningTournaments, viewStyle: viewStyle, sortAscending: true) - case .history: - EventListView(tournaments: endedTournaments, viewStyle: viewStyle, sortAscending: false) - case .tenup: - EventListView(tournaments: federalDataViewModel.federalTournaments, viewStyle: viewStyle, sortAscending: true) - .id(uuid) + ScrollViewReader { proxy in + List { + switch navigation.agendaDestination! { + case .activity: + EventListView(tournaments: runningTournaments, sortAscending: true) + case .history: + EventListView(tournaments: endedTournaments, sortAscending: false) + case .tenup: + EventListView(tournaments: federalDataViewModel.federalTournaments, sortAscending: true) + .id(uuid) + case .around: + EventListView(tournaments: federalDataViewModel.searchedFederalTournaments, sortAscending: true) + } + } + .onChange(of: navigation.agendaDestination) { + withAnimation { + proxy.scrollTo(0, anchor: .center) + } } } + .environment(\.viewStyle, viewStyle) .environment(federalDataViewModel) .overlay { if let error, navigation.agendaDestination == .tenup { @@ -119,14 +132,18 @@ struct ActivityView: View { ContentUnavailableView.search(text: searchText) } else if federalDataViewModel.areFiltersEnabled() { ContentUnavailableView { - Text("Aucun résultat") + Text("Aucun tournoi") } description: { - Text(federalDataViewModel.filterStatus()) + Text("Aucun tournoi ne correspond aux fitres que vous avez choisis : \(federalDataViewModel.filterStatus())") } actions: { - RowButtonView("supprimer le filtre") { + FooterButtonView("supprimer vos filtres") { federalDataViewModel.removeFilters() } .padding(.horizontal) + FooterButtonView("modifier vos filtres") { + presentFilterView = true + } + .padding(.horizontal) } } else { _dataEmptyView() @@ -134,147 +151,213 @@ struct ActivityView: View { } } } - //.searchable(text: $searchText) - .onAppear { presentToolbar = true } - .onDisappear { presentToolbar = false } - .sheet(item: $newTournament) { tournament in - EventCreationView(tournaments: [tournament], selectedClub: federalDataViewModel.selectedClub()) - .environment(navigation) - .tint(.master) + } + //.searchable(text: $searchText) + .onAppear { presentToolbar = true } + .onDisappear { presentToolbar = false } + .refreshable { + if navigation.agendaDestination == .tenup { + federalDataViewModel.federalTournaments.removeAll() + NetworkFederalService.shared.formId = "" + _gatherFederalTournaments() } - .refreshable { - if navigation.agendaDestination == .tenup { - federalDataViewModel.federalTournaments.removeAll() - NetworkFederalService.shared.formId = "" - _gatherFederalTournaments() - } + } + .task { + if navigation.agendaDestination == .tenup + && dataStore.user.hasTenupClubs() == true + && federalDataViewModel.federalTournaments.isEmpty { + _gatherFederalTournaments() } - .task { - if navigation.agendaDestination == .tenup - && dataStore.user.hasTenupClubs() == true - && federalDataViewModel.federalTournaments.isEmpty { - _gatherFederalTournaments() - } + } + .onChange(of: navigation.agendaDestination) { + if tournaments.isEmpty, viewStyle == .calendar { + viewStyle = .list } - .onChange(of: navigation.agendaDestination) { - if navigation.agendaDestination == .tenup - && dataStore.user.hasTenupClubs() == true - && federalDataViewModel.federalTournaments.isEmpty { - _gatherFederalTournaments() + + if navigation.agendaDestination == .tenup + && dataStore.user.hasTenupClubs() == true + && federalDataViewModel.federalTournaments.isEmpty { + _gatherFederalTournaments() + } + } + .onChange(of: presentFilterView, { old, new in + if old == true, new == false { //closing filter view + if tournaments.isEmpty, viewStyle == .calendar { + viewStyle = .list } } - .toolbar { - if presentToolbar { - //let _activityStatus = _activityStatus() - if federalDataViewModel.areFiltersEnabled() { - ToolbarItem(placement: .status) { - Text(federalDataViewModel.filterStatus()) - } + }) + .toolbarTitleDisplayMode(.large) + .navigationTitle(TabDestination.activity.title) + .navigationDestination(for: Tournament.self) { tournament in + TournamentView(tournament: tournament) + } + .toolbar { + ToolbarItemGroup(placement: .topBarLeading) { + Button { + switch viewStyle { + case .list: + viewStyle = .calendar + case .calendar: + viewStyle = .list } + } label: { + Image(systemName: "calendar.circle") + .resizable() + .scaledToFit() + .frame(minHeight: 32) + } + .symbolVariant(viewStyle == .calendar ? .fill : .none) + + Button { + presentFilterView.toggle() + } label: { + Image(systemName: "line.3.horizontal.decrease.circle") + .resizable() + .scaledToFit() + .frame(minHeight: 32) + } + .symbolVariant(federalDataViewModel.areFiltersEnabled() ? .fill : .none) + + _pasteView() + } + + ToolbarItem(placement: .topBarTrailing) { + Button { + newTournament = Tournament.newEmptyInstance() - ToolbarItemGroup(placement: .topBarLeading) { - Button { - switch viewStyle { - case .list: - viewStyle = .calendar - case .calendar: - viewStyle = .list - } - } label: { - Image(systemName: "calendar.circle") - .resizable() - .scaledToFit() - .frame(minHeight: 28) + } label: { + Image(systemName: "plus.circle.fill") + .resizable() + .scaledToFit() + .frame(minHeight: 32) + } + } + + if presentToolbar, tournaments.isEmpty == false, federalDataViewModel.areFiltersEnabled() || navigation.agendaDestination == .around { + ToolbarItemGroup(placement: .bottomBar) { + VStack(spacing: 0) { + let searchStatus = _searchStatus() + if searchStatus.isEmpty == false { + Text(_searchStatus()) + .font(.footnote) + .foregroundStyle(.secondary) } - .symbolVariant(viewStyle == .calendar ? .fill : .none) - Button { - presentFilterView.toggle() - } label: { - Image(systemName: "line.3.horizontal.decrease.circle") - .resizable() - .scaledToFit() - .frame(minHeight: 28) - } - .symbolVariant(federalDataViewModel.areFiltersEnabled() ? .fill : .none) - - _pasteView() - } - - ToolbarItem(placement: .topBarTrailing) { - Button { - newTournament = Tournament.newEmptyInstance() + HStack { + if navigation.agendaDestination == .around { + FooterButtonView("modifier votre recherche") { + displaySearchView = true + } + + if federalDataViewModel.areFiltersEnabled() { + Text("ou") + } + } - } label: { - Image(systemName: "plus.circle.fill") - .resizable() - .scaledToFit() - .frame(minHeight: 28) + if federalDataViewModel.areFiltersEnabled() { + FooterButtonView(_filterButtonTitle()) { + presentFilterView = true + } + + } } + .padding(.bottom, 8) } } } - .navigationTitle(TabDestination.activity.title) - .navigationDestination(for: Tournament.self) { tournament in - TournamentView(tournament: tournament) - } - .sheet(isPresented: $presentFilterView) { - TournamentFilterView(federalDataViewModel: federalDataViewModel) - .environment(navigation) - .tint(.master) - } - .sheet(isPresented: $presentClubSearchView, onDismiss: { - if dataStore.user.hasTenupClubs() == true { - federalDataViewModel.federalTournaments.removeAll() - navigation.agendaDestination = .tenup - } - }) { - ClubImportView() - .tint(.master) + } + .sheet(isPresented: $presentFilterView) { + TournamentFilterView(federalDataViewModel: federalDataViewModel) + .environment(navigation) + .tint(.master) + } + .sheet(isPresented: $presentClubSearchView, onDismiss: { + if dataStore.user.hasTenupClubs() == true { + federalDataViewModel.federalTournaments.removeAll() + navigation.agendaDestination = .tenup } + }) { + ClubImportView() + .tint(.master) } - } - .sheet(item: $quickAccessScreen) { screen in - switch screen { - case .inscription(let pasteString): + .sheet(isPresented: $displaySearchView) { NavigationStack { - List { - Section { - Text(pasteString) - } header: { - Text("Contenu du presse-papier") - } - - Section { - ForEach(getRunningTournaments()) { tournament in - NavigationLink { - AddTeamView(tournament: tournament, pasteString: pasteString, editedTeam: nil) - } label: { - VStack(alignment: .leading) { - Text(tournament.tournamentTitle()) - Text(tournament.formattedDate()).foregroundStyle(.secondary) + TournamentLookUpView() + .environment(federalDataViewModel) + } + } + .sheet(item: $newTournament) { tournament in + EventCreationView(tournaments: [tournament], selectedClub: federalDataViewModel.selectedClub()) + .environment(navigation) + .tint(.master) + } + .sheet(item: $quickAccessScreen) { screen in + switch screen { + case .inscription(let pasteString): + NavigationStack { + List { + Section { + Text(pasteString) + } header: { + Text("Contenu du presse-papier") + } + + Section { + ForEach(getRunningTournaments()) { tournament in + NavigationLink { + AddTeamView(tournament: tournament, pasteString: pasteString, editedTeam: nil) + } label: { + VStack(alignment: .leading) { + Text(tournament.tournamentTitle()) + Text(tournament.formattedDate()).foregroundStyle(.secondary) + } } } + } header: { + Text("À coller dans la liste d'inscription") } - } header: { - Text("À coller dans la liste d'inscription") } - } - .toolbar { - ToolbarItem(placement: .topBarLeading) { - Button("Fermer") { - self.quickAccessScreen = nil + .toolbar { + ToolbarItem(placement: .topBarLeading) { + Button("Fermer") { + self.quickAccessScreen = nil + } } } + .navigationTitle("Choix du tournoi") + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(.visible, for: .navigationBar) } - .navigationTitle("Choix du tournoi") - .navigationBarTitleDisplayMode(.inline) - .toolbarBackground(.visible, for: .navigationBar) } } } } + private func _searchStatus() -> String { + var searchStatus : [String] = [] + if navigation.agendaDestination == .around, federalDataViewModel.searchedFederalTournaments.isEmpty == false { + let filteredSearchedFederalTournaments = federalDataViewModel.filteredSearchedFederalTournaments + + let status : String = filteredSearchedFederalTournaments.count.formatted() + " tournoi" + filteredSearchedFederalTournaments.count.pluralSuffix + searchStatus.append(status) + } + + if federalDataViewModel.areFiltersEnabled(), tournaments.isEmpty == false { + searchStatus.append(federalDataViewModel.filterStatus()) + } + + return searchStatus.joined(separator: " ") + } + + private func _filterButtonTitle() -> String { + var prefix = "modifier " + if navigation.agendaDestination == .around, federalDataViewModel.searchedFederalTournaments.isEmpty == false { + prefix = "" + } + return prefix + "vos filtres" + } + private func _gatherFederalTournaments() { isGatheringFederalTournaments = true Task { @@ -298,6 +381,8 @@ struct ActivityView: View { _endedEmptyView() case .tenup: _tenupEmptyView() + case .around: + _searchTenupEmptyView() } } @@ -363,6 +448,33 @@ struct ActivityView: View { } } + @ViewBuilder + private func _searchTenupEmptyView() -> some View { + if federalDataViewModel.searchAttemptCount == 0 { + ContentUnavailableView { + Label("Recherche de tournoi", systemImage: "magnifyingglass") + } description: { + Text("Chercher les tournois autour de vous pour mieux décider les tournois à proposer dans votre club. Padel Club vous facilite même l'inscription !") + } actions: { + RowButtonView("Lancer la recherche") { + displaySearchView = true + } + .padding() + } + } else { + ContentUnavailableView { + Label("Aucun tournoi", systemImage: "shield.slash") + } description: { + Text("Aucun tournoi ne correspond aux critères sélectionnés.") + } actions: { + FooterButtonView("modifier vos critères de recherche") { + displaySearchView = true + } + .padding() + } + } + } + } //#Preview { diff --git a/PadelClub/Views/Navigation/Agenda/CalendarView.swift b/PadelClub/Views/Navigation/Agenda/CalendarView.swift index a39f63f..474fb28 100644 --- a/PadelClub/Views/Navigation/Agenda/CalendarView.swift +++ b/PadelClub/Views/Navigation/Agenda/CalendarView.swift @@ -91,8 +91,15 @@ struct CalendarView: View { Menu { ForEach(tournament.tournaments, id: \.id) { build in if federalDataViewModel.isFederalTournamentValidForFilters(tournament, build: build) { - Button(build.buildHolderTitle()) { - _createOrShow(federalTournament: tournament, existingTournament: event(forTournament: tournament)?.existingBuild(build), build: build) + + if navigation.agendaDestination == .around { + NavigationLink(build.buildHolderTitle()) { + TournamentSubscriptionView(federalTournament: tournament, build: build, user: dataStore.user) + } + } else { + Button(build.buildHolderTitle()) { + _createOrShow(federalTournament: tournament, existingTournament: event(forTournament: tournament)?.existingBuild(build), build: build) + } } } } diff --git a/PadelClub/Views/Navigation/Agenda/EventListView.swift b/PadelClub/Views/Navigation/Agenda/EventListView.swift index 4c89482..3a8a53b 100644 --- a/PadelClub/Views/Navigation/Agenda/EventListView.swift +++ b/PadelClub/Views/Navigation/Agenda/EventListView.swift @@ -12,16 +12,19 @@ struct EventListView: View { @EnvironmentObject var dataStore: DataStore @Environment(NavigationViewModel.self) var navigation: NavigationViewModel @Environment(FederalDataViewModel.self) var federalDataViewModel: FederalDataViewModel + @Environment(\.viewStyle) var viewStyle let tournaments: [FederalTournamentHolder] - let viewStyle: AgendaDestination.ViewStyle let sortAscending: Bool var body: some View { - let groupedTournamentsByDate = Dictionary(grouping: navigation.agendaDestination == .tenup ? federalDataViewModel.filteredFederalTournaments : tournaments) { $0.startDate.startOfMonth } + let groupedTournamentsByDate = Dictionary(grouping: federalDataViewModel.filteredFederalTournaments(from: tournaments)) { $0.startDate.startOfMonth } switch viewStyle { case .list: - ForEach(groupedTournamentsByDate.keys.sorted(by: sortAscending ? { $0 < $1 } : { $0 > $1 }), id: \.self) { section in + let nextMonths = groupedTournamentsByDate.keys.sorted(by: sortAscending ? { $0 < $1 } : { $0 > $1 }) + + ForEach(nextMonths.indices, id: \.self) { sectionIndex in + let section = nextMonths[sectionIndex] if let _tournaments = groupedTournamentsByDate[section]?.sorted(by: sortAscending ? { $0.startDate < $1.startDate } : { $0.startDate > $1.startDate } ) { Section { @@ -34,11 +37,14 @@ struct EventListView: View { Text("\(count.formatted()) tournoi" + count.pluralSuffix) } } + .id(sectionIndex) .headerProminence(.increased) } } case .calendar: - ForEach(_nextMonths(), id: \.self) { section in + let nextMonths = _nextMonths() + ForEach(nextMonths.indices, id: \.self) { sectionIndex in + let section = nextMonths[sectionIndex] let _tournaments = groupedTournamentsByDate[section] ?? [] Section { CalendarView(date: section, tournaments: _tournaments).id(federalDataViewModel.id) @@ -50,6 +56,7 @@ struct EventListView: View { Text("\(count.formatted()) tournoi" + count.pluralSuffix) } } + .id(sectionIndex) .headerProminence(.increased) .task { if navigation.agendaDestination == .tenup @@ -77,16 +84,25 @@ struct EventListView: View { } private func _nextMonths() -> [Date] { - var result: [Date] = [] - var currentDate = Date().startOfMonth - - // Generate 100 future months - for _ in 0..<12 { - result.append(currentDate) - currentDate = Calendar.current.date(byAdding: .month, value: 1, to: currentDate)! + let currentDate = Date().startOfMonth + let uniqueDates = tournaments.map { $0.startDate.startOfMonth }.uniqued().sorted() + let firstMonthOfDate = uniqueDates.first + let lastMonthOfDate = uniqueDates.last + let calendar = Calendar.current + + if let firstMonthOfDate, let lastMonthOfDate { + if navigation.agendaDestination == .history { + return calendar.generateMonthRange(startDate: firstMonthOfDate, endDate: lastMonthOfDate).reversed() + } else if navigation.agendaDestination == .around || navigation.agendaDestination == .tenup { + return calendar.generateMonthRange(startDate: firstMonthOfDate, endDate: lastMonthOfDate) + } else { + let min = min(currentDate, firstMonthOfDate) + let max = max(currentDate, lastMonthOfDate) + return calendar.generateMonthRange(startDate: min, endDate: calendar.addMonths(3, to: max)) + } + } else { + return calendar.generateMonthRange(startDate: currentDate, endDate: calendar.addMonths(3, to: currentDate)) } - - return result } private func _listView(_ tournaments: [FederalTournamentHolder]) -> some View { diff --git a/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift b/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift new file mode 100644 index 0000000..d4e8ca7 --- /dev/null +++ b/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift @@ -0,0 +1,483 @@ +// +// TournamentLookUpView.swift +// PadelClub +// +// Created by razmig on 08/09/2024. +// + +import SwiftUI +import CoreLocation +import CoreLocationUI + +struct TournamentLookUpView: View { + @Environment(FederalDataViewModel.self) var federalDataViewModel: FederalDataViewModel + @StateObject var locationManager = LocationManager() + @Environment(\.dismiss) private var dismiss + + @State private var searchField: String = "" + @State var page: Int = 0 + @State var total: Int = 0 + + @State private var tournamentCategories = Set() + @State private var tournamentLevels = Set() + @State private var tournamentAges = Set() + @State private var tournamentTypes = Set() + @State private var searching: Bool = false + @State private var startDate: Date = Date() + @State private var endDate: Date = Calendar.current.date(byAdding: .month, value: 3, to: Date())! + @AppStorage("lastCity") private var city: String = "" + @State private var ligue: String = "" + @State private var distance: Double = 30 + @State private var sortingOption: String = "dateDebut+asc" + @State private var requestedToGetAllPages: Bool = false + @State private var nationalCup: Bool = false + @State private var revealSearchParameters: Bool = true + @State private var presentAlert: Bool = false + + var tournaments: [FederalTournament] { + federalDataViewModel.searchedFederalTournaments + } + + var body: some View { + List { + searchParametersView + } + .alert("Attention", isPresented: $presentAlert, actions: { + Button { + presentAlert = false + requestedToGetAllPages = true + page += 1 + searching = true + Task { + await getNewPage() + searching = false + dismiss() + } + } label: { + Label("Tout voir", systemImage: "arrow.down.circle") + } + Button("Annuler") { + revealSearchParameters = true + presentAlert = false + } + }, message: { + Text("Il y a beacoup de tournois pour cette requête, êtes-vous sûr de vouloir tout récupérer ? Sinon essayez d'affiner votre recherche.") + }) + .toolbarBackground(.visible, for: .bottomBar, .navigationBar) + .navigationTitle("Chercher un tournoi") + .navigationBarTitleDisplayMode(.inline) + .onChange(of: locationManager.city) { + if let newValue = locationManager.city, city.isEmpty { + city = newValue + } + } + .toolbarTitleDisplayMode(.large) + .toolbar { + ToolbarItem(placement: .bottomBar) { + if revealSearchParameters { + FooterButtonView("Lancer la recherche") { + runSearch() + } + .disabled(searching) + } else if searching { + HStack(spacing: 20) { + Spacer() + ProgressView() + if total > 0 { + let percent = Double(tournaments.count) / Double(total) + Text(percent.formatted(.percent.precision(.significantDigits(1...3))) + " en récupération de Tenup") + .font(.caption) + } + Spacer() + } + } + } + ToolbarItem(placement: .topBarTrailing) { + Menu { +#if DEBUG + if tournaments.isEmpty == false { + Section { + ShareLink(item: pastedTournaments) { + Label("Par texte", systemImage: "square.and.arrow.up") + .labelStyle(.titleAndIcon) + } + ShareLink(item: japList) { + Label("JAP liste", systemImage: "square.and.arrow.up") + .labelStyle(.titleAndIcon) + } + } header: { + Text("Partager les résultats") + } + } + Divider() +#endif + + Button(role: .destructive) { + tournamentLevels = Set() + tournamentCategories = Set() + city = "" + locationManager.location = nil + locationManager.city = nil + distance = 30 + startDate = Date() + endDate = Calendar.current.date(byAdding: .month, value: 3, to: Date())! + sortingOption = "dateDebut+asc" + revealSearchParameters = true + federalDataViewModel.searchedFederalTournaments = [] + federalDataViewModel.searchAttemptCount = 0 + } label: { + Text("Ré-initialiser la recherche") + } + } label: { + Label("Options", systemImage: "ellipsis.circle") + } + } + } + } + var pastedTournaments: String { + tournaments.map { $0.shareMessage }.joined() + } + + var japList: String { + Set(tournaments.map { $0.japMessage }).joined(separator: "\n") + } + + private var clubsFound: [String] { + Set(tournaments.compactMap { $0.nomClub }).sorted() + } + + private var liguesFound: [String] { + Set(tournaments.compactMap { $0.nomLigue }).sorted() + } + + private func runSearch() { + revealSearchParameters = false + total = 0 + page = 0 + federalDataViewModel.searchedFederalTournaments = [] + searching = true + requestedToGetAllPages = false + federalDataViewModel.searchAttemptCount += 1 + Task { + await getNewPage() + searching = false + if tournaments.isEmpty == false && tournaments.count < total && total >= 200 && requestedToGetAllPages == false { + presentAlert = true + } else { + dismiss() + } + } + } + + private var distanceLimit: Measurement { + distanceLimit(distance: distance) + } + + private func distanceLimit(distance: Double) -> Measurement { + Measurement(value: distance, unit: .kilometers) + } + + private var categories: [TournamentCategory] { + tournamentCategories.compactMap { TournamentCategory(rawValue: $0) } + } + + private var levels: [TournamentLevel] { + tournamentLevels.compactMap { TournamentLevel(rawValue: $0) } + } + + private var ages: [FederalTournamentAge] { + tournamentAges.compactMap { FederalTournamentAge(rawValue: $0) } + } + + private var types: [FederalTournamentType] { + tournamentTypes.compactMap { FederalTournamentType(rawValue: $0) } + } + + func getNewPage() async { + do { + if NetworkFederalService.shared.formId.isEmpty { + await getNewBuildForm() + } else { + let commands = try await NetworkFederalService.shared.getAllFederalTournaments(sortingOption: sortingOption, page: page, startDate: startDate, endDate: endDate, city: city, distance: distance, categories: categories, levels: levels, lat: locationManager.location?.coordinate.latitude.formatted(.number.locale(Locale(identifier: "us"))), lng: locationManager.location?.coordinate.longitude.formatted(.number.locale(Locale(identifier: "us"))), ages: ages, types: types, nationalCup: nationalCup) + let resultCommand = commands.first(where: { $0.results != nil }) + if let newTournaments = resultCommand?.results?.items { + newTournaments.forEach { ft in + if tournaments.contains(where: { $0.id == ft.id }) == false { + federalDataViewModel.searchedFederalTournaments.append(ft) + } + } + } + if let count = resultCommand?.results?.nb_results { + print("count", count, total, tournaments.count, page) + total = count + + if tournaments.count < count && page < total / 30 { + if total < 200 || requestedToGetAllPages { + page += 1 + await getNewPage() + } + } else { + print("finished") + } + } else { + print("total results not found") + } + } + } catch { + print("getNewPage", error) + await getNewBuildForm() + } + } + + func getNewBuildForm() async { + do { + try await NetworkFederalService.shared.getNewBuildForm() + await getNewPage() + } catch { + print("getNewBuildForm", error) + } + } + + @ViewBuilder + var searchContollerView: some View { + Section { + Button { + runSearch() + } label: { + HStack { + Label("Chercher un tournoi", systemImage: "magnifyingglass") + if searching { + Spacer() + ProgressView() + } + } + } + Button { + tournamentLevels = Set() + tournamentCategories = Set() + city = "" + locationManager.location = nil + locationManager.city = nil + distance = 30 + startDate = Date() + endDate = Calendar.current.date(byAdding: .month, value: 3, to: Date())! + sortingOption = "dateDebut+asc" + revealSearchParameters = true + } label: { + Label("Ré-initialiser la recherche", systemImage: "xmark.circle") + } + } + } + + @ViewBuilder + var searchParametersView: some View { + @Bindable var federalDataViewModel = federalDataViewModel + Section { + DatePicker("Début", selection: $startDate, displayedComponents: .date) + DatePicker("Fin", selection: $endDate, displayedComponents: .date) + Picker(selection: $federalDataViewModel.dayDuration) { + Text("aucune").tag(nil as Int?) + Text(1.formatted()).tag(1 as Int?) + Text(2.formatted()).tag(2 as Int?) + Text(3.formatted()).tag(3 as Int?) + } label: { + Text("Durée max (en jours)") + } + + Picker(selection: $federalDataViewModel.dayPeriod) { + ForEach(DayPeriod.allCases) { + Text($0.localizedDayPeriodLabel()).tag($0) + } + } label: { + Text("En semaine ou week-end") + } + + HStack { + TextField("Ville", text: $city) + if let city = locationManager.city { + Divider() + Text(city).italic() + } + if locationManager.requestStarted { + ProgressView() + } else { + LocationButton { + locationManager.requestLocation() + } + .symbolVariant(.fill) + .foregroundColor (Color.white) + .cornerRadius (20) + .font(.system(size: 12)) + } + } + + Picker(selection: $distance) { + Text(distanceLimit(distance:30).formatted()).tag(30.0) + Text(distanceLimit(distance:50).formatted()).tag(50.0) + Text(distanceLimit(distance:60).formatted()).tag(60.0) + Text(distanceLimit(distance:90).formatted()).tag(90.0) + Text(distanceLimit(distance:150).formatted()).tag(150.0) + Text(distanceLimit(distance:200).formatted()).tag(200.0) + Text(distanceLimit(distance:400).formatted()).tag(400.0) + Text("Aucune").tag(3000.0) + } label: { + Text("Distance max") + } + + Picker(selection: $sortingOption) { + Text("Distance").tag("_DIST_") + Text("Date de début").tag("dateDebut+asc") + Text("Date de fin").tag("dateFin+asc") + } label: { + Text("Trier par") + } + + NavigationLink { + List(TournamentCategory.allCases, selection: $tournamentCategories) { type in + Text(type.localizedLabel()) + } + .navigationTitle("Catégories") + .environment(\.editMode, Binding.constant(EditMode.active)) + } label: { + HStack { + Text("Catégorie") + Spacer() + categoriesLabel + .foregroundStyle(.secondary) + } + } + + NavigationLink { + List(TournamentLevel.allCases, selection: $tournamentLevels) { type in + Text(type.localizedLabel()) + } + .navigationTitle("Niveaux") + .environment(\.editMode, Binding.constant(EditMode.active)) + } label: { + HStack { + Text("Niveau") + Spacer() + levelsLabel + .foregroundStyle(.secondary) + } + } + + NavigationLink { + List(FederalTournamentAge.allCases, selection: $tournamentAges) { type in + Text(type.localizedLabel()) + } + .navigationTitle("Limites d'âge") + .environment(\.editMode, Binding.constant(EditMode.active)) + } label: { + HStack { + Text("Limite d'âge") + Spacer() + if tournamentAges.isEmpty || tournamentAges.count == FederalTournamentAge.allCases.count { + Text("Tous les âges") + .foregroundStyle(.secondary) + } else { + Text(ages.map({ $0.localizedLabel()}).joined(separator: ", ")) + .foregroundStyle(.secondary) + } + } + } + + NavigationLink { + List(FederalTournamentType.allCases, selection: $tournamentTypes) { type in + Text(type.localizedLabel()) + } + .navigationTitle("Types de tournoi") + .environment(\.editMode, Binding.constant(EditMode.active)) + } label: { + HStack { + Text("Type de tournoi") + Spacer() + if tournamentTypes.isEmpty || tournamentTypes.count == FederalTournamentType.allCases.count { + Text("Tous les types") + .foregroundStyle(.secondary) + } else { + Text(types.map({ $0.localizedLabel()}).joined(separator: ", ")) + .foregroundStyle(.secondary) + } + } + } + + Picker(selection: $nationalCup) { + Text("N'importe").tag(false) + Text("Uniquement").tag(true) + } label: { + Text("Circuit National Padel Cup") + } + } header: { + Text("Critères de recherche") + } + .headerProminence(.increased) + .disabled(searching) + } + + var categoriesLabel: some View { + if tournamentCategories.isEmpty || tournamentCategories.count == TournamentCategory.allCases.count { + Text("Toutes les catégories") + } else { + Text(categories.map({ $0.localizedLabel() }).joined(separator: ", ")) + } + } + + var levelsLabel: some View { + if tournamentLevels.isEmpty || tournamentLevels.count == TournamentLevel.allCases.count { + Text("Tous les niveaux") + } else { + Text(levels.map({ $0.localizedLabel() }).joined(separator: ", ")) + } + } + + @ViewBuilder + var searchParametersSummaryView: some View { + VStack(alignment: .leading) { + HStack { + Text("Lieu") + Spacer() + Text(city) + if distance >= 3000 { + Text("sans limite de distance") + } else { + Text("à moins de " + distanceLimit.formatted()) + } + } + HStack { + Text("Période") + Spacer() + Text("Du") + Text(startDate.twoDigitsYearFormatted) + Text("Au") + Text(endDate.twoDigitsYearFormatted) + } + HStack { + Text("Niveau") + Spacer() + levelsLabel + } + HStack { + Text("Catégorie") + Spacer() + categoriesLabel + } + + HStack { + Text("Tri") + Spacer() + Text(sortingOptionLabel) + } + } + } + + var sortingOptionLabel: String { + switch sortingOption { + case "_DIST_": return "Distance" + case "dateDebut+asc": return "Date de début" + case "dateFin+asc": return "Date de fin" + default: + return "Distance" + } + } +} diff --git a/PadelClub/Views/Navigation/Agenda/TournamentSubscriptionView.swift b/PadelClub/Views/Navigation/Agenda/TournamentSubscriptionView.swift new file mode 100644 index 0000000..41e586e --- /dev/null +++ b/PadelClub/Views/Navigation/Agenda/TournamentSubscriptionView.swift @@ -0,0 +1,232 @@ +// +// TournamentSubscriptionView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 09/09/2024. +// + +import SwiftUI + +struct TournamentSubscriptionView: View { + @EnvironmentObject var networkMonitor: NetworkMonitor + + let federalTournament: FederalTournament + let build: any TournamentBuildHolder + let user: User + + @State private var selectedPlayers: [ImportedPlayer] + @State private var contactType: ContactType? = nil + @State private var sentError: ContactManagerError? = nil + + init(federalTournament: FederalTournament, build: any TournamentBuildHolder, user: User) { + self.federalTournament = federalTournament + self.build = build + self.user = user + _selectedPlayers = .init(wrappedValue: [user.currentPlayerData()].compactMap({ $0 })) + } + + var body: some View { + List { + Section { + LabeledContent("Tournoi") { + Text(federalTournament.libelle ?? "Tournoi") + } + LabeledContent("Club") { + Text(federalTournament.clubLabel()) + } + LabeledContent("Épreuve") { + Text(build.buildHolderTitle()) + } + + LabeledContent("JAP") { + Text(federalTournament.umpireLabel()) + } + LabeledContent("Mail") { + Text(federalTournament.mailLabel()) + } + LabeledContent("Téléphone") { + Text(federalTournament.phoneLabel()) + } + } header: { + Text("Informations") + } + + Section { + ForEach(selectedPlayers) { teamPlayer in + NavigationLink { + SelectablePlayerListView(allowSelection: 1, playerSelectionAction: { players in + if let player = players.first { + selectedPlayers.remove(elements: [teamPlayer]) + selectedPlayers.append(player) + } + }) + } label: { + ImportedPlayerView(player: teamPlayer) + } + } + + if selectedPlayers.count < 2 { + NavigationLink { + SelectablePlayerListView(allowSelection: 1, playerSelectionAction: { players in + if let player = players.first { + selectedPlayers.append(player) + } + }) + } label: { + Text("Choisir un partenaire") + } + } + } header: { + if selectedPlayers.isEmpty == false { + HStack { + Text("Poids de l'équipe") + Spacer() + Text(selectedPlayers.map { $0.rank }.reduce(0, +).formatted()) + } + } + } + + if let courrielEngagement = federalTournament.courrielEngagement { + Section { + RowButtonView("S'inscrire par email") { + contactType = .mail(date: nil, recipients: [courrielEngagement], bccRecipients: nil, body: messageBody, subject: messageSubject, tournamentBuild: build as? TournamentBuild) + } + } + } + + if let installation = federalTournament.installation, let telephone = installation.telephone { + if telephone.isMobileNumber() { + Section { + RowButtonView("S'inscrire par message") { + contactType = .message(date: nil, recipients: [telephone], body: messageBodyShort, tournamentBuild: build as? TournamentBuild) + } + } + } + let number = telephone.replacingOccurrences(of: " ", with: "") + if let url = URL(string: "tel:\(number)") { + Link(destination: url) { + Label("Appeler", systemImage: "phone") + } + } + + Section { + Text(messageBody) + } header: { + Text("Message preparé par Padel Club") + } footer: { + CopyPasteButtonView(pasteValue: messageBody) + } + } + + } + .toolbar(content: { + Menu { + Link(destination: URL(string:"https://tenup.fft.fr/tournoi/\(federalTournament.id)")!) { + Label("Voir sur Tenup", systemImage: "tennisball") + } + ShareLink(item: federalTournament.shareMessage) { + Label("Partager les infos", systemImage: "info") + } + } label: { + LabelOptions() + } + }) + .alert("Un problème est survenu", isPresented: messageSentFailed) { + Button("OK") { + } + } message: { + Text(_networkErrorMessage) + } + .sheet(item: $contactType) { contactType in + Group { + switch contactType { + case .message(_, let recipients, let body, _): + MessageComposeView(recipients: recipients, body: body) { result in + switch result { + case .cancelled: + break + case .failed: + self.sentError = .messageFailed + case .sent: + if networkMonitor.connected == false { + self.sentError = .messageNotSent + } + @unknown default: + break + } + } + case .mail(_, let recipients, let bccRecipients, let body, let subject, _): + MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in + switch result { + case .cancelled, .saved: + self.contactType = nil + case .failed: + self.contactType = nil + self.sentError = .mailFailed + case .sent: + if networkMonitor.connected == false { + self.contactType = nil + self.sentError = .mailNotSent + } + @unknown default: + break + } + } + } + } + .tint(.master) + } + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(.visible, for: .navigationBar) + .navigationTitle("Détail du tournoi") + } + + var teamsString: String { + selectedPlayers.map { $0.pasteData() }.joined(separator: "\n") + } + + var messageBody: String { + let bonjourOuBonsoir = Date().timeOfDay.hello + let bonneSoireeOuBonneJournee = Date().timeOfDay.goodbye + let body = [["\(bonjourOuBonsoir),\n\nJe souhaiterais inscrire mon équipe au tournoi : ", build.buildHolderTitle(), "du", federalTournament.computedStartDate, "au", federalTournament.clubLabel() + ".\n"].compacted().joined(separator: " "), teamsString, "\nCordialement,\n", user.fullName() ?? bonneSoireeOuBonneJournee, "----------------------------------\nCe message a été préparé grâce à l'application Padel Club !\nVotre tournoi n'est pas encore dessus ? \(URLs.main.rawValue)", "Téléchargez l'app : \(URLs.appStore.rawValue)", "En savoir plus : \(URLs.appDescription.rawValue)"].compactMap { $0 }.joined(separator: "\n") + "\n" + return body + } + + var messageBodyShort: String { + let body = [[build.buildHolderTitle(), federalTournament.clubLabel()].compacted().joined(separator: " "), federalTournament.computedStartDate, teamsString].compacted().joined(separator: "\n") + "\n" + return body + } + + var messageSubject: String { + let subject = [build.buildHolderTitle(), federalTournament.clubLabel()].compacted().joined(separator: " ") + return subject + } + + var messageSentFailed: Binding { + Binding { + sentError != nil + } set: { newValue in + if newValue == false { + sentError = nil + } + } + } + + private var _networkErrorMessage: String { + var errors: [String] = [] + + if networkMonitor.connected == false { + errors.append("L'appareil n'est pas connecté à internet.") + } + if sentError == .mailNotSent { + errors.append("Le mail est dans la boîte d'envoi de l'app Mail. Vérifiez son état dans l'app Mail avant d'essayer de le renvoyer.") + } + if (sentError == .messageFailed || sentError == .messageNotSent) { + errors.append("Le SMS n'a pas été envoyé") + } + if sentError == .mailFailed { + errors.append("Le mail n'a pas été envoyé") + } + return errors.joined(separator: "\n") + } +} diff --git a/PadelClub/Views/Round/LoserRoundSettingsView.swift b/PadelClub/Views/Round/LoserRoundSettingsView.swift index b8e9ba9..2e24481 100644 --- a/PadelClub/Views/Round/LoserRoundSettingsView.swift +++ b/PadelClub/Views/Round/LoserRoundSettingsView.swift @@ -16,11 +16,31 @@ struct LoserRoundSettingsView: View { var body: some View { List { + Section { + RowButtonView(isEditingTournamentSeed.wrappedValue == true ? "Terminer l'édition" : "Éditer les tours joués") { + isEditingTournamentSeed.wrappedValue.toggle() + } + } + + Section { + RowButtonView("Synchroniser les noms des matchs") { + let allRoundMatches = upperBracketRound.loserRounds.flatMap({ $0.allMatches + }) + allRoundMatches.forEach({ $0.name = $0.roundTitle() }) + do { + try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: allRoundMatches) + } catch { + Logger.error(error) + } + } + } + Section { RowButtonView("Effacer les matchs de classements", role: .destructive) { upperBracketRound.round.deleteLoserBracket() } } + .disabled(upperBracketRound.round.loserRounds().isEmpty) Section { RowButtonView("Créer les matchs de classements", role: .destructive) { @@ -30,12 +50,7 @@ struct LoserRoundSettingsView: View { } } } - - Section { - RowButtonView(isEditingTournamentSeed.wrappedValue == true ? "Terminer l'édition" : "Éditer les tours joués") { - isEditingTournamentSeed.wrappedValue.toggle() - } - } + .disabled(upperBracketRound.round.loserRounds().isEmpty == false) //todo proposer ici l'impression des matchs de classements peut-être? } diff --git a/PadelClub/Views/Round/LoserRoundView.swift b/PadelClub/Views/Round/LoserRoundView.swift index 017db3d..eb7b2fa 100644 --- a/PadelClub/Views/Round/LoserRoundView.swift +++ b/PadelClub/Views/Round/LoserRoundView.swift @@ -53,13 +53,13 @@ struct LoserRoundView: View { if isEditingTournamentSeed.wrappedValue == true { RowButtonView(match.disabled ? "Jouer ce match" : "Ne pas jouer ce match", role: .destructive) { - match._toggleMatchDisableState(!match.disabled) + match._toggleMatchDisableState(!match.disabled, single: true) } } } } header: { HStack { - if let seedInterval = loserRound.seedInterval() { + if let seedInterval = loserRound.seedInterval(initialMode: isEditingTournamentSeed.wrappedValue == true) { Text(seedInterval.localizedLabel(.wide)) let seedIntervalPointRange = seedInterval.pointsRange(tournamentLevel: tournament.tournamentLevel, teamsCount: tournament.teamCount) Spacer() @@ -67,13 +67,13 @@ struct LoserRoundView: View { .font(.caption) } else { if let previousRound = loserRound.previousRound() { - if let seedInterval = previousRound.seedInterval() { + if let seedInterval = previousRound.seedInterval(initialMode: isEditingTournamentSeed.wrappedValue == true) { Text(seedInterval.localizedLabel()) } else { Text("no previous round") } } else if let parentRound = loserRound.parentRound { - if let seedInterval = parentRound.seedInterval() { + if let seedInterval = parentRound.seedInterval(initialMode: isEditingTournamentSeed.wrappedValue == true) { Text(seedInterval.localizedLabel()) } else { Text("no parent round") diff --git a/PadelClub/Views/Round/LoserRoundsView.swift b/PadelClub/Views/Round/LoserRoundsView.swift index 4e583c3..f1ac8bb 100644 --- a/PadelClub/Views/Round/LoserRoundsView.swift +++ b/PadelClub/Views/Round/LoserRoundsView.swift @@ -167,6 +167,10 @@ struct LoserRoundsView: View { init(upperBracketRound: UpperRound) { self.upperBracketRound = upperBracketRound _selectedRound = State(wrappedValue: upperBracketRound.loserRounds.first(where: { $0.rounds.anySatisfy({ $0.getActiveLoserRound() != nil }) }) ?? upperBracketRound.loserRounds.first(where: { $0.shouldBeDisplayed })) + + if upperBracketRound.loserRounds.allSatisfy({ $0.shouldBeDisplayed == false }) { + _isEditingTournamentSeed = .init(wrappedValue: true) + } } var destinations: [LoserRound] { diff --git a/PadelClub/Views/Round/RoundSettingsView.swift b/PadelClub/Views/Round/RoundSettingsView.swift index ee049c7..6efa24b 100644 --- a/PadelClub/Views/Round/RoundSettingsView.swift +++ b/PadelClub/Views/Round/RoundSettingsView.swift @@ -92,7 +92,7 @@ struct RoundSettingsView: View { Section { let roundIndex = tournament.rounds().count - RowButtonView("Ajouter " + RoundRule.roundName(fromRoundIndex: roundIndex)) { + RowButtonView("Ajouter " + RoundRule.roundName(fromRoundIndex: roundIndex), role: .destructive) { let round = Round(tournament: tournament.id, index: roundIndex, matchFormat: tournament.matchFormat) let matchCount = RoundRule.numberOfMatches(forRoundIndex: roundIndex) let matchStartIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex) @@ -132,7 +132,8 @@ struct RoundSettingsView: View { Logger.error(error) } round.buildLoserBracket() - matches.filter { $0.disabled }.forEach { $0._toggleLoserMatchDisableState(true) + matches.filter { $0.disabled }.forEach { + $0._toggleLoserMatchDisableState(true) } } } @@ -153,6 +154,18 @@ struct RoundSettingsView: View { } } } + + Section { + RowButtonView("Synchroniser les noms des matchs") { + let allRoundMatches = tournament.allRoundMatches() + allRoundMatches.forEach({ $0.name = $0.roundTitle() }) + do { + try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: allRoundMatches) + } catch { + Logger.error(error) + } + } + } } .toolbar { ToolbarItem(placement: .topBarTrailing) { diff --git a/PadelClub/Views/Round/RoundView.swift b/PadelClub/Views/Round/RoundView.swift index 3e52112..12bda95 100644 --- a/PadelClub/Views/Round/RoundView.swift +++ b/PadelClub/Views/Round/RoundView.swift @@ -74,15 +74,17 @@ struct RoundView: View { let bracketTip = BracketEditTip(nextRoundName: upperRound.round.nextRound()?.roundTitle()) TipView(bracketTip).tipStyle(tint: .green, asSection: true) - Section { - let leftToPlay = (RoundRule.numberOfMatches(forRoundIndex: upperRound.round.index) - disabledMatchesCount) - LabeledContent { - Text(leftToPlay.formatted()) - } label: { - Text("Match\(leftToPlay.pluralSuffix) à jouer \(upperRound.title)") + if upperRound.round.hasStarted() == false { + Section { + let leftToPlay = (RoundRule.numberOfMatches(forRoundIndex: upperRound.round.index) - disabledMatchesCount) + LabeledContent { + Text(leftToPlay.formatted()) + } label: { + Text("Match\(leftToPlay.pluralSuffix) à jouer \(upperRound.title)") + } + } footer: { + Text("\(disabledMatchesCount) match\(disabledMatchesCount.pluralSuffix) désactivé\(disabledMatchesCount.pluralSuffix) automatiquement") } - } footer: { - Text("\(disabledMatchesCount) match\(disabledMatchesCount.pluralSuffix) désactivé\(disabledMatchesCount.pluralSuffix) automatiquement") } } diff --git a/PadelClub/Views/Shared/TournamentFilterView.swift b/PadelClub/Views/Shared/TournamentFilterView.swift index d9bcb65..9d0a2c3 100644 --- a/PadelClub/Views/Shared/TournamentFilterView.swift +++ b/PadelClub/Views/Shared/TournamentFilterView.swift @@ -9,12 +9,13 @@ import SwiftUI struct TournamentFilterView: View { @EnvironmentObject var dataStore: DataStore + @Environment(NavigationViewModel.self) private var navigation @Environment(\.dismiss) private var dismiss @State private var levels: Set @State private var categories: Set @State private var ageCategories: Set @State private var selectedClubs: Set - var federalDataViewModel: FederalDataViewModel + @State private var federalDataViewModel: FederalDataViewModel init(federalDataViewModel: FederalDataViewModel) { self.federalDataViewModel = federalDataViewModel @@ -27,30 +28,26 @@ struct TournamentFilterView: View { var body: some View { NavigationView { Form { - let clubs : [Club] = dataStore.user.clubsObjects() - if clubs.filter({ $0.code != nil }).isEmpty == false { - Section { - ForEach(clubs.filter({ $0.code != nil })) { club in - LabeledContent { - Button { - if selectedClubs.contains(club.code!) { - selectedClubs.remove(club.code!) - } else { - selectedClubs.insert(club.code!) - } - } label: { - if selectedClubs.contains(club.code!) { - Image(systemName: "checkmark.circle.fill") - } - } - } label: { - Text(club.clubTitle()) - } + + Section { + Picker(selection: $federalDataViewModel.dayDuration) { + Text("aucune").tag(nil as Int?) + Text(1.formatted()).tag(1 as Int?) + Text(2.formatted()).tag(2 as Int?) + Text(3.formatted()).tag(3 as Int?) + } label: { + Text("Durée max (en jours)") + } + + Picker(selection: $federalDataViewModel.dayPeriod) { + ForEach(DayPeriod.allCases) { + Text($0.localizedDayPeriodLabel()).tag($0) } - } header: { - Text("Clubs") + } label: { + Text("En semaine ou week-end") } } + Section { ForEach(TournamentLevel.allCases) { level in LabeledContent { @@ -74,7 +71,7 @@ struct TournamentFilterView: View { } Section { - ForEach(TournamentCategory.allCases) { category in + ForEach([TournamentCategory.men, TournamentCategory.women, TournamentCategory.mix]) { category in LabeledContent { Button { if categories.contains(category) { @@ -88,7 +85,7 @@ struct TournamentFilterView: View { } } } label: { - Text(category.localizedLabel(.title)) + Text(category.localizedLabel(.wide)) } } } header: { @@ -116,6 +113,58 @@ struct TournamentFilterView: View { } header: { Text("Catégories d'âge") } + + if navigation.agendaDestination == .around { + let clubs : [FederalClub] = federalDataViewModel.searchedClubs + if clubs.isEmpty == false { + Section { + ForEach(clubs) { club in + LabeledContent { + Button { + if selectedClubs.contains(club.federalClubCode) { + selectedClubs.remove(club.federalClubCode) + } else { + selectedClubs.insert(club.federalClubCode) + } + } label: { + if selectedClubs.contains(club.federalClubCode) { + Image(systemName: "checkmark.circle.fill") + } + } + } label: { + Text(club.federalClubName) + } + } + } header: { + Text("Clubs") + } + } + } else { + let clubs : [Club] = dataStore.user.clubsObjects().filter({ $0.code != nil }) + if clubs.isEmpty == false { + Section { + ForEach(clubs) { club in + LabeledContent { + Button { + if selectedClubs.contains(club.code!) { + selectedClubs.remove(club.code!) + } else { + selectedClubs.insert(club.code!) + } + } label: { + if selectedClubs.contains(club.code!) { + Image(systemName: "checkmark.circle.fill") + } + } + } label: { + Text(club.clubTitle()) + } + } + } header: { + Text("Clubs") + } + } + } } .toolbar { ToolbarItem(placement: .topBarLeading) { diff --git a/PadelClub/Views/Team/EditingTeamView.swift b/PadelClub/Views/Team/EditingTeamView.swift index 4bb148b..5a03ef6 100644 --- a/PadelClub/Views/Team/EditingTeamView.swift +++ b/PadelClub/Views/Team/EditingTeamView.swift @@ -81,6 +81,7 @@ struct EditingTeamView: View { Text("Confirmation reçue") Text("L'équipe vous a confirmé votre convocation") } + } else { Text("Cette équipe n'a pas été convoquée") } diff --git a/PadelClub/Views/Team/TeamPickerView.swift b/PadelClub/Views/Team/TeamPickerView.swift index 4eb1980..a9b143c 100644 --- a/PadelClub/Views/Team/TeamPickerView.swift +++ b/PadelClub/Views/Team/TeamPickerView.swift @@ -14,8 +14,11 @@ struct TeamPickerView: View { @State private var confirmTeam: TeamRegistration? @State private var presentTeamPickerView: Bool = false @State private var searchField: String = "" + @State private var sortOrder: SortOrder = .ascending + var shouldConfirm: Bool = false var groupStagePosition: Int? = nil + var matchTypeContext: MatchType = .bracket var luckyLosers: [TeamRegistration] = [] let teamPicked: ((TeamRegistration) -> (Void)) @@ -43,40 +46,20 @@ struct TeamPickerView: View { Text("Même ligne en poule") } } - let teams = tournament.selectedSortedTeams() - if luckyLosers.isEmpty == false { - Section { - _teamListView(luckyLosers.sorted(by: \.weight)) - } header: { - Text("Repêchage") - } - } + _sectionView(luckyLosers.sorted(by: \.weight, order: sortOrder), title: "Repêchage") let qualified = tournament.availableQualifiedTeams() - if qualified.isEmpty == false { - Section { - _teamListView(qualified.sorted(by: \.weight)) - } header: { - Text("Qualifiées entrants") - } - } + _sectionView(qualified.sorted(by: \.weight, order: sortOrder), title: "Qualifiées entrants") + - Section { - _teamListView(teams.filter({ $0.availableForSeedPick() }).sorted(by: \.weight).reversed()) - } header: { - Text("Disponible") - } - Section { - _teamListView(teams.filter({ $0.inGroupStage() }).sorted(by: \.groupStagePosition!).reversed()) - } header: { - Text("Déjà placée en poule") - } - Section { - _teamListView(teams.filter({ $0.inRound() }).sorted(by: \.bracketPosition!).reversed()) - } header: { - Text("Déjà placée dans le tableau") + let teams = tournament.selectedSortedTeams() + if matchTypeContext == .loserBracket { + _sectionView(teams.filter({ $0.inGroupStage() && $0.qualified == false }).sorted(by: \.weight, order: sortOrder), title: "Non qualifié de poules") } - + + _sectionView(teams.filter({ $0.availableForSeedPick() }).sorted(by: \.weight, order: sortOrder), title: "Disponible") + _sectionView(teams.filter({ $0.inGroupStage() }).sorted(by: \.weight, order: sortOrder), title: "Déjà placée en poule") + _sectionView(teams.filter({ $0.inRound() }).sorted(by: \.weight, order: sortOrder), title: "Déjà placée dans le tableau") } .searchable(text: $searchField, placement: .navigationBarDrawer(displayMode: .always)) .keyboardType(.alphabet) @@ -84,11 +67,51 @@ struct TeamPickerView: View { .navigationTitle("Choisir une équipe") .toolbarBackground(.visible, for: .navigationBar) .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .topBarLeading) { + Button("Annuler", role: .cancel) { + presentTeamPickerView = false + } + } + ToolbarItem(placement: .topBarTrailing) { + Menu { + Section { + Picker(selection: $sortOrder) { + Label("Trier les équipes par poids croissant", systemImage: "chevron.up").tag(SortOrder.ascending) + .labelStyle(.titleAndIcon) + Label("Trier les équipes par poids décroissant", systemImage: "chevron.down").tag(SortOrder.descending) + .labelStyle(.titleAndIcon) + } label: { + Text("Trier les équipes par poids") + } + .pickerStyle(.inline) + } header: { + Text("Trier les équipes par poids") + } + } label: { + HStack { + Text("Poids") + Image(systemName: sortOrder == .ascending ? "chevron.up" : "chevron.down") + } + } + } + } } .tint(.master) } } + @ViewBuilder + private func _sectionView(_ teams: [TeamRegistration], title: String) -> some View { + if teams.isEmpty == false { + Section { + _teamListView(teams) + } header: { + Text(title) + } + } + } + private func _teamListView(_ teams: [TeamRegistration]) -> some View { ForEach(teams) { team in if searchField.isEmpty || team.contains(searchField) { diff --git a/PadelClub/Views/Team/TeamRowView.swift b/PadelClub/Views/Team/TeamRowView.swift index 0b3550d..533d4bc 100644 --- a/PadelClub/Views/Team/TeamRowView.swift +++ b/PadelClub/Views/Team/TeamRowView.swift @@ -21,6 +21,17 @@ struct TeamRowView: View { Text(name).foregroundStyle(.secondary) } + if let groupStage = team.groupStageObject() { + HStack { + Text(groupStage.groupStageTitle()) + if let finalPosition = groupStage.finalPosition(ofTeam: team) { + Text((finalPosition + 1).ordinalFormatted()) + } + } + } else if let round = team.initialRound() { + Text(round.roundTitle(.wide)) + } + if team.players().isEmpty == false { ForEach(team.players()) { player in Text(player.playerLabel()) diff --git a/PadelClub/Views/Tournament/Screen/TournamentRankView.swift b/PadelClub/Views/Tournament/Screen/TournamentRankView.swift index 88b0031..baf9600 100644 --- a/PadelClub/Views/Tournament/Screen/TournamentRankView.swift +++ b/PadelClub/Views/Tournament/Screen/TournamentRankView.swift @@ -106,6 +106,7 @@ struct TournamentRankView: View { } } } + .id(calculating) .alert("Position", isPresented: isEditingTeam) { if let selectedTeam { @Bindable var team = selectedTeam @@ -154,6 +155,7 @@ struct TournamentRankView: View { } struct TeamRankCellView: View { + @EnvironmentObject var dataStore: DataStore @Environment(\.editMode) private var editMode @Environment(Tournament.self) var tournament: Tournament @State private var isEditingTeam: Bool = false @@ -192,26 +194,37 @@ struct TournamentRankView: View { .fontWeight(.bold) Text(key.ordinalFormattedSuffix()).font(.caption) } + if let index = tournament.indexOf(team: team) { - let rankingDifference = index - (key - 1) - if rankingDifference > 0 { - HStack(spacing: 0.0) { - Text(rankingDifference.formatted(.number.sign(strategy: .always()))) - .monospacedDigit() - Image(systemName: "arrowtriangle.up.fill") - .imageScale(.small) - } - .foregroundColor(.green) - } else if rankingDifference < 0 { + ZStack { HStack(spacing: 0.0) { - Text(rankingDifference.formatted(.number.sign(strategy: .always()))) + Text(tournament.teamCount.formatted(.number.sign(strategy: .always()))) .monospacedDigit() Image(systemName: "arrowtriangle.down.fill") .imageScale(.small) } - .foregroundColor(.logoRed) - } else { - Text("--") + .opacity(0) + + let rankingDifference = index - (key - 1) + if rankingDifference > 0 { + HStack(spacing: 0.0) { + Text(rankingDifference.formatted(.number.sign(strategy: .always()))) + .monospacedDigit() + Image(systemName: "arrowtriangle.up.fill") + .imageScale(.small) + } + .foregroundColor(.green) + } else if rankingDifference < 0 { + HStack(spacing: 0.0) { + Text(rankingDifference.formatted(.number.sign(strategy: .always()))) + .monospacedDigit() + Image(systemName: "arrowtriangle.down.fill") + .imageScale(.small) + } + .foregroundColor(.logoRed) + } else { + Text("--") + } } } } @@ -295,6 +308,7 @@ struct TournamentRankView: View { calculating = true } + self.rankings.removeAll() let finalRanks = await tournament.finalRanking() finalRanks.keys.sorted().forEach { rank in if let rankedTeamIds = finalRanks[rank] { diff --git a/PadelClub/Views/Tournament/Shared/TournamentCellView.swift b/PadelClub/Views/Tournament/Shared/TournamentCellView.swift index 5014e02..1e9ab62 100644 --- a/PadelClub/Views/Tournament/Shared/TournamentCellView.swift +++ b/PadelClub/Views/Tournament/Shared/TournamentCellView.swift @@ -23,7 +23,15 @@ struct TournamentCellView: View { var body: some View { ForEach(tournament.tournaments, id: \.id) { build in - _buildView(build, existingTournament: event?.existingBuild(build)) + if navigation.agendaDestination == .around, let federalTournament = tournament as? FederalTournament { + NavigationLink { + TournamentSubscriptionView(federalTournament: federalTournament, build: build, user: dataStore.user) + } label: { + _buildView(build, existingTournament: event?.existingBuild(build)) + } + } else { + _buildView(build, existingTournament: event?.existingBuild(build)) + } } } @@ -98,7 +106,7 @@ struct TournamentCellView: View { } else if let teamCount { Text(teamCount.formatted()) } - } else if let federalTournament = tournament as? FederalTournament { + } else if let federalTournament = tournament as? FederalTournament, navigation.agendaDestination != .around { Button { _createOrShow(federalTournament: federalTournament, existingTournament: existingTournament, build: build) } label: { diff --git a/PadelClub/Views/Tournament/TournamentInitView.swift b/PadelClub/Views/Tournament/TournamentInitView.swift index 25fd1dd..969f6ff 100644 --- a/PadelClub/Views/Tournament/TournamentInitView.swift +++ b/PadelClub/Views/Tournament/TournamentInitView.swift @@ -22,7 +22,12 @@ struct TournamentInitView: View { LabeledContent { Text(tournaments.count.formatted() + " tournoi" + tournaments.count.pluralSuffix) } label: { - Text("Gestion de l'événement") + Text("Réglages de l'événement") + if let eventName = event.name, eventName.isEmpty == false { + Text(eventName).foregroundStyle(.secondary) + } else { + Text("Aucune description").foregroundStyle(.secondary) + } } } } diff --git a/PadelClub/Views/Tournament/TournamentRunningView.swift b/PadelClub/Views/Tournament/TournamentRunningView.swift index 4763306..626a82e 100644 --- a/PadelClub/Views/Tournament/TournamentRunningView.swift +++ b/PadelClub/Views/Tournament/TournamentRunningView.swift @@ -21,7 +21,8 @@ struct TournamentRunningView: View { MatchListView(section: "en cours", matches: tournament.runningMatches(allMatches), hideWhenEmpty: tournament.hasEnded()) // MatchListView(section: "à lancer", matches: tournament.readyMatches(allMatches), isExpanded: false) // MatchListView(section: "disponible", matches: tournament.availableToStart(allMatches), isExpanded: false) - MatchListView(section: "terminés", matches: tournament.finishedMatches(allMatches), isExpanded: tournament.hasEnded()) + let finishedMatches = tournament.finishedMatches(allMatches, limit: tournament.courtCount) + MatchListView(section: "Dernier\(finishedMatches.count.pluralSuffix) match\(finishedMatches.count.pluralSuffix) terminé\(finishedMatches.count.pluralSuffix)", matches: finishedMatches, isExpanded: tournament.hasEnded()) } } diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index fa14f46..7dbe23b 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -131,7 +131,7 @@ struct TournamentView: View { } NavigationLink(value: Screen.event) { - Text("Gestion de l'événement") + Text("Réglages de l'événement") } } @@ -176,7 +176,7 @@ struct TournamentView: View { } NavigationLink(value: Screen.event) { - Text("Gestion de l'événement") + Text("Réglages de l'événement") } NavigationLink(value: Screen.settings) { LabelSettings()