Merge branch 'main'

Conflicts:
	PadelClub.xcodeproj/project.pbxproj
clubs
Razmig Sarkissian 1 year ago
commit 893561a280
  1. 36
      PadelClub.xcodeproj/project.pbxproj
  2. 0
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-07-2023.csv
  3. 0
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-08-2023.csv
  4. 0
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-07-2023.csv
  5. 0
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-08-2023.csv
  6. 0
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv
  7. 0
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv
  8. 0
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv
  9. 0
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv
  10. 8
      PadelClub/Data/Coredata/ImportedPlayer+Extensions.swift
  11. 5
      PadelClub/Data/Federal/PlayerHolder.swift
  12. 42
      PadelClub/Data/MonthData.swift
  13. 18
      PadelClub/Extensions/URL+Extensions.swift
  14. 2
      PadelClub/PadelClubApp.swift
  15. 33
      PadelClub/Utils/FileImportManager.swift
  16. 9
      PadelClub/Utils/SourceFileManager.swift
  17. 2
      PadelClub/ViewModel/SearchViewModel.swift
  18. 18
      PadelClub/Views/Components/UnderlineView.swift
  19. 96
      PadelClub/Views/Navigation/MainView.swift
  20. 80
      PadelClub/Views/Navigation/Umpire/PadelClubView.swift
  21. 5
      PadelClub/Views/Shared/ImportedPlayerView.swift
  22. 2
      PadelClub/Views/Tournament/FileImportView.swift
  23. 2
      PadelClub/Views/Tournament/Screen/AddTeamView.swift

