multistore
Razmig Sarkissian 2 years ago
parent 0a3110967a
commit 588c7e8868
  1. 2
      PadelClub.xcodeproj/project.pbxproj
  2. 18
      PadelClub/Data/Federal/FederalPlayer.swift
  3. 20
      PadelClub/Data/MonthData.swift
  4. 2
      PadelClub/Data/Tournament.swift
  5. 15
      PadelClub/Utils/FileImportManager.swift
  6. 5
      PadelClub/Views/Navigation/MainView.swift
  7. 4
      PadelClub/Views/Navigation/Organizer/TournamentOrganizerView.swift
  8. 65
      PadelClub/Views/Navigation/Umpire/PadelClubView.swift
  9. 15
      PadelClub/Views/Team/Components/TeamHeaderView.swift
  10. 4
      PadelClub/Views/Tournament/FileImportView.swift
  11. 8
      PadelClub/Views/Tournament/Shared/TournamentCellView.swift

@ -958,7 +958,6 @@
FF025AE62BD1111000A86CF8 /* GlobalSettingsView.swift */, FF025AE62BD1111000A86CF8 /* GlobalSettingsView.swift */,
FF025AEE2BD1AE9400A86CF8 /* DurationSettingsView.swift */, FF025AEE2BD1AE9400A86CF8 /* DurationSettingsView.swift */,
FF025AF02BD1AEBD00A86CF8 /* MatchFormatStorageView.swift */, FF025AF02BD1AEBD00A86CF8 /* MatchFormatStorageView.swift */,
FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */,
); );
path = Toolbox; path = Toolbox;
sourceTree = "<group>"; sourceTree = "<group>";
@ -967,6 +966,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FF3F74F52B919E45004CFE0E /* UmpireView.swift */, FF3F74F52B919E45004CFE0E /* UmpireView.swift */,
FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */,
); );
path = Umpire; path = Umpire;
sourceTree = "<group>"; sourceTree = "<group>";

