multistore
Razmig Sarkissian 2 years ago
parent 13e09d2163
commit 5f4c995fb8
  1. 16
      PadelClub.xcodeproj/project.pbxproj
  2. 39
      PadelClub/Data/Tournament.swift
  3. 13
      PadelClub/Data/User.swift
  4. 15
      PadelClub/Manager/ContactManager.swift
  5. 188
      PadelClub/Views/Calling/CallMessageCustomizationView.swift
  6. 25
      PadelClub/Views/Calling/CallSettingsView.swift
  7. 0
      PadelClub/Views/Cashier/CashierDetailView.swift
  8. 0
      PadelClub/Views/Cashier/CashierView.swift
  9. 2
      PadelClub/Views/Components/RowButtonView.swift
  10. 11
      PadelClub/Views/Event/EventCreationView.swift
  11. 12
      PadelClub/Views/Event/TournamentConfiguratorView.swift
  12. 19
      PadelClub/Views/Planning/PlanningSettingsView.swift
  13. 109
      PadelClub/Views/Planning/PlanningView.swift
  14. 12
      PadelClub/Views/Tournament/Screen/Components/TournamentDurationManagerView.swift
  15. 11
      PadelClub/Views/Tournament/Screen/Components/TournamentFieldsManagerView.swift
  16. 12
      PadelClub/Views/Tournament/TournamentRunningView.swift

@ -85,6 +85,7 @@
FF0EC5752BB195E20056B6D1 /* CLASSEMENT-PADEL-DAMES-11-2022.csv in Resources */ = {isa = PBXBuildFile; fileRef = FF0EC5342BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-11-2022.csv */; };
FF0EC5762BB195E20056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-04-2023.csv in Resources */ = {isa = PBXBuildFile; fileRef = FF0EC5452BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-04-2023.csv */; };
FF0EC5772BB195E20056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-10-2022.csv in Resources */ = {isa = PBXBuildFile; fileRef = FF0EC54A2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-10-2022.csv */; };
FF11627A2BCF8109000C4809 /* CallMessageCustomizationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162792BCF8109000C4809 /* CallMessageCustomizationView.swift */; };
FF1CBC1B2BB53D1F0036DAAB /* FederalTournament.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */; };
FF1CBC1D2BB53DC10036DAAB /* Calendar+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */; };
FF1CBC1F2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */; };
@ -354,6 +355,7 @@
FF0EC54A2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-10-2022.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-10-2022.csv"; sourceTree = "<group>"; };
FF0EC54B2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-11-2022.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-11-2022.csv"; sourceTree = "<group>"; };
FF0EC54C2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-12-2022.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-12-2022.csv"; sourceTree = "<group>"; };
FF1162792BCF8109000C4809 /* CallMessageCustomizationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMessageCustomizationView.swift; sourceTree = "<group>"; };
FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournament.swift; sourceTree = "<group>"; };
FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+Extensions.swift"; sourceTree = "<group>"; };
FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournamentSearchScope.swift; sourceTree = "<group>"; };
@ -642,6 +644,7 @@
FF089EB92BB011EE00F0AEC7 /* Player */,
FF9267FD2BCE94520080F940 /* Calling */,
FFF964512BC2628600EEF017 /* Planning */,
FF11627B2BCF937F000C4809 /* Cashier */,
FF3F74F72B919F96004CFE0E /* Tournament */,
C4A47D882B7BBB5000ADC637 /* Subscription */,
C4A47D852B7BA33F00ADC637 /* User */,
@ -766,6 +769,15 @@
path = CSV;
sourceTree = "<group>";
};
FF11627B2BCF937F000C4809 /* Cashier */ = {
isa = PBXGroup;
children = (
FF9267F92BCE78EB0080F940 /* CashierDetailView.swift */,
FF9267F72BCE78C70080F940 /* CashierView.swift */,
);
path = Cashier;
sourceTree = "<group>";
};
FF1DC54D2BAB34FA00FD8220 /* Club */ = {
isa = PBXGroup;
children = (
@ -825,8 +837,6 @@
FF8F26532BAE1E4400650388 /* TableStructureView.swift */,
FF0E0B6C2BC254C6005F00A9 /* TournamentScheduleView.swift */,
FF9268062BCE94D90080F940 /* TournamentCallView.swift */,
FF9267F72BCE78C70080F940 /* CashierView.swift */,
FF9267F92BCE78EB0080F940 /* CashierDetailView.swift */,
FF8F26522BAE0E4E00650388 /* Components */,
);
path = Screen;
@ -950,6 +960,7 @@
FF9268002BCE94920080F940 /* SeedsCallingView.swift */,
FF9268022BCE94A30080F940 /* GroupStageCallingView.swift */,
FF9268082BCEDC2C0080F940 /* CallView.swift */,
FF1162792BCF8109000C4809 /* CallMessageCustomizationView.swift */,
);
path = Calling;
sourceTree = "<group>";
@ -1362,6 +1373,7 @@
FF8F263D2BAD627A00650388 /* TournamentConfiguratorView.swift in Sources */,
FFC1E10C2BAC7FB0008D6F59 /* ClubImportView.swift in Sources */,
FF3B60A32BC49BBC008C2E66 /* MatchScheduler.swift in Sources */,
FF11627A2BCF8109000C4809 /* CallMessageCustomizationView.swift in Sources */,
FF5DA1952BB927E800A33061 /* GenericDestinationPickerView.swift in Sources */,
FF8F26542BAE1E4400650388 /* TableStructureView.swift in Sources */,
C45BAE442BCA753E002EEC8A /* Purchase.swift in Sources */,

