Fix memory issue when going in federal players search

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

@ -372,20 +372,20 @@ struct AddTeamView: View {
self.tournamentStore?.teamRegistrations.addOrUpdate(instance: team)
self.tournamentStore?.playerRegistrations.addOrUpdate(contentOfs: players)
pasteString = nil
editableTextField = ""
createdPlayers.removeAll()
createdPlayerIds.removeAll()
if team.players().count > 1 {
dismiss()
} else {
editedTeam = team
team.unsortedPlayers().forEach { player in
createdPlayers.insert(player)
createdPlayerIds.insert(player.id)
}
}
pasteString = nil
editableTextField = ""
createdPlayers.removeAll()
createdPlayerIds.removeAll()
if team.players().count > 1 {
dismiss()
} else {
editedTeam = team
team.unsortedPlayers().forEach { player in
createdPlayers.insert(player)
createdPlayerIds.insert(player.id)
}
}
}
private func _updateTeam(checkDuplicates: Bool) {
@ -421,22 +421,14 @@ struct AddTeamView: View {
return max(boundingRect.height + 20, 40) // Add some padding and set a minimum height
}
struct PasteStringSection: 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 {
@ViewBuilder
private func _buildingTeamView() -> some View {
if let pasteString {
Section {
TextEditor(text: $editableTextField)
.frame(height: textHeight)
.onChange(of: editableTextField) {
textHeight = AddTeamView._calculateHeight(text: pasteString)
textHeight = Self._calculateHeight(text: pasteString)
}
.focused($focusedField, equals: .pasteField)
.toolbar {
@ -468,104 +460,121 @@ struct AddTeamView: View {
FooterButtonView("effacer le texte") {
self.focusedField = nil
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())
}
@ViewBuilder
private func _buildingTeamView() -> some View {
PasteStringSection(
pasteString: pasteString,
editableTextField: $editableTextField,
textHeight: $textHeight,
focusedField: _focusedField,
handlePasteString: handlePasteString,
displayWarningNotEnoughCharacter: $displayWarningNotEnoughCharacter
)
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")
}
}
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 {
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
}
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("Chercher dans la base") {
presentPlayerSearch = true
}
RowButtonView("Effacer cette recherche") {
self.pasteString = nil
self.editableTextField = ""
RowButtonView("Effacer cette recherche") {
self.pasteString = nil
self.editableTextField = ""
}
}
}
} else {
_listOfPlayers(searchFilteredPlayers: sortedPlayers, pasteString: pasteString)
}
} 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
func hitForSearch(_ ip: ImportedPlayer, _ pasteString: String?) -> Int {
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 = [
"Anthony dovetta ( 3620578 K )et christophe capeau ( 4666443v)",
"""

Loading…
Cancel
Save