@ -169,7 +169,19 @@ class FederalPlayer: Decodable {
club = result[10] club = result[10]
} }
static func lastRank(mostRecentDateAvailable: Date?, man: Bool) async -> Int? { static func anonymousCount(mostRecentDateAvailable: Date?) async -> Int? {
let context = PersistenceController.shared.localContainer.newBackgroundContext()
let importedPlayerFetchRequest = ImportedPlayer.fetchRequest()
var predicate = NSPredicate(format: "lastName == %@ && firstName == %@", "", "")
if let mostRecentDateAvailable {
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)])
}
importedPlayerFetchRequest.predicate = predicate
let count = try? context.count(for: importedPlayerFetchRequest)
return count
}
static func lastRank(mostRecentDateAvailable: Date?, man: Bool) async -> (Int, Int?)? {
let context = PersistenceController.shared.localContainer.newBackgroundContext() let context = PersistenceController.shared.localContainer.newBackgroundContext()
let lastPlayerFetch = ImportedPlayer.fetchRequest() let lastPlayerFetch = ImportedPlayer.fetchRequest()
lastPlayerFetch.sortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: false)] lastPlayerFetch.sortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: false)]
@ -178,7 +190,7 @@ class FederalPlayer: Decodable {
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)]) predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)])
} }
lastPlayerFetch.predicate = predicate lastPlayerFetch.predicate = predicate
let count = try? context.count(for: lastPlayerFetch)
do { do {
if let lr = try context.fetch(lastPlayerFetch).first?.rank { if let lr = try context.fetch(lastPlayerFetch).first?.rank {
let fetch = ImportedPlayer.fetchRequest() let fetch = ImportedPlayer.fetchRequest()
@ -189,7 +201,7 @@ class FederalPlayer: Decodable {
fetch.predicate = rankPredicate fetch.predicate = rankPredicate
let lastPlayersCount = try context.count(for: fetch) let lastPlayersCount = try context.count(for: fetch)
return Int(lr) + Int(lastPlayersCount) - 1 return (Int(lr) + Int(lastPlayersCount) - 1, count)
} }
} catch { } catch {
print("ImportedPlayer.fetchRequest", error) print("ImportedPlayer.fetchRequest", error)

@ -21,21 +21,32 @@ class MonthData : ModelObject, Storable {
var maleUnrankedValue: Int? = nil var maleUnrankedValue: Int? = nil
var femaleUnrankedValue: Int? = nil var femaleUnrankedValue: Int? = nil
var maleCount: Int? = nil
var femaleCount: Int? = nil
var anonymousCount: Int? = nil
init(monthKey: String) { init(monthKey: String) {
self.monthKey = monthKey self.monthKey = monthKey
self.creationDate = Date() self.creationDate = Date()
} }
func total() -> Int {
(maleCount ?? 0) + (femaleCount ?? 0)
}
static func calculateCurrentUnrankedValues(mostRecentDateAvailable: Date) async { static func calculateCurrentUnrankedValues(mostRecentDateAvailable: Date) async {
let lastDataSourceMaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: mostRecentDateAvailable, man: true) let lastDataSourceMaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: mostRecentDateAvailable, man: true)
let lastDataSourceFemaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: mostRecentDateAvailable, man: false) let lastDataSourceFemaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: mostRecentDateAvailable, man: false)
let anonymousCount = await FederalPlayer.anonymousCount(mostRecentDateAvailable: mostRecentDateAvailable)
await MainActor.run { await MainActor.run {
if let lastDataSource = DataStore.shared.appSettings.lastDataSource { if let lastDataSource = DataStore.shared.appSettings.lastDataSource {
let currentMonthData : MonthData = Store.main.filter(isIncluded: { $0.monthKey == lastDataSource }).first ?? MonthData(monthKey: lastDataSource) let currentMonthData : MonthData = Store.main.filter(isIncluded: { $0.monthKey == lastDataSource }).first ?? MonthData(monthKey: lastDataSource)
currentMonthData.maleUnrankedValue = lastDataSourceMaleUnranked currentMonthData.maleUnrankedValue = lastDataSourceMaleUnranked?.0
currentMonthData.femaleUnrankedValue = lastDataSourceFemaleUnranked currentMonthData.maleCount = lastDataSourceMaleUnranked?.1
currentMonthData.femaleUnrankedValue = lastDataSourceFemaleUnranked?.0
currentMonthData.femaleCount = lastDataSourceFemaleUnranked?.1
currentMonthData.anonymousCount = anonymousCount
try? DataStore.shared.monthData.addOrUpdate(instance: currentMonthData) try? DataStore.shared.monthData.addOrUpdate(instance: currentMonthData)
} }
} }
@ -50,5 +61,8 @@ class MonthData : ModelObject, Storable {
case _creationDate = "creationDate" case _creationDate = "creationDate"
case _maleUnrankedValue = "maleUnrankedValue" case _maleUnrankedValue = "maleUnrankedValue"
case _femaleUnrankedValue = "femaleUnrankedValue" case _femaleUnrankedValue = "femaleUnrankedValue"
case _maleCount = "maleCount"
case _femaleCount = "femaleCount"
case _anonymousCount = "anonymousCount"
} }
} }