@ -121,6 +121,7 @@
FF4AB6BF2B92577A0002987F /* ImportedPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BE2B92577A0002987F /* ImportedPlayerView.swift */; }; FF4AB6BF2B92577A0002987F /* ImportedPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BE2B92577A0002987F /* ImportedPlayerView.swift */; };
FF4C7F022BBBD7150031B6A3 /* TabItemModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C7F012BBBD7150031B6A3 /* TabItemModifier.swift */; }; FF4C7F022BBBD7150031B6A3 /* TabItemModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C7F012BBBD7150031B6A3 /* TabItemModifier.swift */; };
FF53FBB82BFB302B0051D4C3 /* ClubCourtSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF53FBB72BFB302B0051D4C3 /* ClubCourtSetupView.swift */; }; FF53FBB82BFB302B0051D4C3 /* ClubCourtSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF53FBB72BFB302B0051D4C3 /* ClubCourtSetupView.swift */; };
FF558C632C6CDD020071F9AE /* UnderlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF558C622C6CDD020071F9AE /* UnderlineView.swift */; };
FF5647132C0B6F390081F995 /* LoserRoundSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5647122C0B6F380081F995 /* LoserRoundSettingsView.swift */; }; FF5647132C0B6F390081F995 /* LoserRoundSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5647122C0B6F380081F995 /* LoserRoundSettingsView.swift */; };
FF59FFB32B90EFAC0061EFF9 /* EventListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */; }; FF59FFB32B90EFAC0061EFF9 /* EventListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */; };
FF59FFB72B90EFBF0061EFF9 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB62B90EFBF0061EFF9 /* MainView.swift */; }; FF59FFB72B90EFBF0061EFF9 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB62B90EFBF0061EFF9 /* MainView.swift */; };
@ -371,14 +372,14 @@
FF0E0B6C2BC254C6005F00A9 /* TournamentScheduleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentScheduleView.swift; sourceTree = "<group>"; }; FF0E0B6C2BC254C6005F00A9 /* TournamentScheduleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentScheduleView.swift; sourceTree = "<group>"; };
FF0EC51D2BB16F680056B6D1 /* SwiftParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftParser.swift; sourceTree = "<group>"; }; FF0EC51D2BB16F680056B6D1 /* SwiftParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftParser.swift; sourceTree = "<group>"; };
FF0EC5212BB173E70056B6D1 /* UpdateSourceRankDateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateSourceRankDateView.swift; sourceTree = "<group>"; }; FF0EC5212BB173E70056B6D1 /* UpdateSourceRankDateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateSourceRankDateView.swift; sourceTree = "<group>"; };
FF0EC5232BB195CA0056B6D1 /* CLASSEMENT PADEL DAMES-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL DAMES-07-2023.csv"; sourceTree = "<group>"; }; FF0EC5232BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-07-2023.csv"; sourceTree = "<group>"; };
FF0EC5242BB195CA0056B6D1 /* CLASSEMENT PADEL DAMES-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL DAMES-08-2023.csv"; sourceTree = "<group>"; }; FF0EC5242BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-08-2023.csv"; sourceTree = "<group>"; };
FF0EC5252BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_1-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_1-07-2023.csv"; sourceTree = "<group>"; }; FF0EC5252BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-07-2023.csv"; sourceTree = "<group>"; };
FF0EC5262BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_1-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_1-08-2023.csv"; sourceTree = "<group>"; }; FF0EC5262BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-08-2023.csv"; sourceTree = "<group>"; };
FF0EC5272BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_2-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_2-07-2023.csv"; sourceTree = "<group>"; }; FF0EC5272BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv"; sourceTree = "<group>"; };
FF0EC5282BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_2-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_2-08-2023.csv"; sourceTree = "<group>"; }; FF0EC5282BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv"; sourceTree = "<group>"; };
FF0EC5292BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_3-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_3-07-2023.csv"; sourceTree = "<group>"; }; FF0EC5292BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv"; sourceTree = "<group>"; };
FF0EC52A2BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_3-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_3-08-2023.csv"; sourceTree = "<group>"; }; FF0EC52A2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv"; sourceTree = "<group>"; };
FF0EC52B2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-01-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-01-2023.csv"; sourceTree = "<group>"; }; FF0EC52B2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-01-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-01-2023.csv"; sourceTree = "<group>"; };
FF0EC52C2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-02-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-02-2023.csv"; sourceTree = "<group>"; }; FF0EC52C2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-02-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-02-2023.csv"; sourceTree = "<group>"; };
FF0EC52D2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-03-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-03-2023.csv"; sourceTree = "<group>"; }; FF0EC52D2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-03-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-03-2023.csv"; sourceTree = "<group>"; };
@ -462,6 +463,7 @@
FF4AB6BE2B92577A0002987F /* ImportedPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportedPlayerView.swift; sourceTree = "<group>"; }; FF4AB6BE2B92577A0002987F /* ImportedPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportedPlayerView.swift; sourceTree = "<group>"; };
FF4C7F012BBBD7150031B6A3 /* TabItemModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItemModifier.swift; sourceTree = "<group>"; }; FF4C7F012BBBD7150031B6A3 /* TabItemModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItemModifier.swift; sourceTree = "<group>"; };
FF53FBB72BFB302B0051D4C3 /* ClubCourtSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClubCourtSetupView.swift; sourceTree = "<group>"; }; FF53FBB72BFB302B0051D4C3 /* ClubCourtSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClubCourtSetupView.swift; sourceTree = "<group>"; };
FF558C622C6CDD020071F9AE /* UnderlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnderlineView.swift; sourceTree = "<group>"; };
FF5647122C0B6F380081F995 /* LoserRoundSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoserRoundSettingsView.swift; sourceTree = "<group>"; }; FF5647122C0B6F380081F995 /* LoserRoundSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoserRoundSettingsView.swift; sourceTree = "<group>"; };
FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListView.swift; sourceTree = "<group>"; }; FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListView.swift; sourceTree = "<group>"; };
FF59FFB62B90EFBF0061EFF9 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; }; FF59FFB62B90EFBF0061EFF9 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
@ -817,6 +819,7 @@
FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */, FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */,
C4A47D9E2B7D0BCE00ADC637 /* StepperView.swift */, C4A47D9E2B7D0BCE00ADC637 /* StepperView.swift */,
FFCB74162C480411008384D0 /* CopyPasteButtonView.swift */, FFCB74162C480411008384D0 /* CopyPasteButtonView.swift */,
FF558C622C6CDD020071F9AE /* UnderlineView.swift */,
); );
path = Components; path = Components;
sourceTree = "<group>"; sourceTree = "<group>";
@ -864,14 +867,14 @@
FF0EC54D2BB195CA0056B6D1 /* CSV */ = { FF0EC54D2BB195CA0056B6D1 /* CSV */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FF0EC5232BB195CA0056B6D1 /* CLASSEMENT PADEL DAMES-07-2023.csv */, FF0EC5232BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-07-2023.csv */,
FF0EC5242BB195CA0056B6D1 /* CLASSEMENT PADEL DAMES-08-2023.csv */, FF0EC5242BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-08-2023.csv */,
FF0EC5252BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_1-07-2023.csv */, FF0EC5252BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-07-2023.csv */,
FF0EC5262BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_1-08-2023.csv */, FF0EC5262BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-08-2023.csv */,
FF0EC5272BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_2-07-2023.csv */, FF0EC5272BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv */,
FF0EC5282BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_2-08-2023.csv */, FF0EC5282BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv */,
FF0EC5292BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_3-07-2023.csv */, FF0EC5292BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv */,
FF0EC52A2BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_3-08-2023.csv */, FF0EC52A2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv */,
FF0EC52B2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-01-2023.csv */, FF0EC52B2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-01-2023.csv */,
FF0EC52C2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-02-2023.csv */, FF0EC52C2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-02-2023.csv */,
FF0EC52D2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-03-2023.csv */, FF0EC52D2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-03-2023.csv */,
@ -1628,6 +1631,7 @@
FF59FFB32B90EFAC0061EFF9 /* EventListView.swift in Sources */, FF59FFB32B90EFAC0061EFF9 /* EventListView.swift in Sources */,
FF8F263D2BAD627A00650388 /* TournamentConfiguratorView.swift in Sources */, FF8F263D2BAD627A00650388 /* TournamentConfiguratorView.swift in Sources */,
FFC1E10C2BAC7FB0008D6F59 /* ClubImportView.swift in Sources */, FFC1E10C2BAC7FB0008D6F59 /* ClubImportView.swift in Sources */,
FF558C632C6CDD020071F9AE /* UnderlineView.swift in Sources */,
FF3B60A32BC49BBC008C2E66 /* MatchScheduler.swift in Sources */, FF3B60A32BC49BBC008C2E66 /* MatchScheduler.swift in Sources */,
FF11627A2BCF8109000C4809 /* CallMessageCustomizationView.swift in Sources */, FF11627A2BCF8109000C4809 /* CallMessageCustomizationView.swift in Sources */,
FF6087EA2BE25EF1004E1E47 /* TournamentStatusView.swift in Sources */, FF6087EA2BE25EF1004E1E47 /* TournamentStatusView.swift in Sources */,

@ -52,6 +52,14 @@ extension ImportedPlayer: PlayerHolder {
male male
} }
func isNotFromCurrentDate() -> Bool {
if let importDate, importDate != SourceFileManager.shared.lastDataSourceDate() {
return true
} else {
return false
}
}
func hitForSearch(_ searchText: String) -> Int { func hitForSearch(_ searchText: String) -> Int {
var trimmedSearchText = searchText.lowercased().trimmingCharacters(in: .whitespaces).folding(options: .diacriticInsensitive, locale: .current) var trimmedSearchText = searchText.lowercased().trimmingCharacters(in: .whitespaces).folding(options: .diacriticInsensitive, locale: .current)
trimmedSearchText = trimmedSearchText.replaceCharactersFromSet(characterSet: .punctuationCharacters, replacementString: " ") trimmedSearchText = trimmedSearchText.replaceCharactersFromSet(characterSet: .punctuationCharacters, replacementString: " ")

@ -23,9 +23,14 @@ protocol PlayerHolder {
var assimilation: String? { get } var assimilation: String? { get }
var computedAge: Int? { get } var computedAge: Int? { get }
func getAssimilatedAsMaleRank() -> Int? func getAssimilatedAsMaleRank() -> Int?
func isNotFromCurrentDate() -> Bool
} }
extension PlayerHolder { extension PlayerHolder {
func isNotFromCurrentDate() -> Bool {
false
}
var isAssimilated: Bool { var isAssimilated: Bool {
assimilation == "Oui" assimilation == "Oui"
} }

@ -19,33 +19,53 @@ final class MonthData : ModelObject, Storable {
private(set) var id: String = Store.randomId() private(set) var id: String = Store.randomId()
private(set) var monthKey: String private(set) var monthKey: String
private(set) var creationDate: Date var creationDate: Date
var maleUnrankedValue: Int? = nil var maleUnrankedValue: Int? = nil
var femaleUnrankedValue: Int? = nil var femaleUnrankedValue: Int? = nil
var maleCount: Int? = nil var maleCount: Int? = nil
var femaleCount: Int? = nil var femaleCount: Int? = nil
var anonymousCount: Int? = nil var anonymousCount: Int? = nil
var incompleteMode: Bool = false
init(monthKey: String) { init(monthKey: String) {
self.monthKey = monthKey self.monthKey = monthKey
self.creationDate = Date() self.creationDate = Date()
} }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: ._id)
monthKey = try container.decode(String.self, forKey: ._monthKey)
creationDate = try container.decode(Date.self, forKey: ._creationDate)
maleUnrankedValue = try container.decodeIfPresent(Int.self, forKey: ._maleUnrankedValue)
femaleUnrankedValue = try container.decodeIfPresent(Int.self, forKey: ._femaleUnrankedValue)
maleCount = try container.decodeIfPresent(Int.self, forKey: ._maleCount)
femaleCount = try container.decodeIfPresent(Int.self, forKey: ._femaleCount)
anonymousCount = try container.decodeIfPresent(Int.self, forKey: ._anonymousCount)
incompleteMode = try container.decodeIfPresent(Bool.self, forKey: ._incompleteMode) ?? false
}
func total() -> Int { func total() -> Int {
return (maleCount ?? 0) + (femaleCount ?? 0) return (maleCount ?? 0) + (femaleCount ?? 0)
} }
static func calculateCurrentUnrankedValues(mostRecentDateAvailable: Date) async { static func calculateCurrentUnrankedValues(fromDate: Date) async {
let lastDataSourceMaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: mostRecentDateAvailable, man: true)
let lastDataSourceFemaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: mostRecentDateAvailable, man: false) let fftImportingUncomplete = SourceFileManager.shared.allFiles(true).first(where: { $0.dateFromPath == fromDate })?.fftImportingUncomplete()
let anonymousCount = await FederalPlayer.anonymousCount(mostRecentDateAvailable: mostRecentDateAvailable)
let incompleteMode = fftImportingUncomplete != nil
let lastDataSourceMaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: fromDate, man: true)
let lastDataSourceFemaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: fromDate, man: false)
let anonymousCount = await FederalPlayer.anonymousCount(mostRecentDateAvailable: fromDate)
await MainActor.run { await MainActor.run {
if let lastDataSource = DataStore.shared.appSettings.lastDataSource { let lastDataSource = URL.importDateFormatter.string(from: fromDate)
let currentMonthData : MonthData = DataStore.shared.monthData.first(where: { $0.monthKey == lastDataSource }) ?? MonthData(monthKey: lastDataSource) let currentMonthData : MonthData = DataStore.shared.monthData.first(where: { $0.monthKey == lastDataSource }) ?? MonthData(monthKey: lastDataSource)
currentMonthData.maleUnrankedValue = lastDataSourceMaleUnranked?.0 currentMonthData.creationDate = Date()
currentMonthData.maleCount = lastDataSourceMaleUnranked?.1 currentMonthData.maleUnrankedValue = incompleteMode ? 60000 : lastDataSourceMaleUnranked?.0
currentMonthData.incompleteMode = incompleteMode
currentMonthData.maleCount = incompleteMode ? fftImportingUncomplete : lastDataSourceMaleUnranked?.1
currentMonthData.femaleUnrankedValue = lastDataSourceFemaleUnranked?.0 currentMonthData.femaleUnrankedValue = lastDataSourceFemaleUnranked?.0
currentMonthData.femaleCount = lastDataSourceFemaleUnranked?.1 currentMonthData.femaleCount = lastDataSourceFemaleUnranked?.1
currentMonthData.anonymousCount = anonymousCount currentMonthData.anonymousCount = anonymousCount
@ -56,7 +76,6 @@ final class MonthData : ModelObject, Storable {
} }
} }
} }
}
override func deleteDependencies() throws { override func deleteDependencies() throws {
} }
@ -70,5 +89,6 @@ final class MonthData : ModelObject, Storable {
case _maleCount = "maleCount" case _maleCount = "maleCount"
case _femaleCount = "femaleCount" case _femaleCount = "femaleCount"
case _anonymousCount = "anonymousCount" case _anonymousCount = "anonymousCount"
case _incompleteMode = "incompleteMode"
} }
} }

