Fix memory issue when going in federal players search

sync2
Laurent 8 months ago
parent 2b856fcde4
commit 6334648efd
  1. 456
      PadelClub/Views/Tournament/Screen/AddTeamView.swift

@ -10,7 +10,7 @@ import LeStorage
import CoreData import CoreData
struct AddTeamView: View { struct AddTeamView: View {
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
private var fetchRequest: FetchRequest<ImportedPlayer> private var fetchRequest: FetchRequest<ImportedPlayer>
@ -45,7 +45,7 @@ struct AddTeamView: View {
@State private var displayWarningNotEnoughCharacter: Bool = false @State private var displayWarningNotEnoughCharacter: Bool = false
@State private var testMessageIndex: Int = 0 @State private var testMessageIndex: Int = 0
@State private var presentLocalMultiplayerSearch: Bool = false @State private var presentLocalMultiplayerSearch: Bool = false
var tournamentStore: TournamentStore? { var tournamentStore: TournamentStore? {
return self.tournament.tournamentStore return self.tournament.tournamentStore
} }
@ -61,11 +61,11 @@ struct AddTeamView: View {
createdPlayers.insert(player) createdPlayers.insert(player)
createdPlayerIds.insert(player.id) createdPlayerIds.insert(player.id)
} }
_createdPlayers = .init(wrappedValue: createdPlayers) _createdPlayers = .init(wrappedValue: createdPlayers)
_createdPlayerIds = .init(wrappedValue: createdPlayerIds) _createdPlayerIds = .init(wrappedValue: createdPlayerIds)
} }
let request: NSFetchRequest<ImportedPlayer> = ImportedPlayer.fetchRequest() let request: NSFetchRequest<ImportedPlayer> = ImportedPlayer.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)] request.sortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)]
request.fetchLimit = 1000 request.fetchLimit = 1000
@ -77,7 +77,7 @@ struct AddTeamView: View {
_textHeight = .init(wrappedValue: Self._calculateHeight(text: pasteString)) _textHeight = .init(wrappedValue: Self._calculateHeight(text: pasteString))
cancelShouldDismiss = true cancelShouldDismiss = true
} }
fetchRequest = FetchRequest(fetchRequest: request, animation: .default) fetchRequest = FetchRequest(fetchRequest: request, animation: .default)
} }
@ -97,7 +97,7 @@ struct AddTeamView: View {
computedBody computedBody
} }
} }
var computedBody: some View { var computedBody: some View {
List(selection: $createdPlayerIds) { List(selection: $createdPlayerIds) {
_buildingTeamView() _buildingTeamView()
@ -127,7 +127,7 @@ struct AddTeamView: View {
Button("Créer l'équipe quand même") { Button("Créer l'équipe quand même") {
_createTeam(checkDuplicates: false, checkHomonym: false) _createTeam(checkDuplicates: false, checkHomonym: false)
} }
Button("Annuler", role: .cancel) { Button("Annuler", role: .cancel) {
confirmHomonym = false confirmHomonym = false
} }
@ -140,7 +140,7 @@ struct AddTeamView: View {
Button("Créer l'équipe quand même") { Button("Créer l'équipe quand même") {
_createTeam(checkDuplicates: false, checkHomonym: true) _createTeam(checkDuplicates: false, checkHomonym: true)
} }
Button("Annuler", role: .cancel) { Button("Annuler", role: .cancel) {
confirmDuplicate = false confirmDuplicate = false
} }
@ -221,11 +221,11 @@ struct AddTeamView: View {
.buttonBorderShape(.capsule) .buttonBorderShape(.capsule)
} }
} }
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .topBarTrailing) {
Button { Button {
let generalString = UIPasteboard.general.string ?? "" let generalString = UIPasteboard.general.string ?? ""
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
let s = testMessages[testMessageIndex % testMessages.count] let s = testMessages[testMessageIndex % testMessages.count]
handlePasteString(s) handlePasteString(s)
@ -249,15 +249,15 @@ struct AddTeamView: View {
.navigationTitle(editedTeam == nil ? "Ajouter une équipe" : "Modifier l'équipe") .navigationTitle(editedTeam == nil ? "Ajouter une équipe" : "Modifier l'équipe")
.environment(\.editMode, Binding.constant(EditMode.active)) .environment(\.editMode, Binding.constant(EditMode.active))
} }
private func _isEditingTeam() -> Bool { private func _isEditingTeam() -> Bool {
createdPlayerIds.isEmpty == false || editedTeam != nil || pasteString != nil createdPlayerIds.isEmpty == false || editedTeam != nil || pasteString != nil
} }
var unsortedPlayers: [PlayerRegistration] { var unsortedPlayers: [PlayerRegistration] {
tournament.unsortedPlayers() tournament.unsortedPlayers()
} }
@ViewBuilder @ViewBuilder
private func _managementView() -> some View { private func _managementView() -> some View {
Section { Section {
@ -269,7 +269,7 @@ struct AddTeamView: View {
Text("Cherchez dans la base fédérale de \(rankSourceDate.monthYearFormatted), vous y trouverez tous les joueurs ayant participé à au moins un tournoi dans les 12 derniers mois.") Text("Cherchez dans la base fédérale de \(rankSourceDate.monthYearFormatted), vous y trouverez tous les joueurs ayant participé à au moins un tournoi dans les 12 derniers mois.")
} }
} }
if tournament.isAnimation(), createdPlayers.isEmpty == true { if tournament.isAnimation(), createdPlayers.isEmpty == true {
Section { Section {
RowButtonView("Ajouter plusieurs joueurs du club") { RowButtonView("Ajouter plusieurs joueurs du club") {
@ -279,7 +279,7 @@ struct AddTeamView: View {
Text("Crée une équipe par joueur sélectionné") Text("Crée une équipe par joueur sélectionné")
} }
} }
Section { Section {
RowButtonView("Créer un non classé / non licencié") { RowButtonView("Créer un non classé / non licencié") {
if let pasteString, pasteString.isEmpty == false { if let pasteString, pasteString.isEmpty == false {
@ -292,7 +292,7 @@ struct AddTeamView: View {
Text("Si le joueur n'a pas encore de licence ou n'a pas encore participé à une compétition, vous pouvez le créer vous-même.") Text("Si le joueur n'a pas encore de licence ou n'a pas encore participé à une compétition, vous pouvez le créer vous-même.")
} }
} }
private func _addPlayerSex() -> Int { private func _addPlayerSex() -> Int {
switch tournament.tournamentCategory { switch tournament.tournamentCategory {
case .men, .unlisted: case .men, .unlisted:
@ -304,11 +304,11 @@ struct AddTeamView: View {
} }
} }
private func _filterOption() -> PlayerFilterOption { private func _filterOption() -> PlayerFilterOption {
return tournament.tournamentCategory.playerFilterOption return tournament.tournamentCategory.playerFilterOption
} }
private func _currentSelection() -> Set<PlayerRegistration> { private func _currentSelection() -> Set<PlayerRegistration> {
var currentSelection = Set<PlayerRegistration>() var currentSelection = Set<PlayerRegistration>()
createdPlayerIds.compactMap { id in createdPlayerIds.compactMap { id in
@ -318,7 +318,7 @@ struct AddTeamView: View {
player.setComputedRank(in: tournament) player.setComputedRank(in: tournament)
currentSelection.insert(player) currentSelection.insert(player)
} }
createdPlayerIds.compactMap { id in createdPlayerIds.compactMap { id in
createdPlayers.first(where: { id == $0.id }) createdPlayers.first(where: { id == $0.id })
}.forEach { }.forEach {
@ -334,7 +334,7 @@ struct AddTeamView: View {
}.forEach { player in }.forEach { player in
currentSelection.append(player.license) currentSelection.append(player.license)
} }
createdPlayerIds.compactMap { id in createdPlayerIds.compactMap { id in
createdPlayers.first(where: { id == $0.id }) createdPlayers.first(where: { id == $0.id })
}.forEach { }.forEach {
@ -342,7 +342,7 @@ struct AddTeamView: View {
} }
return currentSelection return currentSelection
} }
private func _isDuplicate() -> Bool { private func _isDuplicate() -> Bool {
if tournament.isAnimation() { return false } if tournament.isAnimation() { return false }
let ids : [String?] = _currentSelectionIds() let ids : [String?] = _currentSelectionIds()
@ -351,15 +351,15 @@ struct AddTeamView: View {
} }
return false return false
} }
private func _createTeam(checkDuplicates: Bool, checkHomonym: Bool) { private func _createTeam(checkDuplicates: Bool, checkHomonym: Bool) {
if checkDuplicates && _isDuplicate() { if checkDuplicates && _isDuplicate() {
confirmDuplicate = true confirmDuplicate = true
return return
} }
let players = _currentSelection() let players = _currentSelection()
if checkHomonym { if checkHomonym {
homonyms = players.filter({ $0.hasHomonym() }) homonyms = players.filter({ $0.hasHomonym() })
if homonyms.isEmpty == false { if homonyms.isEmpty == false {
@ -367,27 +367,27 @@ struct AddTeamView: View {
return return
} }
} }
let team = tournament.addTeam(players) let team = tournament.addTeam(players)
self.tournamentStore?.teamRegistrations.addOrUpdate(instance: team) self.tournamentStore?.teamRegistrations.addOrUpdate(instance: team)
self.tournamentStore?.playerRegistrations.addOrUpdate(contentOfs: players) self.tournamentStore?.playerRegistrations.addOrUpdate(contentOfs: players)
pasteString = nil pasteString = nil
editableTextField = "" editableTextField = ""
createdPlayers.removeAll() createdPlayers.removeAll()
createdPlayerIds.removeAll() createdPlayerIds.removeAll()
if team.players().count > 1 { if team.players().count > 1 {
dismiss() dismiss()
} else { } else {
editedTeam = team editedTeam = team
team.unsortedPlayers().forEach { player in team.unsortedPlayers().forEach { player in
createdPlayers.insert(player) createdPlayers.insert(player)
createdPlayerIds.insert(player.id) createdPlayerIds.insert(player.id)
} }
} }
} }
private func _updateTeam(checkDuplicates: Bool) { private func _updateTeam(checkDuplicates: Bool) {
guard let editedTeam else { return } guard let editedTeam else { return }
if checkDuplicates && _isDuplicate() { if checkDuplicates && _isDuplicate() {
@ -399,7 +399,7 @@ struct AddTeamView: View {
editedTeam.updatePlayers(players, inTournamentCategory: tournament.tournamentCategory) editedTeam.updatePlayers(players, inTournamentCategory: tournament.tournamentCategory)
self.tournamentStore?.teamRegistrations.addOrUpdate(instance: editedTeam) self.tournamentStore?.teamRegistrations.addOrUpdate(instance: editedTeam)
self.tournamentStore?.playerRegistrations.addOrUpdate(contentOfs: players) self.tournamentStore?.playerRegistrations.addOrUpdate(contentOfs: players)
pasteString = nil pasteString = nil
editableTextField = "" editableTextField = ""
@ -407,7 +407,7 @@ struct AddTeamView: View {
dismiss() dismiss()
} }
} }
// Calculating the height based on the content of the TextEditor // Calculating the height based on the content of the TextEditor
static private func _calculateHeight(text: String) -> CGFloat { static private func _calculateHeight(text: String) -> CGFloat {
let size = CGSize(width: UIScreen.main.bounds.width - 32, height: .infinity) let size = CGSize(width: UIScreen.main.bounds.width - 32, height: .infinity)
@ -420,23 +420,15 @@ 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,104 +460,121 @@ 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 }) {
@ViewBuilder VStack(alignment: .leading, spacing: 0) {
private func _buildingTeamView() -> some View { 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()
PasteStringSection( }
pasteString: pasteString, if tournament.isPlayerAgeInadequate(player: p) {
editableTextField: $editableTextField, Text("Âge invalide !").foregroundStyle(.logoRed).bold()
textHeight: $textHeight, }
focusedField: _focusedField, if tournament.isPlayerRankInadequate(player: p) {
handlePasteString: handlePasteString, Text("Trop bien classé !").foregroundStyle(.logoRed).bold()
displayWarningNotEnoughCharacter: $displayWarningNotEnoughCharacter }
) 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())
}
TeamSelectionSection( VStack(alignment: .leading, spacing: 0) {
createdPlayerIds: createdPlayerIds, Text("Poids").font(.caption)
createdPlayers: createdPlayers, Text(rank.formatted())
unsortedPlayers: unsortedPlayers, }
fetchPlayers: fetchPlayers, Spacer()
editedTeam: editedTeam, VStack(alignment: .trailing, spacing: 0) {
pasteString: pasteString, Text("").font(.caption)
tournament: tournament, Text(tournament.cutLabel(index: teamIndex, teamCount: selectedSortedTeams.count))
_createTeam: _createTeam, }
_updateTeam: _updateTeam, }
dismiss: dismiss, // } else {
_currentSelection: _currentSelection // Text("Préparation de l'équipe")
) }
}
if let pasteString, pasteString.isEmpty == false { if let pasteString, pasteString.isEmpty == false {
let sortedPlayers = _searchFilteredPlayers() let sortedPlayers = _searchFilteredPlayers()
if sortedPlayers.isEmpty { if sortedPlayers.isEmpty {
ContentUnavailableView { ContentUnavailableView {
Label("Aucun résultat", systemImage: "person.2.slash") Label("Aucun résultat", systemImage: "person.2.slash")
} description: { } 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.") 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: { } actions: {
RowButtonView("Créer un joueur non classé") { RowButtonView("Créer un joueur non classé") {
selectionSearchField = pasteString selectionSearchField = pasteString
} }
RowButtonView("Chercher dans la base") {
presentPlayerSearch = true
}
RowButtonView("Chercher dans la base") { RowButtonView("Effacer cette recherche") {
presentPlayerSearch = true self.pasteString = nil
self.editableTextField = ""
}
} }
RowButtonView("Effacer cette recherche") { } else {
self.pasteString = nil _listOfPlayers(searchFilteredPlayers: sortedPlayers, pasteString: pasteString)
self.editableTextField = ""
}
} }
} else { } else {
_listOfPlayers(searchFilteredPlayers: sortedPlayers, pasteString: pasteString) _managementView()
} }
} else {
_managementView()
}
} }
//
// 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 }
@ -602,7 +611,7 @@ struct AddTeamView: View {
} }
return 1 return 1
} }
private func handlePasteString(_ first: String) { private func handlePasteString(_ first: String) {
if first.isEmpty == false { if first.isEmpty == false {
fetchPlayers.nsPredicate = SearchViewModel.pastePredicate(pasteField: first, mostRecentDate: SourceFileManager.shared.mostRecentDateAvailable, filterOption: _filterOption()) fetchPlayers.nsPredicate = SearchViewModel.pastePredicate(pasteField: first, mostRecentDate: SourceFileManager.shared.mostRecentDateAvailable, filterOption: _filterOption())
@ -617,7 +626,7 @@ struct AddTeamView: View {
@ViewBuilder @ViewBuilder
private func _listOfPlayers(searchFilteredPlayers: [ImportedPlayer], pasteString: String) -> some View { private func _listOfPlayers(searchFilteredPlayers: [ImportedPlayer], pasteString: String) -> some View {
let sortedPlayers = _sortedPlayers(searchFilteredPlayers: searchFilteredPlayers, pasteString: pasteString) let sortedPlayers = _sortedPlayers(searchFilteredPlayers: searchFilteredPlayers, pasteString: pasteString)
Section { Section {
ForEach(sortedPlayers) { player in ForEach(sortedPlayers) { player in
ImportedPlayerView(player: player).tag(player.license!) ImportedPlayerView(player: player).tag(player.license!)
@ -628,7 +637,7 @@ struct AddTeamView: View {
} }
} }
private func _searchFilteredPlayers() -> [ImportedPlayer] { private func _searchFilteredPlayers() -> [ImportedPlayer] {
if searchField.isEmpty { if searchField.isEmpty {
return Array(fetchPlayers) return Array(fetchPlayers)
@ -636,171 +645,12 @@ struct AddTeamView: View {
return fetchPlayers.filter({ $0.contains(searchField) }) return fetchPlayers.filter({ $0.contains(searchField) })
} }
} }
private func _sortedPlayers(searchFilteredPlayers: [ImportedPlayer], pasteString: String) -> [ImportedPlayer] { private func _sortedPlayers(searchFilteredPlayers: [ImportedPlayer], pasteString: String) -> [ImportedPlayer] {
return searchFilteredPlayers.sorted(by: { hitForSearch($0, pasteString) > hitForSearch($1, pasteString) }) return searchFilteredPlayers.sorted(by: { hitForSearch($0, pasteString) > hitForSearch($1, pasteString) })
} }
} }
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)",
""" """
@ -827,6 +677,6 @@ Tullou Benjamin 8990867f
""", """,
""" """
Sms Julien La Croix +33622886688 Sms Julien La Croix +33622886688
Salut Raz, c'est ! Ju Lacroix J'espère que tu vas bien depuis le temps! Est-ce que tu peux nous inscrire au 1000 de Bandol avec Derek Gerson stp? Salut Raz, c'est ! Ju Lacroix J'espère que tu vas bien depuis le temps! Est-ce que tu peux nous inscrire au 1000 de Bandol avec Derek Gerson stp?
""" """
] ]

Loading…
Cancel
Save