@ -20,7 +20,11 @@ struct AddTeamView: View {
var tournament : Tournament
var tournament : Tournament
var cancelShouldDismiss : Bool = false
var cancelShouldDismiss : Bool = false
enum FocusField : Hashable {
case pasteField
}
@ FocusState private var focusedField : FocusField ?
@ State private var searchField : String = " "
@ State private var searchField : String = " "
@ State private var presentSearch : Bool = false
@ State private var presentSearch : Bool = false
@ State private var presentPlayerSearch : Bool = false
@ State private var presentPlayerSearch : Bool = false
@ -36,6 +40,7 @@ struct AddTeamView: View {
@ State private var confirmDuplicate : Bool = false
@ State private var confirmDuplicate : Bool = false
@ State private var homonyms : [ PlayerRegistration ] = [ ]
@ State private var homonyms : [ PlayerRegistration ] = [ ]
@ State private var confirmHomonym : Bool = false
@ State private var confirmHomonym : Bool = false
@ State private var editableTextField : String = " "
var tournamentStore : TournamentStore {
var tournamentStore : TournamentStore {
return self . tournament . tournamentStore
return self . tournament . tournamentStore
@ -61,13 +66,32 @@ struct AddTeamView: View {
_pasteString = . init ( wrappedValue : pasteString )
_pasteString = . init ( wrappedValue : pasteString )
_fetchPlayers = FetchRequest < ImportedPlayer > ( sortDescriptors : [ NSSortDescriptor ( keyPath : \ ImportedPlayer . rank , ascending : true ) ] , predicate : SearchViewModel . pastePredicate ( pasteField : pasteString , mostRecentDate : tournament . rankSourceDate , filterOption : tournament . tournamentCategory . playerFilterOption ) )
_fetchPlayers = FetchRequest < ImportedPlayer > ( sortDescriptors : [ NSSortDescriptor ( keyPath : \ ImportedPlayer . rank , ascending : true ) ] , predicate : SearchViewModel . pastePredicate ( pasteField : pasteString , mostRecentDate : tournament . rankSourceDate , filterOption : tournament . tournamentCategory . playerFilterOption ) )
_autoSelect = . init ( wrappedValue : true )
_autoSelect = . init ( wrappedValue : true )
_editableTextField = . init ( wrappedValue : pasteString )
cancelShouldDismiss = true
cancelShouldDismiss = true
}
}
}
}
var body : some View {
var body : some View {
_buildingTeamView ( )
if pasteString = = nil {
. navigationBarBackButtonHidden ( true )
computedBody
} else {
computedBody
. searchable ( text : $ searchField , placement : . navigationBarDrawer ( displayMode : . automatic ) , prompt : Text ( " Chercher dans les résultats " ) )
}
}
var computedBody : some View {
List ( selection : $ createdPlayerIds ) {
_buildingTeamView ( )
}
. onReceive ( fetchPlayers . publisher . count ( ) ) { _ in // < - - h e r e
if let pasteString , count = = 2 , autoSelect = = true {
fetchPlayers . filter { $0 . hitForSearch ( pasteString ) >= hitTarget } . sorted ( by : { $0 . hitForSearch ( pasteString ) > $1 . hitForSearch ( pasteString ) } ) . forEach { player in
createdPlayerIds . insert ( player . license ! )
}
autoSelect = false
}
}
. alert ( " Présence d'homonyme " , isPresented : $ confirmHomonym ) {
. alert ( " Présence d'homonyme " , isPresented : $ confirmHomonym ) {
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 )
@ -121,7 +145,6 @@ struct AddTeamView: View {
}
}
. tint ( . master )
. tint ( . master )
}
}
. navigationTitle ( editedTeam = = nil ? " Ajouter une équipe " : " Modifier l'équipe " )
. toolbar {
. toolbar {
ToolbarItem ( placement : . cancellationAction ) {
ToolbarItem ( placement : . cancellationAction ) {
Button ( " Annuler " , role : . cancel ) {
Button ( " Annuler " , role : . cancel ) {
@ -130,27 +153,23 @@ struct AddTeamView: View {
}
}
if pasteString = = nil {
if pasteString = = nil {
ToolbarItem ( placement : . topBarTrailing ) {
ToolbarItem ( placement : . bottomBar ) {
PasteButton ( payloadType : String . self ) { strings in
PasteButton ( payloadType : String . self ) { strings in
guard let first = strings . first else { return }
guard let first = strings . first else { return }
Task {
handlePasteString ( first )
await MainActor . run {
fetchPlayers . nsPredicate = SearchViewModel . pastePredicate ( pasteField : first , mostRecentDate : SourceFileManager . shared . mostRecentDateAvailable , filterOption : _filterOption ( ) )
fetchPlayers . nsSortDescriptors = [ NSSortDescriptor ( keyPath : \ ImportedPlayer . rank , ascending : true ) ]
pasteString = first
autoSelect = true
}
}
}
}
. foregroundStyle ( . master )
. foregroundStyle ( . master )
. labelStyle ( . iconOnly )
. labelStyle ( . titleAndIcon )
. buttonBorderShape ( . capsule )
. buttonBorderShape ( . capsule )
}
}
}
}
}
}
. navigationBarBackButtonHidden ( _isEditingTeam ( ) )
. navigationBarBackButtonHidden ( _isEditingTeam ( ) )
. toolbarBackground ( . visible , for : . navigationBar )
. toolbarBackground ( . visible , for : . navigationBar )
. toolbarBackground ( . visible , for : . bottomBar )
. navigationBarTitleDisplayMode ( . inline )
. navigationBarTitleDisplayMode ( . inline )
. navigationTitle ( editedTeam = = nil ? " Ajouter une équipe " : " Modifier l'équipe " )
. environment ( \ . editMode , Binding . constant ( EditMode . active ) )
}
}
private func _isEditingTeam ( ) -> Bool {
private func _isEditingTeam ( ) -> Bool {
@ -275,6 +294,8 @@ struct AddTeamView: View {
createdPlayers . removeAll ( )
createdPlayers . removeAll ( )
createdPlayerIds . removeAll ( )
createdPlayerIds . removeAll ( )
pasteString = nil
pasteString = nil
editableTextField = " "
if team . players ( ) . count > 1 {
if team . players ( ) . count > 1 {
dismiss ( )
dismiss ( )
}
}
@ -302,23 +323,42 @@ struct AddTeamView: View {
createdPlayers . removeAll ( )
createdPlayers . removeAll ( )
createdPlayerIds . removeAll ( )
createdPlayerIds . removeAll ( )
pasteString = nil
pasteString = nil
editableTextField = " "
self . editedTeam = nil
self . editedTeam = nil
if editedTeam . players ( ) . count > 1 {
if editedTeam . players ( ) . count > 1 {
dismiss ( )
dismiss ( )
}
}
}
}
@ ViewBuilder
private func _buildingTeamView ( ) -> some View {
private func _buildingTeamView ( ) -> some View {
List ( selection : $ createdPlayerIds ) {
if let pasteString {
if let pasteString {
Section {
Section {
Text ( pasteString )
TextEditor ( text : $ editableTextField )
. focused ( $ focusedField , equals : . pasteField )
. toolbar {
ToolbarItemGroup ( placement : . keyboard ) {
Button ( " Fermer " , role : . cancel ) {
self . editableTextField = pasteString
self . focusedField = nil
}
Spacer ( )
Button ( " Chercher " ) {
self . handlePasteString ( editableTextField )
self . focusedField = nil
}
. buttonStyle ( . bordered )
}
}
} header : {
Text ( " Contenu du presse-papier " )
} footer : {
} footer : {
HStack {
HStack {
Text ( " contenu du presse-papier " )
Spacer ( )
Spacer ( )
Button ( " effacer " , role : . destructive ) {
Button ( " effacer " , role : . destructive ) {
self . focusedField = nil
self . editableTextField = " "
self . pasteString = nil
self . pasteString = nil
self . createdPlayers . removeAll ( )
self . createdPlayers . removeAll ( )
self . createdPlayerIds . removeAll ( )
self . createdPlayerIds . removeAll ( )
@ -387,6 +427,8 @@ struct AddTeamView: View {
Text ( tournament . cutLabel ( index : teamIndex , teamCount : selectedSortedTeams . count ) )
Text ( tournament . cutLabel ( index : teamIndex , teamCount : selectedSortedTeams . count ) )
}
}
}
}
// } e l s e {
// T e x t ( " P r é p a r a t i o n d e l ' é q u i p e " )
}
}
}
}
@ -404,33 +446,16 @@ struct AddTeamView: View {
RowButtonView ( " Effacer cette recherche " ) {
RowButtonView ( " Effacer cette recherche " ) {
self . pasteString = nil
self . pasteString = nil
self . editableTextField = " "
}
}
}
}
} else {
} else {
Section {
_listOfPlayers ( pasteString : pasteString )
let sortedPlayers = fetchPlayers . sorted ( by : { $0 . hitForSearch ( pasteString ) > $1 . hitForSearch ( pasteString ) } )
ForEach ( sortedPlayers ) { player in
ImportedPlayerView ( player : player ) . tag ( player . license ! )
}
} header : {
Text ( fetchPlayers . count . formatted ( ) + " résultat " + fetchPlayers . count . pluralSuffix )
}
}
}
} else {
} else {
_managementView ( )
_managementView ( )
}
}
}
. headerProminence ( . increased )
. onReceive ( fetchPlayers . publisher . count ( ) ) { _ in // < - - h e r e
if let pasteString , count = = 2 , autoSelect = = true {
fetchPlayers . filter { $0 . hitForSearch ( pasteString ) >= hitTarget } . sorted ( by : { $0 . hitForSearch ( pasteString ) > $1 . hitForSearch ( pasteString ) } ) . forEach { player in
createdPlayerIds . insert ( player . license ! )
}
autoSelect = false
}
}
. environment ( \ . editMode , Binding . constant ( EditMode . active ) )
}
}
private var count : Int {
private var count : Int {
@ -453,4 +478,32 @@ struct AddTeamView: View {
Logger . error ( error )
Logger . error ( error )
}
}
}
}
private func handlePasteString ( _ first : String ) {
Task {
await MainActor . run {
fetchPlayers . nsPredicate = SearchViewModel . pastePredicate ( pasteField : first , mostRecentDate : SourceFileManager . shared . mostRecentDateAvailable , filterOption : _filterOption ( ) )
fetchPlayers . nsSortDescriptors = [ NSSortDescriptor ( keyPath : \ ImportedPlayer . rank , ascending : true ) ]
pasteString = first
editableTextField = first
autoSelect = true
}
}
}
@ ViewBuilder
private func _listOfPlayers ( pasteString : String ) -> some View {
let sortedPlayers = fetchPlayers . filter ( { $0 . contains ( searchField ) || searchField . isEmpty } ) . sorted ( by : { $0 . hitForSearch ( pasteString ) > $1 . hitForSearch ( pasteString ) } )
Section {
ForEach ( sortedPlayers ) { player in
ImportedPlayerView ( player : player ) . tag ( player . license ! )
}
} header : {
Text ( sortedPlayers . count . formatted ( ) + " résultat " + sortedPlayers . count . pluralSuffix )
}
}
}
}