|
|
|
@ -421,22 +421,14 @@ struct AddTeamView: View { |
|
|
|
return max(boundingRect.height + 20, 40) // Add some padding and set a minimum height |
|
|
|
return max(boundingRect.height + 20, 40) // Add some padding and set a minimum height |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct PasteStringSection: View { |
|
|
|
@ViewBuilder |
|
|
|
|
|
|
|
private func _buildingTeamView() -> some View { |
|
|
|
let pasteString: String? |
|
|
|
|
|
|
|
@Binding var editableTextField: String |
|
|
|
|
|
|
|
@Binding var textHeight: CGFloat |
|
|
|
|
|
|
|
@FocusState var focusedField: AddTeamView.FocusField? |
|
|
|
|
|
|
|
var handlePasteString: (String) -> Void |
|
|
|
|
|
|
|
@Binding var displayWarningNotEnoughCharacter: Bool |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
|
|
|
if let pasteString { |
|
|
|
if let pasteString { |
|
|
|
Section { |
|
|
|
Section { |
|
|
|
TextEditor(text: $editableTextField) |
|
|
|
TextEditor(text: $editableTextField) |
|
|
|
.frame(height: textHeight) |
|
|
|
.frame(height: textHeight) |
|
|
|
.onChange(of: editableTextField) { |
|
|
|
.onChange(of: editableTextField) { |
|
|
|
textHeight = AddTeamView._calculateHeight(text: pasteString) |
|
|
|
textHeight = Self._calculateHeight(text: pasteString) |
|
|
|
} |
|
|
|
} |
|
|
|
.focused($focusedField, equals: .pasteField) |
|
|
|
.focused($focusedField, equals: .pasteField) |
|
|
|
.toolbar { |
|
|
|
.toolbar { |
|
|
|
@ -468,40 +460,89 @@ struct AddTeamView: View { |
|
|
|
FooterButtonView("effacer le texte") { |
|
|
|
FooterButtonView("effacer le texte") { |
|
|
|
self.focusedField = nil |
|
|
|
self.focusedField = nil |
|
|
|
self.editableTextField = "" |
|
|
|
self.editableTextField = "" |
|
|
|
self.handlePasteString("") |
|
|
|
self.pasteString = nil |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Section { |
|
|
|
|
|
|
|
ForEach(createdPlayerIds.sorted(), id: \.self) { id in |
|
|
|
|
|
|
|
if let p = createdPlayers.first(where: { $0.id == id }) { |
|
|
|
|
|
|
|
VStack(alignment: .leading, spacing: 0) { |
|
|
|
|
|
|
|
if let player = unsortedPlayers.first(where: { ($0.licenceId == p.licenceId && $0.licenceId != nil) }), editedTeam?.includes(player: player) == false { |
|
|
|
|
|
|
|
Text("Déjà inscrit !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if tournament.isPlayerAgeInadequate(player: p) { |
|
|
|
|
|
|
|
Text("Âge invalide !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if tournament.isPlayerRankInadequate(player: p) { |
|
|
|
|
|
|
|
Text("Trop bien classé !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
PlayerView(player: p).tag(p.id) |
|
|
|
|
|
|
|
.environment(tournament) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if let p = fetchPlayers.first(where: { $0.license == id }) { |
|
|
|
|
|
|
|
VStack(alignment: .leading, spacing: 0) { |
|
|
|
|
|
|
|
if let pasteString, pasteString.isEmpty == false, unsortedPlayers.first(where: { $0.licenceId == p.license }) != nil { |
|
|
|
|
|
|
|
Text("Déjà inscrit !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if tournament.isPlayerAgeInadequate(player: p) { |
|
|
|
|
|
|
|
Text("Âge invalide !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if tournament.isPlayerRankInadequate(player: p) { |
|
|
|
|
|
|
|
Text("Trop bien classé !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ImportedPlayerView(player: p).tag(p.license!) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if editedTeam == nil { |
|
|
|
|
|
|
|
if createdPlayerIds.isEmpty { |
|
|
|
|
|
|
|
RowButtonView("Bloquer une place") { |
|
|
|
|
|
|
|
_createTeam(checkDuplicates: false, checkHomonym: false) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
RowButtonView("Ajouter l'équipe") { |
|
|
|
|
|
|
|
_createTeam(checkDuplicates: true, checkHomonym: true) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
RowButtonView("Confirmer") { |
|
|
|
|
|
|
|
_updateTeam(checkDuplicates: false) |
|
|
|
|
|
|
|
dismiss() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} header: { |
|
|
|
|
|
|
|
let _currentSelection = _currentSelection() |
|
|
|
|
|
|
|
let selectedSortedTeams = tournament.selectedSortedTeams() |
|
|
|
|
|
|
|
let rank = _currentSelection.map { |
|
|
|
|
|
|
|
$0.computedRank |
|
|
|
|
|
|
|
}.reduce(0, +) |
|
|
|
|
|
|
|
let teamIndex = selectedSortedTeams.firstIndex(where: { $0.weight >= rank }) ?? selectedSortedTeams.count |
|
|
|
|
|
|
|
if _currentSelection.isEmpty == false, tournament.hideWeight() == false, rank > 0 { |
|
|
|
|
|
|
|
HStack(spacing: 16.0) { |
|
|
|
|
|
|
|
VStack(alignment: .leading, spacing: 0) { |
|
|
|
|
|
|
|
Text("Rang").font(.caption) |
|
|
|
|
|
|
|
Text("#" + (teamIndex + 1).formatted()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VStack(alignment: .leading, spacing: 0) { |
|
|
|
|
|
|
|
Text("Poids").font(.caption) |
|
|
|
|
|
|
|
Text(rank.formatted()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Spacer() |
|
|
|
|
|
|
|
VStack(alignment: .trailing, spacing: 0) { |
|
|
|
|
|
|
|
Text("").font(.caption) |
|
|
|
|
|
|
|
Text(tournament.cutLabel(index: teamIndex, teamCount: selectedSortedTeams.count)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// } else { |
|
|
|
|
|
|
|
// Text("Préparation de l'équipe") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ViewBuilder |
|
|
|
|
|
|
|
private func _buildingTeamView() -> some View { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PasteStringSection( |
|
|
|
|
|
|
|
pasteString: pasteString, |
|
|
|
|
|
|
|
editableTextField: $editableTextField, |
|
|
|
|
|
|
|
textHeight: $textHeight, |
|
|
|
|
|
|
|
focusedField: _focusedField, |
|
|
|
|
|
|
|
handlePasteString: handlePasteString, |
|
|
|
|
|
|
|
displayWarningNotEnoughCharacter: $displayWarningNotEnoughCharacter |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TeamSelectionSection( |
|
|
|
|
|
|
|
createdPlayerIds: createdPlayerIds, |
|
|
|
|
|
|
|
createdPlayers: createdPlayers, |
|
|
|
|
|
|
|
unsortedPlayers: unsortedPlayers, |
|
|
|
|
|
|
|
fetchPlayers: fetchPlayers, |
|
|
|
|
|
|
|
editedTeam: editedTeam, |
|
|
|
|
|
|
|
pasteString: pasteString, |
|
|
|
|
|
|
|
tournament: tournament, |
|
|
|
|
|
|
|
_createTeam: _createTeam, |
|
|
|
|
|
|
|
_updateTeam: _updateTeam, |
|
|
|
|
|
|
|
dismiss: dismiss, |
|
|
|
|
|
|
|
_currentSelection: _currentSelection |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let pasteString, pasteString.isEmpty == false { |
|
|
|
if let pasteString, pasteString.isEmpty == false { |
|
|
|
let sortedPlayers = _searchFilteredPlayers() |
|
|
|
let sortedPlayers = _searchFilteredPlayers() |
|
|
|
@ -534,38 +575,6 @@ struct AddTeamView: View { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// if let pasteString, pasteString.isEmpty == false { |
|
|
|
|
|
|
|
// let sortedPlayers = _searchFilteredPlayers() |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// if sortedPlayers.isEmpty { |
|
|
|
|
|
|
|
// ContentUnavailableView { |
|
|
|
|
|
|
|
// Label("Aucun résultat", systemImage: "person.2.slash") |
|
|
|
|
|
|
|
// } description: { |
|
|
|
|
|
|
|
// Text("Aucun joueur classé n'a été trouvé dans ce message. Attention, si un joueur n'a pas joué de tournoi dans les 12 derniers, Padel Club ne pourra pas le trouver.") |
|
|
|
|
|
|
|
// } actions: { |
|
|
|
|
|
|
|
// RowButtonView("Créer un joueur non classé") { |
|
|
|
|
|
|
|
// selectionSearchField = pasteString |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// RowButtonView("Chercher dans la base") { |
|
|
|
|
|
|
|
// presentPlayerSearch = true |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// RowButtonView("Effacer cette recherche") { |
|
|
|
|
|
|
|
// self.pasteString = nil |
|
|
|
|
|
|
|
// self.editableTextField = "" |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// } else { |
|
|
|
|
|
|
|
// _listOfPlayers(searchFilteredPlayers: sortedPlayers, pasteString: pasteString) |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// } else { |
|
|
|
|
|
|
|
// _managementView() |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@MainActor |
|
|
|
@MainActor |
|
|
|
func hitForSearch(_ ip: ImportedPlayer, _ pasteString: String?) -> Int { |
|
|
|
func hitForSearch(_ ip: ImportedPlayer, _ pasteString: String?) -> Int { |
|
|
|
guard let pasteString else { return 0 } |
|
|
|
guard let pasteString else { return 0 } |
|
|
|
@ -642,165 +651,6 @@ struct AddTeamView: View { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct TeamSelectionSection: View { |
|
|
|
|
|
|
|
let createdPlayerIds: Set<String> |
|
|
|
|
|
|
|
let createdPlayers: Set<PlayerRegistration> |
|
|
|
|
|
|
|
let unsortedPlayers: [PlayerRegistration] |
|
|
|
|
|
|
|
let fetchPlayers: FetchedResults<ImportedPlayer> |
|
|
|
|
|
|
|
let editedTeam: TeamRegistration? |
|
|
|
|
|
|
|
let pasteString: String? |
|
|
|
|
|
|
|
let tournament: Tournament |
|
|
|
|
|
|
|
let _createTeam: (Bool, Bool) -> Void |
|
|
|
|
|
|
|
let _updateTeam: (Bool) -> Void |
|
|
|
|
|
|
|
let dismiss: DismissAction |
|
|
|
|
|
|
|
let _currentSelection: () -> Set<PlayerRegistration> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
|
|
|
Section { |
|
|
|
|
|
|
|
PlayerListView(createdPlayerIds: createdPlayerIds, |
|
|
|
|
|
|
|
createdPlayers: createdPlayers, |
|
|
|
|
|
|
|
unsortedPlayers: unsortedPlayers, |
|
|
|
|
|
|
|
fetchPlayers: fetchPlayers, |
|
|
|
|
|
|
|
editedTeam: editedTeam, |
|
|
|
|
|
|
|
pasteString: pasteString, |
|
|
|
|
|
|
|
tournament: tournament) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ActionButton(editedTeam: editedTeam, |
|
|
|
|
|
|
|
createdPlayerIds: createdPlayerIds, |
|
|
|
|
|
|
|
_createTeam: _createTeam, |
|
|
|
|
|
|
|
_updateTeam: _updateTeam, |
|
|
|
|
|
|
|
dismiss: dismiss) |
|
|
|
|
|
|
|
} header: { |
|
|
|
|
|
|
|
TeamHeader(tournament: tournament, |
|
|
|
|
|
|
|
_currentSelection: _currentSelection) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct PlayerListView: View { |
|
|
|
|
|
|
|
let createdPlayerIds: Set<String> |
|
|
|
|
|
|
|
let createdPlayers: Set<PlayerRegistration> |
|
|
|
|
|
|
|
let unsortedPlayers: [PlayerRegistration] |
|
|
|
|
|
|
|
let fetchPlayers: FetchedResults<ImportedPlayer> |
|
|
|
|
|
|
|
let editedTeam: TeamRegistration? |
|
|
|
|
|
|
|
let pasteString: String? |
|
|
|
|
|
|
|
let tournament: Tournament |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
|
|
|
ForEach(createdPlayerIds.sorted(), id: \.self) { id in |
|
|
|
|
|
|
|
if let p = createdPlayers.first(where: { $0.id == id }) { |
|
|
|
|
|
|
|
CreatedPlayerView(player: p, unsortedPlayers: unsortedPlayers, editedTeam: editedTeam, tournament: tournament) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if let p = fetchPlayers.first(where: { $0.license == id }) { |
|
|
|
|
|
|
|
FetchedPlayerView(player: p, unsortedPlayers: unsortedPlayers, pasteString: pasteString, tournament: tournament) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct CreatedPlayerView: View { |
|
|
|
|
|
|
|
let player: PlayerRegistration |
|
|
|
|
|
|
|
let unsortedPlayers: [PlayerRegistration] |
|
|
|
|
|
|
|
let editedTeam: TeamRegistration? |
|
|
|
|
|
|
|
let tournament: Tournament |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
|
|
|
VStack(alignment: .leading, spacing: 0) { |
|
|
|
|
|
|
|
if let existingPlayer = unsortedPlayers.first(where: { ($0.licenceId == player.licenceId && $0.licenceId != nil) }), editedTeam?.includes(player: existingPlayer) == false { |
|
|
|
|
|
|
|
Text("Déjà inscrit !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if tournament.isPlayerAgeInadequate(player: player) { |
|
|
|
|
|
|
|
Text("Âge invalide !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if tournament.isPlayerRankInadequate(player: player) { |
|
|
|
|
|
|
|
Text("Trop bien classé !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
PlayerView(player: player).tag(player.id) |
|
|
|
|
|
|
|
.environment(tournament) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct FetchedPlayerView: View { |
|
|
|
|
|
|
|
let player: ImportedPlayer |
|
|
|
|
|
|
|
let unsortedPlayers: [PlayerRegistration] |
|
|
|
|
|
|
|
let pasteString: String? |
|
|
|
|
|
|
|
let tournament: Tournament |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
|
|
|
VStack(alignment: .leading, spacing: 0) { |
|
|
|
|
|
|
|
if let pasteString, pasteString.isEmpty == false, unsortedPlayers.first(where: { $0.licenceId == player.license }) != nil { |
|
|
|
|
|
|
|
Text("Déjà inscrit !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if tournament.isPlayerAgeInadequate(player: player) { |
|
|
|
|
|
|
|
Text("Âge invalide !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if tournament.isPlayerRankInadequate(player: player) { |
|
|
|
|
|
|
|
Text("Trop bien classé !").foregroundStyle(.logoRed).bold() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ImportedPlayerView(player: player).tag(player.license!) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ActionButton: View { |
|
|
|
|
|
|
|
let editedTeam: TeamRegistration? |
|
|
|
|
|
|
|
let createdPlayerIds: Set<String> |
|
|
|
|
|
|
|
let _createTeam: (Bool, Bool) -> Void |
|
|
|
|
|
|
|
let _updateTeam: (Bool) -> Void |
|
|
|
|
|
|
|
let dismiss: DismissAction |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
|
|
|
if editedTeam == nil { |
|
|
|
|
|
|
|
if createdPlayerIds.isEmpty { |
|
|
|
|
|
|
|
RowButtonView("Bloquer une place") { |
|
|
|
|
|
|
|
_createTeam(false, false) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
RowButtonView("Ajouter l'équipe") { |
|
|
|
|
|
|
|
_createTeam(true, true) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
RowButtonView("Confirmer") { |
|
|
|
|
|
|
|
_updateTeam(false) |
|
|
|
|
|
|
|
dismiss() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct TeamHeader: View { |
|
|
|
|
|
|
|
let tournament: Tournament |
|
|
|
|
|
|
|
let _currentSelection: () -> Set<PlayerRegistration> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
|
|
|
let currentSelection = _currentSelection() |
|
|
|
|
|
|
|
let selectedSortedTeams = tournament.selectedSortedTeams() |
|
|
|
|
|
|
|
let rank = currentSelection.map { $0.computedRank }.reduce(0, +) |
|
|
|
|
|
|
|
let teamIndex = selectedSortedTeams.firstIndex(where: { $0.weight >= rank }) ?? selectedSortedTeams.count |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if !currentSelection.isEmpty, !tournament.hideWeight(), rank > 0 { |
|
|
|
|
|
|
|
HStack(spacing: 16.0) { |
|
|
|
|
|
|
|
VStack(alignment: .leading, spacing: 0) { |
|
|
|
|
|
|
|
Text("Rang").font(.caption) |
|
|
|
|
|
|
|
Text("#" + (teamIndex + 1).formatted()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VStack(alignment: .leading, spacing: 0) { |
|
|
|
|
|
|
|
Text("Poids").font(.caption) |
|
|
|
|
|
|
|
Text(rank.formatted()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Spacer() |
|
|
|
|
|
|
|
VStack(alignment: .trailing, spacing: 0) { |
|
|
|
|
|
|
|
Text("").font(.caption) |
|
|
|
|
|
|
|
Text(tournament.cutLabel(index: teamIndex, teamCount: selectedSortedTeams.count)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let testMessages = [ |
|
|
|
let testMessages = [ |
|
|
|
"Anthony dovetta ( 3620578 K )et christophe capeau ( 4666443v)", |
|
|
|
"Anthony dovetta ( 3620578 K )et christophe capeau ( 4666443v)", |
|
|
|
""" |
|
|
|
""" |
|
|
|
|