@ -448,7 +448,7 @@ class Tournament : ModelObject, Storable {
//todo
var clubName: String? {
nil
eventObject?.clubObject?.name
}
//todo
@ -629,16 +629,11 @@ class Tournament : ModelObject, Storable {
}
func umpireMail() -> [String]? {
if let mail = UserDefaults.standard.string(forKey: "umpireMail"), mail.isEmpty == false {
return [mail]
if let email = DataStore.shared.user?.email {
return [email]
} else {
return nil
}
// if let umpireMail = federalTournament?.courrielEngagement {
// return [umpireMail]
// } else {
// }
}
func earnings() -> Double {
@ -655,19 +650,29 @@ class Tournament : ModelObject, Storable {
return Double(selectedPlayers.filter { $0.hasPaid() }.count) / Double(selectedPlayers.count)
}
func cashierStatus() -> String {
//todo
return "todo"
typealias TournamentStatus = (label:String, completion: String)
func cashierStatus() -> TournamentStatus {
let selectedPlayers = selectedPlayers()
let paid = selectedPlayers.filter({ $0.hasPaid() })
let label = paid.count.formatted() + " / " + selectedPlayers.count.formatted() + " joueurs encaissés"
let completion = (Double(paid.count) / Double(selectedPlayers.count)).formatted(.percent.precision(.fractionLength(0)))
return TournamentStatus(label: label, completion: completion)
}
func scheduleStatus() -> String {
//todo
return "todo"
func scheduleStatus() -> TournamentStatus {
let allMatches = allMatches()
let ready = allMatches.filter({ $0.startDate != nil })
let label = ready.count.formatted() + " / " + allMatches.count.formatted() + " matchs programmés"
let completion = (Double(ready.count) / Double(allMatches.count)).formatted(.percent.precision(.fractionLength(0)))
return TournamentStatus(label: label, completion: completion)
}
func callStatus() -> String {
//todo
return "todo"
func callStatus() -> TournamentStatus {
let selectedSortedTeams = selectedSortedTeams()
let called = selectedSortedTeams.filter{ $0.called() }
let label = called.count.formatted() + " / " + selectedSortedTeams.count.formatted() + " paires convoquées"
let completion = (Double(called.count) / Double(selectedSortedTeams.count)).formatted(.percent.precision(.fractionLength(0)))
return TournamentStatus(label: label, completion: completion)
}
func bracketStatus() -> String {

@ -27,7 +27,12 @@ class User: UserBase {
var lastName: String
var phone: String?
var country: String?
var callMessageBody : String? = nil
var callMessageSignature: String? = nil
var callDisplayFormat: Bool = false
var callDisplayEntryFee: Bool = false
var callUseFullCustomMessage: Bool = false
init(username: String, email: String, firstName: String, lastName: String, phone: String?, country: String?) {
self.username = username
self.firstName = firstName
@ -64,6 +69,12 @@ class User: UserBase {
case _lastName = "lastName"
case _phone = "phone"
case _country = "country"
case _callMessageBody = "callMessageBody"
case _callMessageSignature = "callMessageSignature"
case _callDisplayFormat = "callDisplayFormat"
case _callDisplayEntryFee = "callDisplayEntryFee"
case _callUseFullCustomMessage = "callUseFullCustomMessage"
}
}

@ -8,6 +8,7 @@
import Foundation
import SwiftUI
import MessageUI
import LeStorage
enum ContactManagerError: LocalizedError {
case mailFailed
@ -33,7 +34,7 @@ extension ContactType {
static let defaultSignature = ""
static func callingGroupStageCustomMessage(tournament: Tournament?, startDate: Date?, roundLabel: String) -> String {
let tournamentCustomMessage = UserDefaults.standard.string(forKey: "customMessage") ?? defaultCustomMessage
let tournamentCustomMessage = DataStore.shared.user?.callMessageBody ?? defaultCustomMessage
let clubName = tournament?.clubName ?? ""
var text = tournamentCustomMessage
@ -48,7 +49,7 @@ extension ContactType {
text = text.replacingOccurrences(of: "#jour", with: "\(date.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide)))")
text = text.replacingOccurrences(of: "#horaire", with: "\(date.formatted(Date.FormatStyle().hour().minute()))")
let signature = UserDefaults.standard.string(forKey: "mySelf") ?? defaultSignature
let signature = DataStore.shared.user?.callMessageSignature ?? defaultSignature
text = text.replacingOccurrences(of: "#signature", with: signature)
return text
@ -56,7 +57,7 @@ extension ContactType {
static func callingGroupStageMessage(tournament: Tournament?, startDate: Date?, roundLabel: String, matchFormat: MatchFormat?) -> String {
let useFullCustomMessage = UserDefaults.standard.bool(forKey: "useFullCustomMessage")
let useFullCustomMessage = DataStore.shared.user?.callUseFullCustomMessage ?? false
if useFullCustomMessage {
return callingGroupStageCustomMessage(tournament: tournament, startDate: startDate, roundLabel: roundLabel)
@ -65,17 +66,17 @@ extension ContactType {
let date = startDate ?? tournament?.startDate ?? Date()
let clubName = tournament?.clubName ?? ""
let message = UserDefaults.standard.string(forKey: "customMessage") ?? defaultCustomMessage
let signature = UserDefaults.standard.string(forKey: "mySelf") ?? defaultSignature
let message = DataStore.shared.user?.callMessageBody ?? defaultCustomMessage
let signature = DataStore.shared.user?.callMessageSignature ?? defaultSignature
let localizedCalled = "convoqué" + (tournament?.tournamentCategory == .women ? "e" : "") + "s"
var formatMessage: String? {
UserDefaults.standard.bool(forKey: "displayFormat") ? matchFormat?.computedLongLabel.appending(".") : nil
(DataStore.shared.user?.callDisplayFormat ?? false) ? matchFormat?.computedLongLabel.appending(".") : nil
}
var entryFeeMessage: String? {
UserDefaults.standard.bool(forKey: "displayEntryFee") ? tournament?.entryFeeMessage : nil
(DataStore.shared.user?.callDisplayEntryFee ?? false) ? tournament?.entryFeeMessage : nil
}
var computedMessage: String {

@ -0,0 +1,188 @@
//
// CallMessageCustomizationView.swift
// Padel Tournament
//
// Created by Razmig Sarkissian on 02/11/2023.
//
import SwiftUI
struct CallMessageCustomizationView: View {
@EnvironmentObject var dataStore: DataStore
var tournament: Tournament
var user: User
@FocusState private var textEditor: Bool
@State private var customClubName: String = ""
@State private var customCallMessageBody: String = ""
@State private var customCallMessageSignature: String = ""
init(tournament: Tournament, user: User) {
self.tournament = tournament
self.user = user
_customCallMessageBody = State(wrappedValue: user.callMessageBody ?? "")
_customCallMessageSignature = State(wrappedValue: user.callMessageSignature ?? "")
_customClubName = State(wrappedValue: tournament.clubName ?? "")
}
var clubName: String {
customClubName
}
var formatMessage: String? {
user.callDisplayFormat ? tournament.matchFormat.computedLongLabel + "." : nil
}
var entryFeeMessage: String? {
user.callDisplayEntryFee ? tournament.entryFeeMessage : nil
}
var computedMessage: String {
[formatMessage, entryFeeMessage, customCallMessageBody].compacted().map { $0.trimmed }.joined(separator: "\n")
}
var finalMessage: String? {
let localizedCalled = "convoqué" + (tournament.tournamentCategory == .women ? "e" : "") + "s"
return "Bonjour,\n\nVous êtes \(localizedCalled) pour jouer en \(RoundRule.roundName(fromRoundIndex: 2).lowercased()) du \(tournament.tournamentTitle()) au \(clubName) le \(Date().formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(Date().formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(customCallMessageSignature)"
}
var body: some View {
@Bindable var user = user
List {
Section {
ZStack {
Text(customCallMessageBody).hidden()
.padding(.vertical, 20)
TextEditor(text: $customCallMessageBody)
.autocorrectionDisabled()
.focused($textEditor)
}
} header: {
Text("Personnalisation du message de convocation")
}
Section {
ZStack {
Text(customCallMessageSignature).hidden()
TextEditor(text: $customCallMessageSignature)
.autocorrectionDisabled()
.focused($textEditor)
}
} header: {
Text("Signature du message")
}
Section {
TextField("Nom du club", text: $customClubName)
.autocorrectionDisabled()
.onSubmit {
if let eventClub = tournament.eventObject?.clubObject {
eventClub.name = customClubName
try? dataStore.clubs.addOrUpdate(instance: eventClub)
}
}
} header: {
Text("Nom du club")
}
Section {
if user.callUseFullCustomMessage {
Text(self.computedFullCustomMessage())
.contextMenu {
Button("Coller dans le presse-papier") {
UIPasteboard.general.string = self.computedFullCustomMessage()
}
}
}
else if let finalMessage {
Text(finalMessage)
.contextMenu {
Button("Coller dans le presse-papier") {
UIPasteboard.general.string = finalMessage
}
}
}
} header: {
Text("Exemple")
}
Section {
LabeledContent {
Toggle(isOn: $user.callUseFullCustomMessage) {
}
} label: {
Text("contrôle complet du message")
}
} header: {
Text("Personnalisation complète")
} footer: {
Text("Utilisez ces balises dans votre texte : #titre, #jour, #horaire, #club, #signature")
}
}
.navigationTitle("Message de convocation")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Menu {
Picker(selection: $user.callDisplayFormat) {
Text("Afficher le format").tag(true)
Text("Masquer le format").tag(false)
} label: {
}
Picker(selection: $user.callDisplayEntryFee) {
Text("Afficher le prix d'inscription").tag(true)
Text("Masquer le prix d'inscription").tag(false)
} label: {
}
} label: {
LabelOptions()
}
}
ToolbarItemGroup(placement: .keyboard) {
if textEditor {
Spacer()
Button {
textEditor = false
} label: {
Label("Fermer", systemImage: "xmark")
}
}
}
}
.onChange(of: user.callUseFullCustomMessage) {
if user.callUseFullCustomMessage == false {
user.callMessageBody = ContactType.defaultCustomMessage
}
_save()
}
.onChange(of: customCallMessageBody) {
user.callMessageBody = customCallMessageBody
_save()
}
.onChange(of: customCallMessageSignature) {
user.callMessageSignature = customCallMessageSignature
_save()
}
.onChange(of: user.callDisplayEntryFee) {
_save()
}
.onChange(of: user.callDisplayFormat) {
_save()
}
}
private func _save() {
try? dataStore.setUser(user)
}
func computedFullCustomMessage() -> String {
var text = customCallMessageBody.replacingOccurrences(of: "#titre", with: tournament.tournamentTitle())
text = text.replacingOccurrences(of: "#club", with: clubName)
text = text.replacingOccurrences(of: "#jour", with: "\(Date().formatted(Date.FormatStyle().weekday(.wide).day().month(.wide)))")
text = text.replacingOccurrences(of: "#horaire", with: "\(Date().formatted(Date.FormatStyle().hour().minute()))")
text = text.replacingOccurrences(of: "#signature", with: customCallMessageSignature)
return text
}
}

@ -14,15 +14,24 @@ struct CallSettingsView: View {
var body: some View {
List {
if let user = dataStore.user {
Section {
NavigationLink {
CallMessageCustomizationView(tournament: tournament, user: user)
} label: {
Text("Personnaliser le message de convocation")
}
}
}
Section {
NavigationLink {
} label: {
Text("Modifier le message de convocation")
RowButtonView("Envoyer un message à tout le monde") {
}
}
Section {
RowButtonView("Annuler toutes les convocations") {
RowButtonView("Annuler toutes les convocations", role: .destructive) {
let teams = tournament.unsortedTeams()
teams.forEach { team in
team.callDate = nil
@ -32,13 +41,7 @@ struct CallSettingsView: View {
}
Section {
RowButtonView("Envoyer un message à tout le monde") {
}
}
Section {
RowButtonView("Tout le monde a été convoqué") {
RowButtonView("Tout le monde a été convoqué", role: .destructive) {
let teams = tournament.unsortedTeams()
teams.forEach { team in
team.callDate = Date()

@ -66,7 +66,7 @@ struct RowButtonView: View {
.disabled(animatedProgress)
.frame(maxWidth: .infinity)
.buttonStyle(.borderedProminent)
.tint(role == .destructive ? Color.red : Color.launchScreenBackground)
.tint(role == .destructive ? Color.red : Color.master)
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets(.zero))
.confirmationDialog("Confirmation",

@ -40,12 +40,11 @@ struct EventCreationView: View {
}
if eventType == .approvedTournament {
Stepper(value: $duration, in: 1...3) {
HStack {
Text("Durée")
Spacer()
Text("\(duration) jour" + duration.pluralSuffix)
}
LabeledContent {
StepperView(count: $duration, minimum: 1, maximum: 3)
} label: {
Text("Durée")
Text("\(duration) jour" + duration.pluralSuffix)
}
}

@ -35,13 +35,11 @@ struct TournamentConfigurationView: View {
Text(type.localizedLabel()).tag(type.rawValue)
}
}
Stepper(value: $tournament.teamCount, in: minimumTeamsCount...maximumTeamsCount) {
HStack {
Text("Équipes souhaitées")
Spacer()
Text(tournament.teamCount.formatted())
}
LabeledContent {
StepperView(count: $tournament.teamCount, minimum: minimumTeamsCount, maximum: maximumTeamsCount)
} label: {
Text("Équipes souhaitées")
Text(tournament.teamCount.formatted())
}
}
}

@ -39,12 +39,11 @@ struct PlanningSettingsView: View {
List {
Section {
DatePicker(tournament.startDate.formatted(.dateTime.weekday()), selection: $tournament.startDate)
Stepper(value: $tournament.dayDuration, in: 1...1_000) {
HStack {
Text("Durée")
Spacer()
Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix)
}
LabeledContent {
StepperView(count: $tournament.dayDuration, minimum: 1, maximum: 1_000)
} label: {
Text("Durée")
Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix)
}
} header: {
Text("Démarrage et durée du tournoi")
@ -114,14 +113,6 @@ struct PlanningSettingsView: View {
}
}
}
Section {
NavigationLink {
} label: {
Text("Modifier le message de convocation")
}
}
}
.onChange(of: groupStageCourtCount) {
tournament.groupStageCourtCount = groupStageCourtCount

@ -9,7 +9,6 @@ import SwiftUI
struct PlanningView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(\.editMode) private var editMode
let matches: [Match]
@State private var timeSlots: [Date:[Match]]
@ -30,85 +29,27 @@ struct PlanningView: View {
Section {
ForEach(keys.filter({ $0.dayInt == day.dayInt }), id: \.self) { key in
if let _matches = timeSlots[key] {
if editMode?.wrappedValue.isEditing == true {
HStack {
VStack(alignment: .leading) {
let index = keys.firstIndex(of: key)
Button {
let previousKey = keys[index! - 1]
let previousMatches = timeSlots[previousKey]
previousMatches?.forEach { match in
match.startDate = key
}
_matches.forEach { match in
match.startDate = previousKey
}
_update()
} label: {
Image(systemName: "arrow.up")
}
.buttonStyle(.bordered)
.disabled(index == 0)
Button {
let nextKey = keys[index! + 1]
let nextMatches = timeSlots[nextKey]
nextMatches?.forEach { match in
match.startDate = key
}
_matches.forEach { match in
match.startDate = nextKey
}
_update()
} label: {
Image(systemName: "arrow.down")
}
.buttonStyle(.bordered)
.disabled(index == keys.count - 1)
}
VStack(alignment: .leading) {
DisclosureGroup {
ForEach(_matches) { match in
NavigationLink {
MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle)
} label: {
LabeledContent {
Text(_matches.count.formatted() + " match" + _matches.count.pluralSuffix)
} label: {
Text(key.formatted(date: .omitted, time: .shortened)).font(.largeTitle)
}
ForEach(_matches) { match in
LabeledContent {
Text(match.matchFormat.format)
} label: {
if let groupStage = match.groupStageObject {
Text(groupStage.groupStageTitle())
} else if let round = match.roundObject {
Text(round.roundTitle())
}
Text(match.matchTitle())
if let court = match.court {
Text(court)
}
}
}
}
} else {
DisclosureGroup {
ForEach(_matches) { match in
NavigationLink {
MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle)
} label: {
LabeledContent {
if let court = match.court {
Text(court)
}
} label: {
if let groupStage = match.groupStageObject {
Text(groupStage.groupStageTitle())
} else if let round = match.roundObject {
Text(round.roundTitle())
}
Text(match.matchTitle())
if let groupStage = match.groupStageObject {
Text(groupStage.groupStageTitle())
} else if let round = match.roundObject {
Text(round.roundTitle())
}
Text(match.matchTitle())
}
}
} label: {
_timeSlotView(key: key, matches: _matches)
}
} label: {
_timeSlotView(key: key, matches: _matches)
}
}
}
@ -118,29 +59,9 @@ struct PlanningView: View {
.headerProminence(.increased)
}
}
.toolbar {
EditButton()
}
.onChange(of: isEditing) { old, new in
if old == true && new == false {
print("save")
try? dataStore.matches.addOrUpdate(contentOfs: matches)
}
}
.navigationTitle("Programmation")
}
private func _update() {
let timeSlots = Dictionary(grouping: matches) { $0.startDate ?? .distantFuture }
self.timeSlots = timeSlots
self.days = Set(timeSlots.keys.map { $0.startOfDay }).sorted()
self.keys = timeSlots.keys.sorted()
}
private var isEditing: Bool {
editMode?.wrappedValue.isEditing == true
}
private func _timeSlotView(key: Date, matches: [Match]) -> some View {
LabeledContent {
Text(matches.count.formatted() + " match" + matches.count.pluralSuffix)

@ -12,13 +12,11 @@ struct TournamentDurationManagerView: View {
var body: some View {
@Bindable var tournament = tournament
Stepper(value: $tournament.dayDuration, in: 1...3) {
LabeledContent {
Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix)
} label: {
Text("Durée")
}
LabeledContent {
StepperView(count: $tournament.dayDuration, minimum: 1, maximum: 3)
} label: {
Text("Durée")
Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix)
}
}
}

@ -12,12 +12,11 @@ struct TournamentFieldsManagerView: View {
@Binding var count: Int
var body: some View {
Stepper(value: $count, in: 1...1_000) {
LabeledContent {
Text(count.formatted())
} label: {
Text(localizedStringKey)
}
LabeledContent {
StepperView(count: $count, minimum: 1, maximum: 1_000)
} label: {
Text(localizedStringKey)
Text(count.formatted())
}
}
}

@ -14,26 +14,32 @@ struct TournamentRunningView: View {
var body: some View {
Section {
NavigationLink(value: Screen.schedule) {
let tournamentStatus = tournament.scheduleStatus()
LabeledContent {
Text(tournament.scheduleStatus())
Text(tournamentStatus.completion).foregroundStyle(.master)
} label: {
Text("Horaires")
Text(tournamentStatus.label)
}
}
NavigationLink(value: Screen.call) {
let tournamentStatus = tournament.callStatus()
LabeledContent {
Text(tournament.callStatus())
Text(tournamentStatus.completion).foregroundStyle(.master)
} label: {
Text("Convocations")
Text(tournamentStatus.label)
}
}
NavigationLink(value: Screen.cashier) {
let tournamentStatus = tournament.cashierStatus()
LabeledContent {
Text(tournament.cashierStatus())
Text(tournamentStatus.completion).foregroundStyle(.master)
} label: {
Text("Encaissement")
Text(tournamentStatus.label)
}
}
}

Loading…
Cancel
Save