@ -562,7 +562,7 @@ class Tournament : ModelObject, Storable {
let defaultSorting : [MySortDescriptor<TeamRegistration>] = _defaultSorting() let defaultSorting : [MySortDescriptor<TeamRegistration>] = _defaultSorting()
let _completeTeams = _teams.sorted(using: defaultSorting, order: .ascending).filter { $0.isWildCard() == false} let _completeTeams = _teams.sorted(using: defaultSorting, order: .ascending).filter { $0.isWildCard() == false }.prefix(teamCount).sorted(by: \.initialWeight)
let wcGroupStage = _teams.filter { $0.wildCardGroupStage }.sorted(using: _currentSelectionSorting, order: .ascending) let wcGroupStage = _teams.filter { $0.wildCardGroupStage }.sorted(using: _currentSelectionSorting, order: .ascending)

@ -106,7 +106,9 @@ class FileImportManager {
} }
} }
let significantPlayerCount = 2 let significantPlayerCount = 2
self.weight = (players.prefix(significantPlayerCount).map { $0.computedRank } + missing.map { tournament.unrankValue(for: $0 == 1 ? true : false ) ?? 0 }).prefix(significantPlayerCount).reduce(0,+) let pl = players.prefix(significantPlayerCount).map { $0.computedRank }
let missingPl = (missing.map { tournament.unrankValue(for: $0 == 1 ? true : false ) ?? ($0 == 1 ? 100_000 : 10_000) }).prefix(significantPlayerCount)
self.weight = pl.reduce(0,+) + missingPl.reduce(0,+)
} else { } else {
self.weight = players.map { $0.computedRank }.reduce(0,+) self.weight = players.map { $0.computedRank }.reduce(0,+)
} }
@ -307,6 +309,13 @@ class FileImportManager {
} }
private func _getPadelClubTeams(from fileContent: String, tournament: Tournament) async -> [TeamHolder] { private func _getPadelClubTeams(from fileContent: String, tournament: Tournament) async -> [TeamHolder] {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "fr_FR")
// Set the date format to match the input string
dateFormatter.dateFormat = "EEE dd MMM yyyy 'à' HH:mm"
var lines = fileContent.components(separatedBy: "\n\n") var lines = fileContent.components(separatedBy: "\n\n")
var results: [TeamHolder] = [] var results: [TeamHolder] = []
let fetchRequest = ImportedPlayer.fetchRequest() let fetchRequest = ImportedPlayer.fetchRequest()
@ -324,8 +333,8 @@ class FileImportManager {
}) })
if let registeredPlayers, registeredPlayers.isEmpty == false { if let registeredPlayers, registeredPlayers.isEmpty == false {
var registrationDate: Date? { var registrationDate: Date? {
if let registrationDateData = data[safe:2]?.replacingOccurrences(of: "inscrit le ", with: "") { if let registrationDateData = data[safe:2]?.replacingOccurrences(of: "Inscrit le ", with: "") {
return try? Date(registrationDateData, strategy: .dateTime.weekday().day().month().hour().minute()) return dateFormatter.date(from: registrationDateData)
} }
return nil return nil
} }

@ -59,6 +59,11 @@ struct MainView: View {
// PadelClubView() // PadelClubView()
// .tabItem(for: .padelClub) // .tabItem(for: .padelClub)
} }
.id(Store.main.currentUserUUID)
.onChange(of: Store.main.currentUserUUID) {
navigation.tournament = nil
navigation.path.removeLast(navigation.path.count)
}
.environmentObject(dataStore) .environmentObject(dataStore)
.task { .task {
await self._checkSourceFileAvailability() await self._checkSourceFileAvailability()

@ -6,6 +6,7 @@
// //
import SwiftUI import SwiftUI
import LeStorage
struct TournamentOrganizerView: View { struct TournamentOrganizerView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@ -46,6 +47,9 @@ struct TournamentOrganizerView: View {
} }
} }
} }
.onChange(of: Store.main.currentUserUUID) {
selectedTournamentId = nil
}
} }
} }

