Merge branch 'main'

Conflicts:
	PadelClub.xcodeproj/project.pbxproj
clubs
Raz 1 year ago
commit 70f398e226
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 15
      PadelClub/Data/MonthData.swift
  3. 2
      PadelClub/Data/PlayerRegistration.swift
  4. 2
      PadelClub/Data/TeamRegistration.swift
  5. 2
      PadelClub/Extensions/Date+Extensions.swift
  6. 56
      PadelClub/Extensions/URL+Extensions.swift
  7. 2
      PadelClub/Utils/FileImportManager.swift
  8. 48
      PadelClub/Utils/Network/NetworkManager.swift
  9. 2
      PadelClub/Utils/Network/NetworkManagerError.swift
  10. 41
      PadelClub/Utils/SourceFileManager.swift
  11. 2
      PadelClub/Views/Components/StepperView.swift
  12. 34
      PadelClub/Views/Navigation/MainView.swift
  13. 30
      PadelClub/Views/Navigation/Umpire/PadelClubView.swift
  14. 37
      PadelClub/Views/Tournament/Screen/AddTeamView.swift

@ -1939,7 +1939,7 @@
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2; CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
@ -1989,7 +1989,7 @@
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2; CURRENT_PROJECT_VERSION = 7;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -19,7 +19,7 @@ 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
var creationDate: Date private(set) 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
@ -32,6 +32,10 @@ final class MonthData : ModelObject, Storable {
self.creationDate = Date() self.creationDate = Date()
} }
fileprivate func _updateCreationDate() {
self.creationDate = Date()
}
required init(from decoder: Decoder) throws { required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: ._id) id = try container.decode(String.self, forKey: ._id)
@ -52,7 +56,10 @@ final class MonthData : ModelObject, Storable {
static func calculateCurrentUnrankedValues(fromDate: Date) async { static func calculateCurrentUnrankedValues(fromDate: Date) async {
let fftImportingUncomplete = SourceFileManager.shared.allFiles(true).first(where: { $0.dateFromPath == fromDate })?.fftImportingUncomplete() let fileURL = SourceFileManager.shared.allFiles(true).first(where: { $0.dateFromPath == fromDate && $0.index == 0 })
print("calculateCurrentUnrankedValues", fromDate.monthYearFormatted, fileURL?.path())
let fftImportingUncomplete = fileURL?.fftImportingUncomplete()
let fftImportingMaleUnrankValue = fileURL?.fftImportingMaleUnrankValue()
let incompleteMode = fftImportingUncomplete != nil let incompleteMode = fftImportingUncomplete != nil
@ -62,8 +69,8 @@ final class MonthData : ModelObject, Storable {
await MainActor.run { await MainActor.run {
let lastDataSource = URL.importDateFormatter.string(from: fromDate) 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.creationDate = Date() currentMonthData._updateCreationDate()
currentMonthData.maleUnrankedValue = incompleteMode ? 60000 : lastDataSourceMaleUnranked?.0 currentMonthData.maleUnrankedValue = incompleteMode ? fftImportingMaleUnrankValue : lastDataSourceMaleUnranked?.0
currentMonthData.incompleteMode = incompleteMode currentMonthData.incompleteMode = incompleteMode
currentMonthData.maleCount = incompleteMode ? fftImportingUncomplete : lastDataSourceMaleUnranked?.1 currentMonthData.maleCount = incompleteMode ? fftImportingUncomplete : lastDataSourceMaleUnranked?.1
currentMonthData.femaleUnrankedValue = lastDataSourceFemaleUnranked?.0 currentMonthData.femaleUnrankedValue = lastDataSourceFemaleUnranked?.0

@ -281,7 +281,7 @@ final class PlayerRegistration: ModelObject, Storable {
} }
func setComputedRank(in tournament: Tournament) { func setComputedRank(in tournament: Tournament) {
let currentRank = rank ?? tournament.unrankValue(for: isMalePlayer()) ?? 100_000 let currentRank = rank ?? tournament.unrankValue(for: isMalePlayer()) ?? 70_000
switch tournament.tournamentCategory { switch tournament.tournamentCategory {
case .men: case .men:
computedRank = isMalePlayer() ? currentRank : currentRank + PlayerRegistration.addon(for: currentRank, manMax: tournament.maleUnrankedValue ?? 0, womanMax: tournament.femaleUnrankedValue ?? 0) computedRank = isMalePlayer() ? currentRank : currentRank + PlayerRegistration.addon(for: currentRank, manMax: tournament.maleUnrankedValue ?? 0, womanMax: tournament.femaleUnrankedValue ?? 0)

@ -478,7 +478,7 @@ final class TeamRegistration: ModelObject, Storable {
} }
func unrankValue(for malePlayer: Bool) -> Int { func unrankValue(for malePlayer: Bool) -> Int {
return tournamentObject()?.unrankValue(for: malePlayer) ?? 100_000 return tournamentObject()?.unrankValue(for: malePlayer) ?? 70_000
} }
func groupStageObject() -> GroupStage? { func groupStageObject() -> GroupStage? {

@ -215,7 +215,7 @@ extension Date {
extension Date { extension Date {
func isEarlierThan(_ date: Date) -> Bool { func isEarlierThan(_ date: Date) -> Bool {
self < date Calendar.current.compare(self, to: date, toGranularity: .minute) == .orderedAscending
} }
} }

@ -51,6 +51,62 @@ extension URL {
} }
extension URL { extension URL {
func creationDate() -> Date? {
// Use FileManager to retrieve the file attributes
do {
let fileAttributes = try FileManager.default.attributesOfItem(atPath: self.path())
// Access the creationDate from the file attributes
if let creationDate = fileAttributes[.creationDate] as? Date {
print("File creationDate: \(creationDate)")
return creationDate
} else {
print("creationDate not found.")
}
} catch {
print("Error retrieving file attributes: \(error.localizedDescription)")
}
return nil
}
func fftImportingStatus() -> 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)
//0 means no need to reimport, just recalc
//1 or missing means re-import
if let line = lines.first(where: {
$0.hasPrefix("import-status:")
}) {
return Int(line.replacingOccurrences(of: "import-status:", with: ""))
}
return nil
}
func fftImportingMaleUnrankValue() -> 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("unrank-male-value:")
}) {
return Int(line.replacingOccurrences(of: "unrank-male-value:", with: ""))
}
return nil
}
func fftImportingUncomplete() -> Int? { func fftImportingUncomplete() -> 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 {

@ -147,7 +147,7 @@ class FileImportManager {
} }
let significantPlayerCount = 2 let significantPlayerCount = 2
let pl = players.prefix(significantPlayerCount).map { $0.computedRank } 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) let missingPl = (missing.map { tournament.unrankValue(for: $0 == 1 ? true : false ) ?? ($0 == 1 ? 70_000 : 10_000) }).prefix(significantPlayerCount)
self.weight = pl.reduce(0,+) + missingPl.reduce(0,+) 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,+)

@ -18,7 +18,34 @@ class NetworkManager {
try? FileManager.default.removeItem(at: destinationFileUrl) try? FileManager.default.removeItem(at: destinationFileUrl)
} }
func downloadRankingData(lastDateString: String, fileName: String) async throws { // func headerDataRankingData(lastDateString: String, fileName: String) async throws {
// let dateString = ["CLASSEMENT-PADEL", fileName, lastDateString].joined(separator: "-") + ".csv"
//
// let documentsUrl: URL = SourceFileManager.shared.rankingSourceDirectory
// let destinationFileUrl = documentsUrl.appendingPathComponent("\(dateString)")
// let fileURL = URL(string: "https://xlr.alwaysdata.net/static/rankings/\(dateString)")
//
// var request = URLRequest(url:fileURL!)
// request.httpMethod = "HEAD"
// request.addValue("attachment;filename=\(dateString)", forHTTPHeaderField:"Content-Disposition")
// request.addValue("text/csv", forHTTPHeaderField: "Content-Type")
// let task = try await URLSession.shared.dataTask(with: request)
// if let urlResponse = task.1 as? HTTPURLResponse {
// print(urlResponse.allHeaderFields)
// }
// }
//
func formatDateForHTTPHeader(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss 'GMT'"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0) // GMT timezone
return formatter.string(from: date)
}
@discardableResult
func downloadRankingData(lastDateString: String, fileName: String) async throws -> Int? {
let dateString = ["CLASSEMENT-PADEL", fileName, lastDateString].joined(separator: "-") + ".csv" let dateString = ["CLASSEMENT-PADEL", fileName, lastDateString].joined(separator: "-") + ".csv"
@ -26,15 +53,16 @@ class NetworkManager {
let destinationFileUrl = documentsUrl.appendingPathComponent("\(dateString)") let destinationFileUrl = documentsUrl.appendingPathComponent("\(dateString)")
let fileURL = URL(string: "https://xlr.alwaysdata.net/static/rankings/\(dateString)") let fileURL = URL(string: "https://xlr.alwaysdata.net/static/rankings/\(dateString)")
if FileManager.default.fileExists(atPath: destinationFileUrl.path()) {
return
}
var request = URLRequest(url:fileURL!) var request = URLRequest(url:fileURL!)
request.addValue("attachment;filename=\(dateString)", forHTTPHeaderField:"Content-Disposition") request.addValue("attachment;filename=\(dateString)", forHTTPHeaderField:"Content-Disposition")
if FileManager.default.fileExists(atPath: destinationFileUrl.path()), let modificationDate = destinationFileUrl.creationDate() {
request.addValue(formatDateForHTTPHeader(modificationDate), forHTTPHeaderField: "If-Modified-Since")
}
request.addValue("text/csv", forHTTPHeaderField: "Content-Type") request.addValue("text/csv", forHTTPHeaderField: "Content-Type")
let task = try await URLSession.shared.download(for: request) let task = try await URLSession.shared.download(for: request)
if let urlResponse = task.1 as? HTTPURLResponse { if let urlResponse = task.1 as? HTTPURLResponse {
print(dateString, urlResponse.statusCode)
if urlResponse.statusCode == 200 { if urlResponse.statusCode == 200 {
//todo à voir si on en a besoin, permet de re-télécharger un csv si on détecte qu'il a été mis à jour //todo à voir si on en a besoin, permet de re-télécharger un csv si on détecte qu'il a été mis à jour
@ -47,14 +75,22 @@ class NetworkManager {
// } // }
// } // }
// } // }
try? FileManager.default.removeItem(at: destinationFileUrl)
try FileManager.default.copyItem(at: task.0, to: destinationFileUrl) try FileManager.default.copyItem(at: task.0, to: destinationFileUrl)
print("dl rank data ok", lastDateString, fileName) print("dl rank data ok", lastDateString, fileName)
return destinationFileUrl.fftImportingStatus() ?? 1
} else if urlResponse.statusCode == 404 && fileName == "MESSIEURS" { } else if urlResponse.statusCode == 404 && fileName == "MESSIEURS" {
print("dl rank data failed", lastDateString, fileName) print("dl rank data failedm fileNotYetAvailable", lastDateString, fileName)
throw NetworkManagerError.fileNotYetAvailable throw NetworkManagerError.fileNotYetAvailable
} else if urlResponse.statusCode == 304 {
print("dl rank data failed, fileNotModified", lastDateString, fileName)
throw NetworkManagerError.fileNotModified
} else {
print("dl rank data failed, fileNotDownloaded", lastDateString, fileName, urlResponse.statusCode)
throw NetworkManagerError.fileNotDownloaded(urlResponse.statusCode)
} }
} }
return nil
} }
func checkFileCreationDate(filePath: String) throws -> Date? { func checkFileCreationDate(filePath: String) throws -> Date? {

@ -14,6 +14,8 @@ enum NetworkManagerError: LocalizedError {
case mailNotSent //no network no error case mailNotSent //no network no error
case messageFailed case messageFailed
case messageNotSent //no network no error case messageNotSent //no network no error
case fileNotModified
case fileNotDownloaded(Int)
var errorDescription: String? { var errorDescription: String? {
switch self { switch self {

@ -80,16 +80,39 @@ class SourceFileManager {
} }
} }
func fetchData(fromDate current: Date) async { actor SourceFileDownloadTracker {
var _downloadedFileStatus : Int? = nil
func updateIfNecessary(with successState: Int?) {
if successState != nil && (_downloadedFileStatus == nil || _downloadedFileStatus == 0) {
_downloadedFileStatus = successState
}
}
func getDownloadedFileStatus() -> Int? {
return _downloadedFileStatus
}
}
//return nil if no new files
//return 1 if new file to import
//return 0 if new file just to re-calc static data, no need to re-import
@discardableResult
func fetchData(fromDate current: Date) async -> Int? {
let lastStringDate = URL.importDateFormatter.string(from: current) let lastStringDate = URL.importDateFormatter.string(from: current)
let files = ["MESSIEURS", "MESSIEURS-2", "MESSIEURS-3", "MESSIEURS-4", "DAMES"] let files = ["MESSIEURS", "MESSIEURS-2", "MESSIEURS-3", "MESSIEURS-4", "DAMES"]
let sourceFileDownloadTracker = SourceFileDownloadTracker()
do { do {
try await withThrowingTaskGroup(of: Void.self) { group in // Mark 1 try await withThrowingTaskGroup(of: Void.self) { group in // Mark 1
for file in files { for file in files {
group.addTask { group.addTask { [sourceFileDownloadTracker] in
try await NetworkManager.shared.downloadRankingData(lastDateString: lastStringDate, fileName: file) let success = try await NetworkManager.shared.downloadRankingData(lastDateString: lastStringDate, fileName: file)
await sourceFileDownloadTracker.updateIfNecessary(with: success)
} }
} }
@ -110,7 +133,9 @@ class SourceFileManager {
} }
} }
} }
let downloadedFileStatus = await sourceFileDownloadTracker.getDownloadedFileStatus()
return downloadedFileStatus
} }
func getAllFiles(initialDate: String = "08-2022") async { func getAllFiles(initialDate: String = "08-2022") async {
@ -180,7 +205,7 @@ class SourceFileManager {
url.pathExtension == "csv" url.pathExtension == "csv"
}) })
return (allFiles + (Bundle.main.urls(forResourcesWithExtension: "csv", subdirectory: nil) ?? [])).sorted(by: \.dateFromPath).reversed() return (allFiles + (Bundle.main.urls(forResourcesWithExtension: "csv", subdirectory: nil) ?? [])).sorted { $0.dateFromPath == $1.dateFromPath ? $0.index < $1.index : $0.dateFromPath > $1.dateFromPath }
} }
func allFiles(_ isManPlayer: Bool) -> [URL] { func allFiles(_ isManPlayer: Bool) -> [URL] {
@ -192,6 +217,14 @@ class SourceFileManager {
func allFilesSortedByDate(_ isManPlayer: Bool) -> [URL] { func allFilesSortedByDate(_ isManPlayer: Bool) -> [URL] {
return allFiles(isManPlayer) return allFiles(isManPlayer)
} }
static func isDateAfterUrlImportDate(date: Date, dateString: String) -> Bool {
guard let importDate = URL.importDateFormatter.date(from: dateString) else {
return false
}
return importDate.isEarlierThan(date)
}
} }
enum SourceFile: String, CaseIterable { enum SourceFile: String, CaseIterable {

@ -67,7 +67,7 @@ struct StepperView: View {
} }
fileprivate func _plusIsDisabled() -> Bool { fileprivate func _plusIsDisabled() -> Bool {
count >= (maximum ?? 100_000) count >= (maximum ?? 70_000)
} }
fileprivate func _add() { fileprivate func _add() {

@ -11,7 +11,8 @@ import StoreKit
struct MainView: View { struct MainView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(\.requestReview) var requestReview //TODO: IOS BUG
//@Environment(\.requestReview) var requestReview
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@Environment(ImportObserver.self) private var importObserver: ImportObserver @Environment(ImportObserver.self) private var importObserver: ImportObserver
@ -70,7 +71,7 @@ struct MainView: View {
#if DEBUG #if DEBUG
#else #else
_requestReviewIfAppropriated() //_requestReviewIfAppropriated()
#endif #endif
} }
@ -146,7 +147,7 @@ struct MainView: View {
let isConnected = StoreCenter.main.userId != nil let isConnected = StoreCenter.main.userId != nil
let numberOfSignificantTournaments = dataStore.tournaments.filter({ $0.isDeleted == false && $0.endDate != nil }).count let numberOfSignificantTournaments = dataStore.tournaments.filter({ $0.isDeleted == false && $0.endDate != nil }).count
if isConnected || numberOfSignificantTournaments > 0 { if isConnected || numberOfSignificantTournaments > 0 {
requestReview() //requestReview()
} }
} }
@ -230,25 +231,36 @@ struct MainView: View {
} }
private func _checkingDataIntegrity() { private func _checkingDataIntegrity() {
if lastDataSource == nil, importObserver.checkingFiles == false, importObserver.isImportingFile() == false { guard importObserver.checkingFiles == false, importObserver.isImportingFile() == false else {
return
}
if lastDataSource == nil {
Task { Task {
await self._checkSourceFileAvailability() await self._checkSourceFileAvailability()
} }
} else if let lastDataSource, lastDataSource != URL.importDateFormatter.string(from: Date()), importObserver.checkingFiles == false, importObserver.isImportingFile() == false { } else if let lastDataSource, lastDataSource != URL.importDateFormatter.string(from: Date()) {
Task { Task {
await self._checkSourceFileAvailability() await self._checkSourceFileAvailability()
} }
} else if let lastDataSource, lastDataSource == "08-2024" { } else if let lastDataSource, let mostRecentDateImported = URL.importDateFormatter.date(from: lastDataSource), SourceFileManager.isDateAfterUrlImportDate(date:mostRecentDateImported, dateString: "07-2024") {
let monthData = dataStore.monthData.sorted(by: \.creationDate) let monthData = dataStore.monthData.sorted(by: \.creationDate)
if let current = monthData.last, current.monthKey == "08-2024", current.incompleteMode == false {
if monthData.first(where: { $0.monthKey == "07-2024" }) == nil {
Task {
await _checkSourceFileAvailability()
}
} else {
if let current = monthData.last {
Task { Task {
let updated = await SourceFileManager.shared.fetchData(fromDate: mostRecentDateImported)
print("file updated", updated)
if let updated, updated == 1 {
await _startImporting(importingDate: mostRecentDateImported)
} else if current.incompleteMode == false || updated == 0 {
await _calculateMonthData(dataSource: current.monthKey) await _calculateMonthData(dataSource: current.monthKey)
} }
} }
if monthData.first(where: { $0.monthKey == "07-2024" }) == nil, importObserver.isImportingFile() == false, importObserver.checkingFiles == false {
Task {
await _checkSourceFileAvailability()
} }
} }
} }

@ -39,7 +39,11 @@ struct PadelClubView: View {
if let currentMonth = monthData.first, currentMonth.incompleteMode { if let currentMonth = monthData.first, currentMonth.incompleteMode {
Section { 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("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.")
if currentMonth.maleUnrankedValue == nil {
Text("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 70.000.")
}
Text("Un classement souligné comme ci-dessous indiquera que l'information provient d'un mois précédent.") Text("Un classement souligné comme ci-dessous indiquera que l'information provient d'un mois précédent.")
@ -158,10 +162,12 @@ struct PadelClubView: View {
LabeledContent { LabeledContent {
if let maleUnrankedValue = monthData.maleUnrankedValue { if let maleUnrankedValue = monthData.maleUnrankedValue {
Text(maleUnrankedValue.formatted()) Text(maleUnrankedValue.formatted())
} else {
Text(70_000.formatted())
} }
} label: { } label: {
Text("Rang d'un non classé") Text("Rang d'un non classé")
if monthData.incompleteMode { if monthData.incompleteMode && monthData.maleUnrankedValue == nil {
Text("Messieurs (estimation car incomplet)") Text("Messieurs (estimation car incomplet)")
} else { } else {
Text("Messieurs") Text("Messieurs")
@ -196,14 +202,6 @@ struct PadelClubView: View {
} }
} }
.id(uuid) .id(uuid)
.task {
await self._checkSourceFileAvailability()
}
.refreshable {
Task {
await self._checkSourceFileAvailability()
}
}
.headerProminence(.increased) .headerProminence(.increased)
.navigationTitle("Données fédérales") .navigationTitle("Données fédérales")
} }
@ -226,18 +224,6 @@ struct PadelClubView: View {
} }
} }
private func _checkSourceFileAvailability() async {
print("check internet")
print("check files on internet")
print("check if any files on internet are more recent than here")
importObserver.checkingFiles = true
await SourceFileManager.shared.fetchData()
importObserver.checkingFilesAttempt += 1
importObserver.checkingFiles = false
//uuid = UUID()
}
private func _startImporting() { private func _startImporting() {
let importingDate = SourceFileManager.shared.mostRecentDateAvailable let importingDate = SourceFileManager.shared.mostRecentDateAvailable
importObserver.currentImportDate = importingDate importObserver.currentImportDate = importingDate

@ -149,7 +149,7 @@ struct AddTeamView: View {
@ViewBuilder @ViewBuilder
private func _managementView() -> some View { private func _managementView() -> some View {
Section { Section {
RowButtonView("Rechercher dans la base fédérale") { RowButtonView("Ajouter via la base fédérale") {
presentPlayerSearch = true presentPlayerSearch = true
} }
} footer: { } footer: {
@ -365,6 +365,22 @@ struct AddTeamView: View {
} }
} }
} }
if editedTeam == nil {
if createdPlayerIds.isEmpty {
RowButtonView("Bloquer une place") {
_createTeam(checkDuplicates: false)
}
} else {
RowButtonView("Ajouter l'équipe") {
_createTeam(checkDuplicates: true)
}
}
} else {
RowButtonView("Confirmer") {
_updateTeam(checkDuplicates: false)
editedTeam = nil
}
}
} header: { } header: {
let _currentSelection = _currentSelection() let _currentSelection = _currentSelection()
let selectedSortedTeams = tournament.selectedSortedTeams() let selectedSortedTeams = tournament.selectedSortedTeams()
@ -393,25 +409,6 @@ struct AddTeamView: View {
} }
Section {
if editedTeam == nil {
if createdPlayerIds.isEmpty {
RowButtonView("Bloquer une place") {
_createTeam(checkDuplicates: false)
}
} else {
RowButtonView("Ajouter l'équipe") {
_createTeam(checkDuplicates: true)
}
}
} else {
RowButtonView("Modifier l'équipe") {
_updateTeam(checkDuplicates: false)
editedTeam = nil
}
}
}
if let pasteString { if let pasteString {
if fetchPlayers.isEmpty { if fetchPlayers.isEmpty {
ContentUnavailableView { ContentUnavailableView {

Loading…
Cancel
Save