diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index a20085d..676e7c3 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -1909,6 +1909,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 92; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -1939,6 +1940,7 @@ OTHER_SWIFT_FLAGS = "-Onone"; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; @@ -1953,6 +1955,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 92; DEFINES_MODULE = YES; @@ -1981,6 +1984,7 @@ 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; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; diff --git a/PadelClub/Data/GroupStage.swift b/PadelClub/Data/GroupStage.swift index cba7fb4..c172cb3 100644 --- a/PadelClub/Data/GroupStage.swift +++ b/PadelClub/Data/GroupStage.swift @@ -200,7 +200,7 @@ final class GroupStage: ModelObject, Storable { return _matches().first(where: { matchIndexes.contains($0.index) }) } - func availableToStart(playedMatches: [Match], in runningMatches: [Match]) async -> [Match] { + func availableToStart(playedMatches: [Match], in runningMatches: [Match]) -> [Match] { #if DEBUG_TIME //DEBUGING TIME let start = Date() defer { @@ -222,19 +222,7 @@ final class GroupStage: ModelObject, Storable { return playedMatches.filter({ $0.isRunning() }).sorted(by: \.computedStartDateForSorting) } - func asyncRunningMatches(playedMatches: [Match]) async -> [Match] { - #if DEBUG_TIME //DEBUGING TIME - let start = Date() - defer { - let duration = Duration.milliseconds(Date().timeIntervalSince(start) * 1_000) - print("func group stage runningMatches", id, duration.formatted(.units(allowed: [.seconds, .milliseconds]))) - } - #endif - return playedMatches.filter({ $0.isRunning() }).sorted(by: \.computedStartDateForSorting) - } - - - func readyMatches(playedMatches: [Match]) async -> [Match] { + func readyMatches(playedMatches: [Match]) -> [Match] { #if DEBUG_TIME //DEBUGING TIME let start = Date() defer { diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index 96c98e9..7dc156e 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -76,9 +76,9 @@ final class TeamRegistration: ModelObject, Storable { self.tournamentStore.teamScores.deleteDependencies(self.teamScores()) } - func hasArrived() { + func hasArrived(isHere: Bool = false) { let unsortedPlayers = unsortedPlayers() - unsortedPlayers.forEach({ $0.hasArrived = true }) + unsortedPlayers.forEach({ $0.hasArrived = !isHere }) do { try self.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: unsortedPlayers) } catch { @@ -86,6 +86,12 @@ final class TeamRegistration: ModelObject, Storable { } } + func isHere() -> Bool { + let unsortedPlayers = unsortedPlayers() + return unsortedPlayers.allSatisfy({ $0.hasArrived }) + } + + func isSeedable() -> Bool { bracketPosition == nil && groupStage == nil } diff --git a/PadelClub/Views/GroupStage/GroupStageView.swift b/PadelClub/Views/GroupStage/GroupStageView.swift index f8659b1..061f0fb 100644 --- a/PadelClub/Views/GroupStage/GroupStageView.swift +++ b/PadelClub/Views/GroupStage/GroupStageView.swift @@ -20,10 +20,6 @@ struct GroupStageView: View { @State private var confirmResetMatch: Bool = false let playedMatches: [Match] - @State private var runningMatches: [Match]? - @State private var readyMatches: [Match]? - @State private var availableToStart: [Match]? - init(groupStage: GroupStage) { self.groupStage = groupStage self.playedMatches = groupStage.playedMatches() @@ -55,16 +51,14 @@ struct GroupStageView: View { } .headerProminence(.increased) - MatchListView(section: "en cours", matches: runningMatches, hideWhenEmpty: true) + let runningMatches = groupStage.runningMatches(playedMatches: playedMatches) + MatchListView(section: "en cours", matches: groupStage.runningMatches(playedMatches: playedMatches), hideWhenEmpty: true) + let availableToStart = groupStage.availableToStart(playedMatches: playedMatches, in: runningMatches) MatchListView(section: "prêt à démarrer", matches: availableToStart, hideWhenEmpty: true) - MatchListView(section: "à lancer", matches: self.readyMatches, hideWhenEmpty: true) + .listRowView(isActive: availableToStart.isEmpty == false, color: .green, hideColorVariation: true) + MatchListView(section: "à lancer", matches: groupStage.readyMatches(playedMatches: playedMatches), hideWhenEmpty: true) MatchListView(section: "terminés", matches: groupStage.finishedMatches(playedMatches: playedMatches), isExpanded: false) } - .task { - self.runningMatches = await groupStage.asyncRunningMatches(playedMatches: playedMatches) - self.readyMatches = await groupStage.readyMatches(playedMatches: playedMatches) - self.availableToStart = await groupStage.availableToStart(playedMatches: playedMatches, in: runningMatches ?? []) - } .toolbar { ToolbarItem(placement: .topBarTrailing) { _groupStageMenuView() @@ -148,6 +142,11 @@ struct GroupStageView: View { } ForEach(team.players()) { player in Text(player.playerLabel()).lineLimit(1) + .overlay { + if player.hasArrived && team.isHere() == false { + Color.logoYellow.opacity(0.6) + } + } } } Spacer() @@ -175,12 +174,43 @@ struct GroupStageView: View { } } .contextMenu { - Button("équipe présente") { - team.hasArrived() + let teamHasArrived = team.isHere() + Button { + team.hasArrived(isHere: teamHasArrived) + } label: { + if teamHasArrived { + Label("équipe présente", systemImage: "checkmark").foregroundStyle(.green) + } else { + Text("équipe présente") + } + } + + Divider() + + Section { + ForEach(team.players()) { player in + Button { + player.hasArrived.toggle() + do { + try self.tournamentStore.playerRegistrations.addOrUpdate(instance: player) + } catch { + Logger.error(error) + } + } label: { + if player.hasArrived { + Label("\(player.playerLabel())", systemImage: "checkmark") + } else { + Text("\(player.playerLabel())") + } + } + } + } header: { + Text("Joueur présent") } } } .listRowView(isActive: team.qualified, color: .master) + .listRowView(isActive: team.isHere(), color: .green, hideColorVariation: true) } else { VStack(alignment: .leading, spacing: 0) { Text("#\(index + 1)") diff --git a/PadelClub/Views/Navigation/Agenda/ActivityView.swift b/PadelClub/Views/Navigation/Agenda/ActivityView.swift index 3aec543..2e55ce4 100644 --- a/PadelClub/Views/Navigation/Agenda/ActivityView.swift +++ b/PadelClub/Views/Navigation/Agenda/ActivityView.swift @@ -110,12 +110,14 @@ struct ActivityView: View { self.error = nil } } + .padding() } else if isGatheringFederalTournaments { ProgressView() } else { if tournaments.isEmpty && viewStyle == .list { if searchText.isEmpty == false { ContentUnavailableView.search(text: searchText) + .padding() } else if federalDataViewModel.areFiltersEnabled() { ContentUnavailableView { Text("Aucun résultat") @@ -126,8 +128,10 @@ struct ActivityView: View { federalDataViewModel.removeFilters() } } + .padding() } else { _dataEmptyView() + .padding() } } } diff --git a/PadelClub/Views/Round/RoundView.swift b/PadelClub/Views/Round/RoundView.swift index fe80468..acb0c25 100644 --- a/PadelClub/Views/Round/RoundView.swift +++ b/PadelClub/Views/Round/RoundView.swift @@ -157,15 +157,22 @@ struct RoundView: View { } if availableQualifiedTeams.isEmpty == false { - if spaceLeft.isEmpty == false { + let qualifiedOnSeedSpot = (spaceLeft.isEmpty || tournament.seeds().isEmpty) ? true : false + let availableSeedSpot : [any SpinDrawable] = qualifiedOnSeedSpot ? (seedSpaceLeft + spaceLeft).flatMap({ $0.matchSpots() }).filter({ $0.match.team( $0.teamPosition) == nil }) : spaceLeft + if availableSeedSpot.isEmpty == false { Section { DisclosureGroup { ForEach(availableQualifiedTeams) { team in NavigationLink { - SpinDrawView(drawees: [team], segments: spaceLeft) { results in + + SpinDrawView(drawees: [team], segments: availableSeedSpot) { results in Task { results.forEach { drawResult in - team.setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true) + if let matchSpot : MatchSpot = availableSeedSpot[drawResult.drawIndex] as? MatchSpot { + team.setSeedPosition(inSpot: matchSpot.match, slot: matchSpot.teamPosition, opposingSeeding: false) + } else if let matchSpot : Match = availableSeedSpot[drawResult.drawIndex] as? Match { + team.setSeedPosition(inSpot: matchSpot, slot: nil, opposingSeeding: true) + } } _save() if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty { @@ -357,3 +364,31 @@ struct RoundView: View { // RoundView(round: Round.mock()) // .environment(Tournament.mock()) //} + +struct MatchSpot: SpinDrawable { + let match: Match + let teamPosition: TeamPosition + + func segmentLabel(_ displayStyle: DisplayStyle) -> [String] { + [match.roundTitle(), matchTitle(displayStyle: displayStyle)].compactMap { $0 } + } + + func matchTitle(displayStyle: DisplayStyle) -> String { + [match.matchTitle(displayStyle), teamPositionLabel()].joined(separator: " - ") + } + + func teamPositionLabel() -> String { + switch teamPosition { + case .one: + return "haut" + case .two: + return "bas" + } + } +} + +extension Match { + func matchSpots() -> [MatchSpot] { + [MatchSpot(match: self, teamPosition: .one), MatchSpot(match: self, teamPosition: .two)] + } +} diff --git a/PadelClub/Views/ViewModifiers/ListRowViewModifier.swift b/PadelClub/Views/ViewModifiers/ListRowViewModifier.swift index ec9c829..bcd0f36 100644 --- a/PadelClub/Views/ViewModifiers/ListRowViewModifier.swift +++ b/PadelClub/Views/ViewModifiers/ListRowViewModifier.swift @@ -10,12 +10,17 @@ import SwiftUI struct ListRowViewModifier: ViewModifier { let isActive: Bool let color: Color + var hideColorVariation: Bool = false + func colorVariation() -> Color { + hideColorVariation ? Color(uiColor: .systemBackground) : color.variation() + } + func body(content: Content) -> some View { if isActive { content .listRowBackground( - color.variation() + colorVariation() .overlay(alignment: .leading, content: { color.frame(width: 8) }) @@ -27,7 +32,7 @@ struct ListRowViewModifier: ViewModifier { } extension View { - func listRowView(isActive: Bool = false, color: Color) -> some View { - modifier(ListRowViewModifier(isActive: isActive, color: color)) + func listRowView(isActive: Bool = false, color: Color, hideColorVariation: Bool = false) -> some View { + modifier(ListRowViewModifier(isActive: isActive, color: color, hideColorVariation: hideColorVariation)) } }