@ -26,12 +26,6 @@ struct PadelClubView: View {
animation: .default) animation: .default)
private var players: FetchedResults<ImportedPlayer> private var players: FetchedResults<ImportedPlayer>
@FetchRequest(
sortDescriptors: [],
predicate: NSPredicate(format: "lastName == %@ && firstName == %@", "", ""),
animation: .default)
private var anonymousPlayers: FetchedResults<ImportedPlayer>
var _mostRecentDateAvailable: Date? { var _mostRecentDateAvailable: Date? {
SourceFileManager.shared.mostRecentDateAvailable SourceFileManager.shared.mostRecentDateAvailable
} }
@ -96,27 +90,6 @@ struct PadelClubView: View {
} }
} }
} }
Section {
LabeledContent {
Text(players.filter{ $0.male }.count.formatted())
} label: {
Text("Messieurs")
}
LabeledContent {
Text(players.filter{ $0.male == false }.count.formatted())
} label: {
Text("Dames")
}
LabeledContent {
Text(anonymousPlayers.count.formatted())
} label: {
Text("Joueurs anonymes")
}
} header: {
Text(players.count.formatted() + " joueurs")
}
} }
if importingFiles { if importingFiles {
@ -136,6 +109,29 @@ struct PadelClubView: View {
let monthData = dataStore.monthData.sorted(by: \.creationDate).reversed() let monthData = dataStore.monthData.sorted(by: \.creationDate).reversed()
ForEach(monthData) { monthData in ForEach(monthData) { monthData in
Section { Section {
LabeledContent {
if let maleCount = monthData.maleCount {
Text(maleCount.formatted())
}
} label: {
Text("Messieurs")
}
LabeledContent {
if let femaleCount = monthData.femaleCount {
Text(femaleCount.formatted())
}
} label: {
Text("Dames")
}
LabeledContent {
if let anonymousCount = monthData.anonymousCount {
Text(anonymousCount.formatted())
}
} label: {
Text("Joueurs anonymes")
}
LabeledContent { LabeledContent {
if let maleUnrankedValue = monthData.maleUnrankedValue { if let maleUnrankedValue = monthData.maleUnrankedValue {
Text(maleUnrankedValue.formatted()) Text(maleUnrankedValue.formatted())
@ -153,7 +149,22 @@ struct PadelClubView: View {
Text("Dames") Text("Dames")
} }
} header: { } header: {
HStack {
Text(monthData.monthKey) Text(monthData.monthKey)
Spacer()
Text(monthData.total().formatted() + " joueurs")
}
} footer: {
HStack {
Spacer()
FooterButtonView("recalculer") {
Task {
if let monthKeyDate = URL.importDateFormatter.date(from: monthData.monthKey) {
await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: monthKeyDate)
}
}
}
}
} }
} }
} }

@ -19,23 +19,34 @@ struct TeamHeaderView: View {
private func _teamHeaderView(_ team: TeamRegistration, teamIndex: Int?) -> some View { private func _teamHeaderView(_ team: TeamRegistration, teamIndex: Int?) -> some View {
HStack { HStack {
if let teamIndex { if let teamIndex {
VStack(alignment: .leading, spacing: 0) {
Text("rang").font(.caption)
Text("#" + (teamIndex + 1).formatted()) Text("#" + (teamIndex + 1).formatted())
} }
}
if team.unsortedPlayers().isEmpty == false { if team.unsortedPlayers().isEmpty == false {
VStack(alignment: .leading, spacing: 0) {
Text("poids").font(.caption)
Text(team.weight.formatted()) Text(team.weight.formatted())
} }
if team.isWildCard() {
Text("wildcard").italic().font(.caption)
} }
Spacer() Spacer()
VStack(alignment: .trailing, spacing: 0) {
if team.walkOut { if team.walkOut {
Text("").font(.caption)
Text("WO") Text("WO")
} else if let teamIndex, let tournament { } else if let teamIndex, let tournament {
if team.isWildCard() {
Text("wildcard").font(.caption).italic()
} else {
Text("").font(.caption)
}
Text(tournament.cutLabel(index: teamIndex)) Text(tournament.cutLabel(index: teamIndex))
} }
} }
} }
}
} }
#Preview { #Preview {

@ -246,6 +246,10 @@ struct FileImportView: View {
errorMessage = nil errorMessage = nil
teams.removeAll() teams.removeAll()
} }
if let rankSourceDate = tournament.rankSourceDate, tournament.unrankValue(for: false) == nil || tournament.unrankValue(for: true) == nil {
await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: rankSourceDate)
}
self.teams = await FileImportManager.shared.createTeams(from: fileContent, tournament: tournament, fileProvider: fileProvider) self.teams = await FileImportManager.shared.createTeams(from: fileContent, tournament: tournament, fileProvider: fileProvider)
await MainActor.run { await MainActor.run {
convertingFile = false convertingFile = false

@ -69,7 +69,9 @@ struct TournamentCellView: View {
} }
Spacer() Spacer()
if let tournament = tournament as? Tournament, displayStyle == .wide { if let tournament = tournament as? Tournament, displayStyle == .wide {
Text(tournament.sortedTeams().count.formatted()) let hasStarted = tournament.inscriptionClosed() || tournament.hasStarted()
let count = hasStarted ? tournament.selectedSortedTeams().count : tournament.unsortedTeams().count
Text(count.formatted())
} else if let federalTournament = tournament as? FederalTournament { } else if let federalTournament = tournament as? FederalTournament {
Button { Button {
_createOrShow(federalTournament: federalTournament, existingTournament: existingTournament, build: build) _createOrShow(federalTournament: federalTournament, existingTournament: existingTournament, build: build)
@ -89,7 +91,9 @@ struct TournamentCellView: View {
Text(tournament.durationLabel()) Text(tournament.durationLabel())
Spacer() Spacer()
if let tournament = tournament as? Tournament { if let tournament = tournament as? Tournament {
Text("équipes") let hasStarted = tournament.inscriptionClosed() || tournament.hasStarted()
let word = hasStarted ? "équipes" : "inscriptions"
Text(word)
} }
} }
Text(tournament.subtitleLabel()) Text(tournament.subtitleLabel())

Loading…
Cancel
Save