diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 215bce4..e21dc63 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -1939,7 +1939,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 34; + CURRENT_PROJECT_VERSION = 37; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; @@ -1977,7 +1977,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 34; + CURRENT_PROJECT_VERSION = 37; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; diff --git a/PadelClub/Data/Match.swift b/PadelClub/Data/Match.swift index 4b4d864..3a743b7 100644 --- a/PadelClub/Data/Match.swift +++ b/PadelClub/Data/Match.swift @@ -355,6 +355,10 @@ class Match: ModelObject, Storable { func followingMatch() -> Match? { guard let nextRoundId = roundObject?.nextRound()?.id else { return nil } + return getFollowingMatch(fromNextRoundId: nextRoundId) + } + + func getFollowingMatch(fromNextRoundId nextRoundId: String) -> Match? { return Store.main.filter(isIncluded: { $0.round == nextRoundId && $0.index == (index - 1) / 2 }).first } diff --git a/PadelClub/Data/User.swift b/PadelClub/Data/User.swift index efd04c8..29de3e6 100644 --- a/PadelClub/Data/User.swift +++ b/PadelClub/Data/User.swift @@ -73,8 +73,8 @@ class User: ModelObject, UserBase, Storable { return "Sportivement,\n\(firstName) \(lastName), votre JAP." } - func hasClubs() -> Bool { - self.clubs.isEmpty == false + func hasTenupClubs() -> Bool { + self.clubsObjects().filter({ $0.code != nil }).isEmpty == false } func hasFavoriteClubsAndCreatedClubs() -> Bool { @@ -90,7 +90,7 @@ class User: ModelObject, UserBase, Storable { } func createdClubsObjectsNotFavorite() -> [Club] { - return Store.main.filter(isIncluded: { ($0.creator == id) || clubs.contains($0.id) == false }) + return Store.main.filter(isIncluded: { ($0.creator == id) && clubs.contains($0.id) == false }) } func saveMatchFormatsDefaultDuration(_ matchFormat: MatchFormat, estimatedDuration: Int) { diff --git a/PadelClub/Extensions/String+Extensions.swift b/PadelClub/Extensions/String+Extensions.swift index 0398619..580830e 100644 --- a/PadelClub/Extensions/String+Extensions.swift +++ b/PadelClub/Extensions/String+Extensions.swift @@ -46,16 +46,18 @@ extension String { func acronym() -> String { let acronym = canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines) if acronym.count > 10 { - return concatenateFirstLetters() + return concatenateFirstLetters().uppercased() } else { - return acronym + return acronym.uppercased() } } func concatenateFirstLetters() -> String { // Split the input into sentences let sentences = self.components(separatedBy: .whitespacesAndNewlines) - + if sentences.count == 1 { + return String(self.prefix(10)) + } // Extract the first character of each sentence let firstLetters = sentences.compactMap { sentence -> Character? in let trimmedSentence = sentence.trimmingCharacters(in: .whitespacesAndNewlines) diff --git a/PadelClub/Views/Club/ClubDetailView.swift b/PadelClub/Views/Club/ClubDetailView.swift index 257493c..62081e7 100644 --- a/PadelClub/Views/Club/ClubDetailView.swift +++ b/PadelClub/Views/Club/ClubDetailView.swift @@ -17,6 +17,7 @@ struct ClubDetailView: View { @State private var zipCode: String @State private var selectedCourt: Court? @Bindable var club: Club + @State private var clubDeleted: Bool = false var displayContext: DisplayContext var selection: ((Club) -> ())? = nil @@ -58,7 +59,7 @@ struct ClubDetailView: View { .submitLabel( displayContext == .addition ? .next : .done) .onSubmit(of: .text) { if club.acronym.isEmpty { - club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines) + club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines).acronym() } if displayContext == .edition && city.isEmpty == true { @@ -217,9 +218,10 @@ struct ClubDetailView: View { Section { RowButtonView("Supprimer ce club", role: .destructive) { do { - try dataStore.clubs.deleteById(club.id) + clubDeleted = true dataStore.user.clubs.removeAll(where: { $0 == club.id }) self.dataStore.saveUser() + try dataStore.clubs.deleteById(club.id) dismiss() } catch { Logger.error(error) @@ -240,7 +242,7 @@ struct ClubDetailView: View { CourtView(court: court) } .onDisappear { - if displayContext == .edition { + if displayContext == .edition && clubDeleted == false { do { try dataStore.clubs.addOrUpdate(instance: club) } catch { diff --git a/PadelClub/Views/Club/ClubRowView.swift b/PadelClub/Views/Club/ClubRowView.swift index 3a3e2dc..0f7f2fd 100644 --- a/PadelClub/Views/Club/ClubRowView.swift +++ b/PadelClub/Views/Club/ClubRowView.swift @@ -13,13 +13,14 @@ struct ClubRowView: View { var body: some View { LabeledContent { + Text(club.acronym) // if displayContext == .edition { // Image(systemName: club.isFavorite() ? "star.fill" : "star") // .foregroundStyle(club.isFavorite() ? .green : .logoRed) // } } label: { + Text("Club") Text(club.name) - Text(club.acronym) } } } diff --git a/PadelClub/Views/Club/ClubsView.swift b/PadelClub/Views/Club/ClubsView.swift index 7d4dc8d..862f897 100644 --- a/PadelClub/Views/Club/ClubsView.swift +++ b/PadelClub/Views/Club/ClubsView.swift @@ -28,31 +28,36 @@ struct ClubsView: View { var body: some View { List { let clubs : [Club] = dataStore.user.clubsObjects(includeCreated: false) - Section { - ForEach(clubs) { club in - if let selection { - Button { - selection(club) - dismiss() - } label: { - ClubRowView(club: club, displayContext: .selection) - .frame(maxWidth: .infinity) - } - .contentShape(Rectangle()) - .buttonStyle(.plain) - } else { - NavigationLink { - ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: dataStore.user.id) ? .edition : .lockedForEditing) - } label: { - ClubRowView(club: club) + let onlyCreatedClubs : [Club] = dataStore.user.createdClubsObjectsNotFavorite() + + if clubs.isEmpty == false || onlyCreatedClubs.isEmpty == false { + Section { + if clubs.isEmpty && onlyCreatedClubs.isEmpty == false { + _contentUnavailable() + } + ForEach(clubs) { club in + if let selection { + Button { + selection(club) + dismiss() + } label: { + ClubRowView(club: club, displayContext: .selection) + .frame(maxWidth: .infinity) + } + .contentShape(Rectangle()) + .buttonStyle(.plain) + } else { + NavigationLink { + ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: dataStore.user.id) ? .edition : .lockedForEditing) + } label: { + ClubRowView(club: club) + } } } + } header: { + Text("Clubs favoris") } - } header: { - Text("Clubs favoris") } - - let onlyCreatedClubs : [Club] = dataStore.user.createdClubsObjectsNotFavorite() if onlyCreatedClubs.isEmpty == false { Section { @@ -81,22 +86,11 @@ struct ClubsView: View { } } .overlay { - if dataStore.user.hasFavoriteClubsAndCreatedClubs() == false { - ContentUnavailableView { - Label("Aucun club", systemImage: "house.and.flag.fill") - } description: { - Text("Texte décrivant l'utilité d'un club et les features que cela apporte") - } actions: { - RowButtonView("Créer un nouveau club", systemImage: "plus.circle.fill") { - newClub = Club.newEmptyInstance() - } - RowButtonView("Chercher un club", systemImage: "magnifyingglass.circle.fill") { - presentClubSearchView = true - } - } + if dataStore.user.clubsObjects(includeCreated: true).isEmpty { + _contentUnavailable() } } - .navigationTitle(selection == nil ? "Mes clubs" : "Choisir un club") + .navigationTitle(selection == nil ? "Clubs favoris" : "Choisir un club") .navigationBarTitleDisplayMode(.inline) .toolbarBackground(.visible, for: .navigationBar) .sheet(isPresented: presentClubCreationView) { @@ -141,6 +135,22 @@ struct ClubsView: View { } } } + + private func _contentUnavailable() -> some View { + ContentUnavailableView { + Label("Aucun club", systemImage: "house.and.flag.fill") + } description: { + Text("Avoir un club en favori permet d'accéder aux tournois enregistrés sur Tenup.") + } actions: { + RowButtonView("Créer un nouveau club", systemImage: "plus.circle.fill") { + newClub = Club.newEmptyInstance() + } + RowButtonView("Chercher un club", systemImage: "magnifyingglass.circle.fill") { + presentClubSearchView = true + } + } + + } } #Preview { diff --git a/PadelClub/Views/Navigation/Agenda/ActivityView.swift b/PadelClub/Views/Navigation/Agenda/ActivityView.swift index f1e080b..bcbeaf3 100644 --- a/PadelClub/Views/Navigation/Agenda/ActivityView.swift +++ b/PadelClub/Views/Navigation/Agenda/ActivityView.swift @@ -121,14 +121,14 @@ struct ActivityView: View { } .task { if navigation.agendaDestination == .tenup - && dataStore.user.hasClubs() == true + && dataStore.user.hasTenupClubs() == true && federalDataViewModel.federalTournaments.isEmpty { _gatherFederalTournaments() } } .onChange(of: navigation.agendaDestination) { if navigation.agendaDestination == .tenup - && dataStore.user.hasClubs() == true + && dataStore.user.hasTenupClubs() == true && federalDataViewModel.federalTournaments.isEmpty { _gatherFederalTournaments() } @@ -192,7 +192,7 @@ struct ActivityView: View { .tint(.master) } .sheet(isPresented: $presentClubSearchView, onDismiss: { - if dataStore.user.hasClubs() == true { + if dataStore.user.hasTenupClubs() == true { federalDataViewModel.federalTournaments.removeAll() navigation.agendaDestination = .tenup } @@ -247,7 +247,7 @@ struct ActivityView: View { RowButtonView("Créer un nouvel événement") { newTournament = Tournament.newEmptyInstance() } - if dataStore.user.hasClubs() == false { + if dataStore.user.hasTenupClubs() == false { RowButtonView("Chercher l'un de vos clubs") { presentClubSearchView = true } @@ -268,7 +268,7 @@ struct ActivityView: View { } private func _tenupEmptyView() -> some View { - if dataStore.user.hasClubs() == false { + if dataStore.user.hasTenupClubs() == false { ContentUnavailableView { Label("Aucun tournoi", systemImage: "shield.slash") } description: { diff --git a/PadelClub/Views/Navigation/Agenda/EventListView.swift b/PadelClub/Views/Navigation/Agenda/EventListView.swift index 7cfcb48..7adadb5 100644 --- a/PadelClub/Views/Navigation/Agenda/EventListView.swift +++ b/PadelClub/Views/Navigation/Agenda/EventListView.swift @@ -53,7 +53,7 @@ struct EventListView: View { .headerProminence(.increased) .task { if navigation.agendaDestination == .tenup - && dataStore.user.hasClubs() == true + && dataStore.user.hasTenupClubs() == true && _tournaments.isEmpty { _gatherFederalTournaments(startDate: section) } diff --git a/PadelClub/Views/Navigation/MainView.swift b/PadelClub/Views/Navigation/MainView.swift index 9d41fb5..9695d3f 100644 --- a/PadelClub/Views/Navigation/MainView.swift +++ b/PadelClub/Views/Navigation/MainView.swift @@ -49,7 +49,7 @@ struct MainView: View { } var badgeText: Text? { - dataStore.user.username.isEmpty ? Text("!").font(.headline) : nil + Store.main.userId == nil ? Text("!").font(.headline) : nil } var body: some View { diff --git a/PadelClub/Views/Round/RoundSettingsView.swift b/PadelClub/Views/Round/RoundSettingsView.swift index eccbf35..cd1b35f 100644 --- a/PadelClub/Views/Round/RoundSettingsView.swift +++ b/PadelClub/Views/Round/RoundSettingsView.swift @@ -52,8 +52,30 @@ struct RoundSettingsView: View { let round = Round(tournament: tournament.id, index: roundIndex, matchFormat: tournament.matchFormat) let matchCount = RoundRule.numberOfMatches(forRoundIndex: roundIndex) let matchStartIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex) - let matches = (0..