@ -51,6 +51,24 @@ extension URL {
} }
extension URL { extension URL {
func fftImportingUncomplete() -> Int? {
// Read the contents of the file
guard let fileContents = try? String(contentsOfFile: path(), encoding: .utf8) else {
return nil
}
// Split the contents by newline characters
let lines = fileContents.components(separatedBy: .newlines)
if let line = lines.first(where: {
$0.hasPrefix("max-players:")
}) {
return Int(line.replacingOccurrences(of: "max-players:", with: ""))
}
return nil
}
func getUnrankedValue() -> Int? { func getUnrankedValue() -> Int? {
// Read the contents of the file // Read the contents of the file
guard let fileContents = try? String(contentsOfFile: path(), encoding: .utf8) else { guard let fileContents = try? String(contentsOfFile: path(), encoding: .utf8) else {

@ -16,6 +16,7 @@ struct PadelClubApp: App {
@StateObject var networkMonitor: NetworkMonitor = NetworkMonitor() @StateObject var networkMonitor: NetworkMonitor = NetworkMonitor()
@StateObject var dataStore = DataStore.shared @StateObject var dataStore = DataStore.shared
@State private var registrationError: RegistrationError? = nil @State private var registrationError: RegistrationError? = nil
@State private var importObserverViewModel = ImportObserver()
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@ -69,6 +70,7 @@ struct PadelClubApp: App {
} }
.environmentObject(networkMonitor) .environmentObject(networkMonitor)
.environmentObject(dataStore) .environmentObject(dataStore)
.environment(importObserverViewModel)
.environment(navigationViewModel) .environment(navigationViewModel)
.accentColor(.master) .accentColor(.master)
.onAppear { .onAppear {

@ -7,6 +7,7 @@
import Foundation import Foundation
import LeStorage import LeStorage
import SwiftUI
enum FileImportManagerError: LocalizedError { enum FileImportManagerError: LocalizedError {
case unknownFormat case unknownFormat
@ -19,15 +20,36 @@ enum FileImportManagerError: LocalizedError {
} }
} }
@Observable
class ImportObserver {
var checkingFilesAttempt: Int = 0
var checkingFiles: Bool = false
var willCheckDataIntegrity: Bool = false
func currentlyImportingLabel() -> String {
guard let currentImportDate else { return "import en cours" }
if URL.importDateFormatter.string(from: currentImportDate) == "07-2024" {
return "consolidation des données"
}
return "import " + currentImportDate.monthYearFormatted
}
var currentImportDate: Date? = nil
func isImportingFile() -> Bool {
currentImportDate != nil
}
}
class FileImportManager { class FileImportManager {
static let shared = FileImportManager() static let shared = FileImportManager()
func updatePlayers(isMale: Bool, players: inout [FederalPlayer]) { func updatePlayers(isMale: Bool, players: inout [FederalPlayer]) {
guard let mostRecentDateAvailable = URL.importDateFormatter.date(from: "05-2024") else { return }
let replacements: [(Character, Character)] = [("Á", "ç"), ("", "à"), ("Ù", "ô"), ("Ë", "è"), ("Ó", "î"), ("Î", "ë"), ("", "É"), ("Ô", "ï"), ("È", "é"), ("«", "Ç"), ("»", "È")] let replacements: [(Character, Character)] = [("Á", "ç"), ("", "à"), ("Ù", "ô"), ("Ë", "è"), ("Ó", "î"), ("Î", "ë"), ("", "É"), ("Ô", "ï"), ("È", "é"), ("«", "Ç"), ("»", "È")]
var playersLeft = players var playersLeft = players
SourceFileManager.shared.allFilesSortedByDate(isMale).filter({ $0.dateFromPath.isEarlierThan(mostRecentDateAvailable) }).forEach({ url in SourceFileManager.shared.allFilesSortedByDate(isMale).forEach({ url in
if playersLeft.isEmpty == false { if playersLeft.isEmpty == false {
let federalPlayers = readCSV(inputFile: url) let federalPlayers = readCSV(inputFile: url)
let replacementsCharacters = url.dateFromPath.monthYearFormatted != "04-2024" ? [] : replacements let replacementsCharacters = url.dateFromPath.monthYearFormatted != "04-2024" ? [] : replacements
@ -170,18 +192,15 @@ class FileImportManager {
} }
} }
func importDataFromFFT() async -> String? { func importDataFromFFT(importingDate: Date) async -> String? {
if let importingDate = SourceFileManager.shared.mostRecentDateAvailable {
for source in SourceFile.allCases { for source in SourceFile.allCases {
for fileURL in source.currentURLs { for fileURL in source.currentURLs(importingDate: importingDate) {
let p = readCSV(inputFile: fileURL) let p = readCSV(inputFile: fileURL)
await importingChunkOfPlayers(p, importingDate: importingDate) await importingChunkOfPlayers(p, importingDate: importingDate)
} }
} }
return URL.importDateFormatter.string(from: importingDate) return URL.importDateFormatter.string(from: importingDate)
} }
return nil
}
func readCSV(inputFile: URL) -> [FederalPlayer] { func readCSV(inputFile: URL) -> [FederalPlayer] {

@ -204,18 +204,13 @@ enum SourceFile: String, CaseIterable {
return allFiles.filter{$0.pathExtension == "csv" && $0.path().contains(rawValue)} return allFiles.filter{$0.pathExtension == "csv" && $0.path().contains(rawValue)}
} }
var currentURLs: [URL] { func currentURLs(importingDate: Date) -> [URL] {
var files = Bundle.main.urls(forResourcesWithExtension: "csv", subdirectory: nil)?.filter({ url in var files = Bundle.main.urls(forResourcesWithExtension: "csv", subdirectory: nil)?.filter({ url in
url.path().contains(rawValue) url.path().contains(rawValue)
}) ?? [] }) ?? []
files.append(contentsOf: filesFromServer) files.append(contentsOf: filesFromServer)
return files.filter({ $0.dateFromPath == importingDate })
if let mostRecent = files.sorted(by: \.dateFromPath).reversed().first {
return files.filter({ $0.dateFromPath == mostRecent.dateFromPath })
} else {
return []
}
} }
var isMan: Bool { var isMan: Bool {

@ -215,7 +215,7 @@ class SearchViewModel: ObservableObject, Identifiable {
] ]
if let mostRecentDate { if let mostRecentDate {
predicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg)) //predicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg))
} }
if hideAssimilation { if hideAssimilation {

@ -0,0 +1,18 @@
//
// UnderlineView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 14/08/2024.
//
import SwiftUI
struct UnderlineView: View {
var body: some View {
Rectangle()
.stroke(style: StrokeStyle(lineWidth: 2, dash: [2, 2]))
.frame(height: 2) // Height of the dashed line
.foregroundColor(.blue)
.offset(y: 10) // Offset to position the dashed line below the text
}
}

@ -13,11 +13,9 @@ struct MainView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(\.requestReview) var requestReview @Environment(\.requestReview) var requestReview
@AppStorage("importingFiles") var importingFiles: Bool = false
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@Environment(ImportObserver.self) private var importObserver: ImportObserver
@State private var checkingFilesAttempt: Int = 0
@State private var checkingFiles: Bool = false
@State private var mainViewId: UUID = UUID() @State private var mainViewId: UUID = UUID()
var lastDataSource: String? { var lastDataSource: String? {
@ -61,13 +59,12 @@ struct MainView: View {
ActivityView() ActivityView()
.tabItem(for: .activity) .tabItem(for: .activity)
.onAppear { .onAppear {
if lastDataSource == nil, checkingFiles == false, importingFiles == false { print("on appear main view")
Task { if importObserver.willCheckDataIntegrity == false {
await self._checkSourceFileAvailability() importObserver.willCheckDataIntegrity = true
} DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
} else if let lastDataSource, lastDataSource != URL.importDateFormatter.string(from: Date()), checkingFiles == false, importingFiles == false { _checkingDataIntegrity()
Task { importObserver.willCheckDataIntegrity = false
await self._checkSourceFileAvailability()
} }
} }
@ -97,6 +94,8 @@ struct MainView: View {
} }
.id(mainViewId) .id(mainViewId)
.onChange(of: dataStore.user.id) { .onChange(of: dataStore.user.id) {
print("dataStore.user.id", dataStore.user.id)
print("StoreCenter.main.userId", StoreCenter.main.userId)
if StoreCenter.main.userId == nil { // user disconnected if StoreCenter.main.userId == nil { // user disconnected
navigation.path.removeLast(navigation.path.count) navigation.path.removeLast(navigation.path.count)
mainViewId = UUID() mainViewId = UUID()
@ -133,7 +132,7 @@ struct MainView: View {
// } // }
// } // }
.overlay(alignment: .bottom) { .overlay(alignment: .bottom) {
if importingFiles { if importObserver.isImportingFile() {
_activityStatusBoxView() _activityStatusBoxView()
} else { } else {
_activityStatusBoxView() _activityStatusBoxView()
@ -158,15 +157,11 @@ struct MainView: View {
@ViewBuilder @ViewBuilder
func _activityStatus() -> some View { func _activityStatus() -> some View {
if importingFiles { if importObserver.isImportingFile() {
HStack(spacing: 20) { HStack(spacing: 20) {
ProgressView() ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: Color.black)) .progressViewStyle(CircularProgressViewStyle(tint: Color.black))
if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable { Text(importObserver.currentlyImportingLabel())
if mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast {
Text("import " + mostRecentDateAvailable.monthYearFormatted)
}
}
} }
} else if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, let lastDataSourceDate = SourceFileManager.shared.lastDataSourceDate() { } else if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, let lastDataSourceDate = SourceFileManager.shared.lastDataSourceDate() {
if mostRecentDateAvailable > lastDataSourceDate { if mostRecentDateAvailable > lastDataSourceDate {
@ -184,35 +179,80 @@ struct MainView: View {
print("check internet") print("check internet")
print("check files on internet") print("check files on internet")
print("check if any files on internet are more recent than here") print("check if any files on internet are more recent than here")
checkingFiles = true importObserver.checkingFiles = true
await SourceFileManager.shared.fetchData() await SourceFileManager.shared.fetchData()
checkingFilesAttempt += 1 importObserver.checkingFilesAttempt += 1
checkingFiles = false importObserver.checkingFiles = false
if lastDataSource == nil || (dataStore.monthData.first(where: { $0.monthKey == "07-2024" }) == nil) {
await _downloadPreviousDate()
await _importMandatoryData()
}
if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast { if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast {
_startImporting()
print("importing \(mostRecentDateAvailable)")
await _startImporting(importingDate: mostRecentDateAvailable)
} }
} }
private func _startImporting() { private func _startImporting(importingDate: Date) async {
importingFiles = true
Task {
let lastDataSource = await FileImportManager.shared.importDataFromFFT()
await MainActor.run { await MainActor.run {
importingFiles = false importObserver.currentImportDate = importingDate
} }
let lastDataSource = await FileImportManager.shared.importDataFromFFT(importingDate: importingDate)
dataStore.appSettings.lastDataSource = lastDataSource dataStore.appSettings.lastDataSource = lastDataSource
dataStore.appSettingsStorage.write() dataStore.appSettingsStorage.write()
if let lastDataSource, let mostRecentDate = URL.importDateFormatter.date(from: lastDataSource) { await _calculateMonthData(dataSource: lastDataSource)
await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: mostRecentDate) await MainActor.run {
importObserver.currentImportDate = nil
} }
await _downloadPreviousDate() await _downloadPreviousDate()
} }
private func _calculateMonthData(dataSource: String?) async {
if let dataSource, let mostRecentDate = URL.importDateFormatter.date(from: dataSource) {
await MonthData.calculateCurrentUnrankedValues(fromDate: mostRecentDate)
}
} }
private func _downloadPreviousDate() async { private func _downloadPreviousDate() async {
await SourceFileManager.shared.getAllFiles(initialDate: "05-2024") await SourceFileManager.shared.getAllFiles(initialDate: "05-2024")
} }
private func _importMandatoryData() async {
let mandatoryKey = "07-2024"
if dataStore.monthData.first(where: { $0.monthKey == mandatoryKey }) == nil, let importingDate = URL.importDateFormatter.date(from: mandatoryKey) {
print("importing mandatory july data")
await _startImporting(importingDate: importingDate)
}
}
private func _checkingDataIntegrity() {
if lastDataSource == nil, importObserver.checkingFiles == false, importObserver.isImportingFile() == false {
Task {
await self._checkSourceFileAvailability()
}
} else if let lastDataSource, lastDataSource != URL.importDateFormatter.string(from: Date()), importObserver.checkingFiles == false, importObserver.isImportingFile() == false {
Task {
await self._checkSourceFileAvailability()
}
} else if let lastDataSource, lastDataSource == "08-2024" {
let monthData = dataStore.monthData.sorted(by: \.creationDate)
if let current = monthData.last, current.monthKey == "08-2024", current.incompleteMode == false {
Task {
await _calculateMonthData(dataSource: current.monthKey)
}
}
if monthData.first(where: { $0.monthKey == "07-2024" }) == nil, importObserver.isImportingFile() == false, importObserver.checkingFiles == false {
Task {
await _checkSourceFileAvailability()
}
}
}
}
} }
//#Preview { //#Preview {

@ -10,10 +10,6 @@ import LeStorage
struct PadelClubView: View { struct PadelClubView: View {
@State private var uuid: UUID = UUID() @State private var uuid: UUID = UUID()
@State private var checkingFilesAttempt: Int = 0
@State private var checkingFiles: Bool = false
@AppStorage("importingFiles") var importingFiles: Bool = false
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
var lastDataSource: String? { var lastDataSource: String? {
@ -21,6 +17,7 @@ struct PadelClubView: View {
} }
@Environment(\.managedObjectContext) private var viewContext @Environment(\.managedObjectContext) private var viewContext
@Environment(ImportObserver.self) private var importObserver: ImportObserver
@FetchRequest( @FetchRequest(
sortDescriptors: [], sortDescriptors: [],
@ -38,7 +35,22 @@ struct PadelClubView: View {
var body: some View { var body: some View {
List { List {
#if targetEnvironment(simulator) let monthData = dataStore.monthData.sorted(by: \.creationDate).reversed()
if let currentMonth = monthData.first, currentMonth.incompleteMode {
Section {
Text("Attention, depuis Août 2024, les données fédérales publiques des joueurs (messieurs) récupérables sont incomplètes car limité au 40.000 premiers joueurs. Le rang d'un joueur non-classé n'est donc pas calculable pour le moment, Padel Club utilisera une valeur par défaut de de 60.000.")
Text("Un classement souligné comme ci-dessous indiquera que l'information provient d'un mois précédent.")
Text("10342ème")
.background {
UnderlineView()
}
}
}
#if DEBUG
/* /*
["36435", "BOUNOUA", "walid", "France", "3311600", "15,00", "Non", "2", "AUVERGNE RHONE-ALPES", "50 73 0046", "CHAMBERY TC"] ["36435", "BOUNOUA", "walid", "France", "3311600", "15,00", "Non", "2", "AUVERGNE RHONE-ALPES", "50 73 0046", "CHAMBERY TC"]
["36435", "BRUL…", "Romain", "France", "2993139", "15,00", "Non", "2", "NOUVELLE AQUITAINE", "59 33 0447", "SAINT LOUBES TC"] ["36435", "BRUL…", "Romain", "France", "2993139", "15,00", "Non", "2", "NOUVELLE AQUITAINE", "59 33 0447", "SAINT LOUBES TC"]
@ -83,7 +95,7 @@ struct PadelClubView: View {
} }
} }
if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, _lastDataSourceDate.isEarlierThan(mostRecentDateAvailable), importingFiles == false { if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, _lastDataSourceDate.isEarlierThan(mostRecentDateAvailable), importObserver.isImportingFile() == false {
Section { Section {
RowButtonView("Importer \(mostRecentDateAvailable.monthYearFormatted)") { RowButtonView("Importer \(mostRecentDateAvailable.monthYearFormatted)") {
_startImporting() _startImporting()
@ -100,7 +112,7 @@ struct PadelClubView: View {
Text("Padel Club va récupérer les données des mois précédents") Text("Padel Club va récupérer les données des mois précédents")
} }
if importingFiles { if importObserver.isImportingFile() {
ContentUnavailableView("Importation en cours", systemImage: "server.rack", description: Text("Une importation des données fédérales publiques est en cours, veuillez patienter.")) ContentUnavailableView("Importation en cours", systemImage: "server.rack", description: Text("Une importation des données fédérales publiques est en cours, veuillez patienter."))
} else if (players.isEmpty || lastDataSource == nil) { } else if (players.isEmpty || lastDataSource == nil) {
ContentUnavailableView { ContentUnavailableView {
@ -116,7 +128,6 @@ struct PadelClubView: View {
} }
} }
let monthData = dataStore.monthData.sorted(by: \.creationDate).reversed()
ForEach(monthData) { monthData in ForEach(monthData) { monthData in
Section { Section {
LabeledContent { LabeledContent {
@ -134,13 +145,15 @@ struct PadelClubView: View {
Text("Dames") Text("Dames")
} }
// LabeledContent { if monthData.incompleteMode {
// if let anonymousCount = monthData.anonymousCount { LabeledContent {
// Text(anonymousCount.formatted()) if let anonymousCount = monthData.anonymousCount {
// } Text(anonymousCount.formatted())
// } label: { }
// Text("Joueurs anonymes") } label: {
// } Text("Joueurs anonymes")
}
}
LabeledContent { LabeledContent {
if let maleUnrankedValue = monthData.maleUnrankedValue { if let maleUnrankedValue = monthData.maleUnrankedValue {
@ -148,8 +161,12 @@ struct PadelClubView: View {
} }
} label: { } label: {
Text("Rang d'un non classé") Text("Rang d'un non classé")
if monthData.incompleteMode {
Text("Messieurs (estimation car incomplet)")
} else {
Text("Messieurs") Text("Messieurs")
} }
}
LabeledContent { LabeledContent {
if let femaleUnrankedValue = monthData.femaleUnrankedValue { if let femaleUnrankedValue = monthData.femaleUnrankedValue {
Text(femaleUnrankedValue.formatted()) Text(femaleUnrankedValue.formatted())
@ -170,7 +187,7 @@ struct PadelClubView: View {
FooterButtonView("recalculer") { FooterButtonView("recalculer") {
Task { Task {
if let monthKeyDate = URL.importDateFormatter.date(from: monthData.monthKey) { if let monthKeyDate = URL.importDateFormatter.date(from: monthData.monthKey) {
await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: monthKeyDate) await MonthData.calculateCurrentUnrankedValues(fromDate: monthKeyDate)
} }
} }
} }
@ -193,14 +210,10 @@ struct PadelClubView: View {
@ViewBuilder @ViewBuilder
func _activityStatus() -> some View { func _activityStatus() -> some View {
if checkingFiles || importingFiles { if importObserver.checkingFiles || importObserver.isImportingFile() {
HStack(spacing: 20) { HStack(spacing: 20) {
ProgressView() ProgressView()
if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable { Text(importObserver.currentlyImportingLabel())
if mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast {
Text("import " + mostRecentDateAvailable.monthYearFormatted)
}
}
} }
} else if let _mostRecentDateAvailable { } else if let _mostRecentDateAvailable {
if _mostRecentDateAvailable > _lastDataSourceDate ?? .distantPast { if _mostRecentDateAvailable > _lastDataSourceDate ?? .distantPast {
@ -218,27 +231,30 @@ struct PadelClubView: View {
print("check internet") print("check internet")
print("check files on internet") print("check files on internet")
print("check if any files on internet are more recent than here") print("check if any files on internet are more recent than here")
checkingFiles = true importObserver.checkingFiles = true
await SourceFileManager.shared.fetchData() await SourceFileManager.shared.fetchData()
checkingFilesAttempt += 1 importObserver.checkingFilesAttempt += 1
checkingFiles = false importObserver.checkingFiles = false
uuid = UUID() //uuid = UUID()
} }
private func _startImporting() { private func _startImporting() {
importingFiles = true let importingDate = SourceFileManager.shared.mostRecentDateAvailable
importObserver.currentImportDate = importingDate
Task { Task {
let lastDataSource = await FileImportManager.shared.importDataFromFFT() if let importingDate {
await MainActor.run { let lastDataSource = await FileImportManager.shared.importDataFromFFT(importingDate: importingDate)
importingFiles = false
}
dataStore.appSettings.lastDataSource = lastDataSource dataStore.appSettings.lastDataSource = lastDataSource
dataStore.appSettingsStorage.write() dataStore.appSettingsStorage.write()
if let lastDataSource, let mostRecentDate = URL.importDateFormatter.date(from: lastDataSource) { if let lastDataSource, let mostRecentDate = URL.importDateFormatter.date(from: lastDataSource) {
await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: mostRecentDate) await MonthData.calculateCurrentUnrankedValues(fromDate: mostRecentDate)
} }
viewContext.refreshAllObjects() viewContext.refreshAllObjects()
} }
await MainActor.run {
importObserver.currentImportDate = nil
}
}
} }
private func _downloadPreviousDate() async { private func _downloadPreviousDate() async {

@ -42,6 +42,11 @@ struct ImportedPlayerView: View {
HStack(alignment: .top, spacing: 0) { HStack(alignment: .top, spacing: 0) {
Text(player.formattedRank()).italic(player.isAssimilated) Text(player.formattedRank()).italic(player.isAssimilated)
.font(.title3) .font(.title3)
.background {
if player.isNotFromCurrentDate() {
UnderlineView()
}
}
if let rank = player.getRank() { if let rank = player.getRank() {
Text(rank.ordinalFormattedSuffix()).italic(player.isAssimilated) Text(rank.ordinalFormattedSuffix()).italic(player.isAssimilated)
.font(.caption) .font(.caption)

@ -484,7 +484,7 @@ struct FileImportView: View {
teams.removeAll() teams.removeAll()
} }
if let rankSourceDate = tournament.rankSourceDate, tournament.unrankValue(for: false) == nil || tournament.unrankValue(for: true) == nil { if let rankSourceDate = tournament.rankSourceDate, tournament.unrankValue(for: false) == nil || tournament.unrankValue(for: true) == nil {
await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: rankSourceDate) await MonthData.calculateCurrentUnrankedValues(fromDate: rankSourceDate)
} }
let event: Event? = tournament.eventObject() let event: Event? = tournament.eventObject()

@ -205,7 +205,7 @@ struct AddTeamView: View {
} }
if let mostRecentDate { if let mostRecentDate {
andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg)) //andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg))
} }
if nameComponents.count > 1 { if nameComponents.count > 1 {

Loading…
Cancel
Save