multistore
Razmig Sarkissian 2 years ago
parent d19b679656
commit cd94a671db
  1. 10
      PadelClub/Data/Match.swift
  2. 2
      PadelClub/Data/Tournament.swift
  3. 7
      PadelClub/Utils/Tips.swift
  4. 32
      PadelClub/Views/Calling/CallMessageCustomizationView.swift
  5. 17
      PadelClub/Views/Components/FortuneWheelView.swift
  6. 2
      PadelClub/Views/Components/MatchListView.swift
  7. 2
      PadelClub/Views/Match/MatchSummaryView.swift
  8. 4
      PadelClub/Views/Player/Components/PlayerSexPickerView.swift
  9. 44
      PadelClub/Views/Round/RoundView.swift
  10. 2
      PadelClub/Views/Score/EditScoreView.swift
  11. 2
      PadelClub/Views/Team/TeamRowView.swift
  12. 9
      PadelClub/Views/Tournament/FileImportView.swift
  13. 8
      PadelClub/Views/Tournament/Screen/BroadcastView.swift
  14. 6
      PadelClub/Views/Tournament/Screen/Components/TournamentClubSettingsView.swift
  15. 2
      PadelClub/Views/Tournament/Screen/Components/TournamentMatchFormatsSettingsView.swift
  16. 10
      PadelClub/Views/Tournament/TournamentInitView.swift
  17. 11
      PadelClub/Views/Tournament/TournamentView.swift

@ -27,12 +27,12 @@ class Match: ModelObject, Storable {
var winningTeamId: String? var winningTeamId: String?
var losingTeamId: String? var losingTeamId: String?
//var broadcasted: Bool //var broadcasted: Bool
//var name: String? private var name: String?
//var order: Int //var order: Int
var disabled: Bool = false var disabled: Bool = false
private(set) var courtIndex: Int? private(set) var courtIndex: Int?
internal init(round: String? = nil, groupStage: String? = nil, startDate: Date? = nil, endDate: Date? = nil, index: Int, matchFormat: MatchFormat? = nil, servingTeamId: String? = nil, winningTeamId: String? = nil, losingTeamId: String? = nil, disabled: Bool = false, courtIndex: Int? = nil) { internal init(round: String? = nil, groupStage: String? = nil, startDate: Date? = nil, endDate: Date? = nil, index: Int, matchFormat: MatchFormat? = nil, servingTeamId: String? = nil, winningTeamId: String? = nil, losingTeamId: String? = nil, name: String? = nil, disabled: Bool = false, courtIndex: Int? = nil) {
self.round = round self.round = round
self.groupStage = groupStage self.groupStage = groupStage
self.startDate = startDate self.startDate = startDate
@ -44,11 +44,9 @@ class Match: ModelObject, Storable {
self.winningTeamId = winningTeamId self.winningTeamId = winningTeamId
self.losingTeamId = losingTeamId self.losingTeamId = losingTeamId
self.disabled = disabled self.disabled = disabled
self.name = name
self.courtIndex = courtIndex self.courtIndex = courtIndex
// self.broadcasted = broadcasted // self.broadcasted = broadcasted
// self.name = name
// self.order = order // self.order = order
} }
@ -630,7 +628,7 @@ class Match: ModelObject, Storable {
case _winningTeamId = "winningTeamId" case _winningTeamId = "winningTeamId"
case _losingTeamId = "losingTeamId" case _losingTeamId = "losingTeamId"
// case _broadcasted = "broadcasted" // case _broadcasted = "broadcasted"
// case _name = "name" case _name = "name"
// case _order = "order" // case _order = "order"
case _disabled = "disabled" case _disabled = "disabled"
} }

@ -96,7 +96,7 @@ class Tournament : ModelObject, Storable {
case _publishBrackets = "publishBrackets" case _publishBrackets = "publishBrackets"
} }
internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = true, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, groupStageCourtCount: Int? = nil, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishManually: Bool = false, publishTeams: Bool = false, publishWaitingList: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false) { internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = false, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, groupStageCourtCount: Int? = nil, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishManually: Bool = false, publishTeams: Bool = false, publishWaitingList: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false) {
self.event = event self.event = event
self.name = name self.name = name
self.startDate = startDate self.startDate = startDate

@ -339,9 +339,12 @@ struct TournamentPublishingTip: Tip {
Text("Gestion de la publication") Text("Gestion de la publication")
} }
enum ActionKey: String {
case showPadelClub = "show-padel-club"
}
var message: Text? { var message: Text? {
let messageString = "Padel Club vous permet de publier votre tournoi et rendre accessible à tous les résultats des matchs et l'évolution de l'événement. Les informations seront accessible sur le site [Padel Club](\(URLs.padelClub))." Text("Padel Club vous permet de publier votre tournoi et rendre accessible à tous les résultats des matchs et l'évolution de l'événement. Les informations seront accessible sur le site Padel Club.")
return Text(.init(messageString))
} }
var image: Image? { var image: Image? {

@ -46,17 +46,18 @@ struct CallMessageCustomizationView: View {
var finalMessage: String? { var finalMessage: String? {
let localizedCalled = "convoqué" + (tournament.tournamentCategory == .women ? "e" : "") + "s" 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)" return "Bonjour,\n\nVous êtes \(localizedCalled) pour jouer en \(RoundRule.roundName(fromRoundIndex: 2).lowercased()) du \(tournament.tournamentTitle()) au \(clubName) le \(tournament.startDate).formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(tournament.startDate.formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(customCallMessageSignature)"
} }
var body: some View { var body: some View {
@Bindable var user = dataStore.user @Bindable var user = dataStore.user
List { List {
_renderingView() _renderingView()
.disabled(true)
_optionsView() _optionsView()
_editorView() _editorView()
if user.summonsUseFullCustomMessage { if user.summonsUseFullCustomMessage && tournament.isFree() == false {
_paymentMethodsView() _paymentMethodsView()
} }
@ -138,9 +139,19 @@ struct CallMessageCustomizationView: View {
Text("Information supplémentaire") Text("Information supplémentaire")
} }
} footer: { } footer: {
if user.summonsUseFullCustomMessage == false {
HStack {
Spacer()
FooterButtonView("éditer") {
focusedField = .body
}
}
}
}
if user.summonsUseFullCustomMessage { if user.summonsUseFullCustomMessage {
LazyVStack(alignment: .leading) { Section {
Text("Utilisez ces balises") LazyHStack {
FooterButtonView("#titre") { FooterButtonView("#titre") {
customCallMessageBody.append("#titre") customCallMessageBody.append("#titre")
focusedField = .body focusedField = .body
@ -170,13 +181,8 @@ struct CallMessageCustomizationView: View {
focusedField = .body focusedField = .body
} }
} }
} else { } header: {
HStack { Text("Utilisez ces balises")
Spacer()
FooterButtonView("éditer") {
focusedField = .body
}
}
} }
} }
} }
@ -219,12 +225,14 @@ struct CallMessageCustomizationView: View {
private func _renderingView() -> some View { private func _renderingView() -> some View {
@Bindable var user = dataStore.user @Bindable var user = dataStore.user
Section { Section {
Group {
if user.summonsUseFullCustomMessage { if user.summonsUseFullCustomMessage {
Text(self.computedFullCustomMessage()) Text(self.computedFullCustomMessage())
} }
else if let finalMessage { else if let finalMessage {
Text(finalMessage) Text(finalMessage)
} }
}.italic().foregroundStyle(.gray)
} header: { } header: {
Text("Rendu généré automatiquement") Text("Rendu généré automatiquement")
} }
@ -248,7 +256,7 @@ struct CallMessageCustomizationView: View {
Text("Options") Text("Options")
} }
if user.summonsDisplayEntryFee && user.summonsUseFullCustomMessage == false { if user.summonsDisplayEntryFee && user.summonsUseFullCustomMessage == false && tournament.isFree() == false {
_paymentMethodsView() _paymentMethodsView()
} }
} }

@ -128,13 +128,14 @@ struct SpinDrawView: View {
} }
} }
Section { //todo
Text("XXX") // Section {
Text("XXX") // Text("XXX")
Text("XXX") // Text("XXX")
} header: { // Text("XXX")
Text("Comité du tournoi") // } header: {
} // Text("Comité du tournoi")
// }
} }
.toolbar { .toolbar {
ToolbarItem(placement: .cancellationAction) { ToolbarItem(placement: .cancellationAction) {
@ -286,7 +287,7 @@ struct FortuneWheelView: View {
Text(string).bold() Text(string).bold()
} }
} }
.padding(.trailing, 30) .padding(.trailing, 40)
.rotationEffect(.degrees(Double(index) * (360 / Double(segments.count)) + (360 / Double(segments.count) / 2))) .rotationEffect(.degrees(Double(index) * (360 / Double(segments.count)) + (360 / Double(segments.count) / 2)))
.foregroundColor(.white) .foregroundColor(.white)
.position(arcPosition(index: index, radius: radius)) .position(arcPosition(index: index, radius: radius))

@ -11,7 +11,7 @@ struct MatchListView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
let section: String let section: String
let matches: [Match] let matches: [Match]
var matchViewStyle: MatchViewStyle = .sectionedStandardStyle var matchViewStyle: MatchViewStyle = .standardStyle
@State var isExpanded: Bool = true @State var isExpanded: Bool = true

@ -76,10 +76,12 @@ struct MatchSummaryView: View {
Text(tournament.tournamentTitle()) Text(tournament.tournamentTitle())
} }
HStack { HStack {
if matchViewStyle != .sectionedStandardStyle {
if let roundTitle { if let roundTitle {
Text(roundTitle) Text(roundTitle)
} }
Text(matchTitle) Text(matchTitle)
}
Spacer() Spacer()
if let courtName { if let courtName {
Spacer() Spacer()

@ -17,8 +17,8 @@ struct PlayerSexPickerView: View {
Text(player.playerLabel()) Text(player.playerLabel())
Spacer() Spacer()
Picker(selection: $player.sex) { Picker(selection: $player.sex) {
Text("Homme").tag(PlayerRegistration.PlayerSexType.male) Text("Homme").tag(PlayerRegistration.PlayerSexType.male as PlayerRegistration.PlayerSexType?)
Text("Femme").tag(PlayerRegistration.PlayerSexType.female) Text("Femme").tag(PlayerRegistration.PlayerSexType.female as PlayerRegistration.PlayerSexType?)
} label: { } label: {
} }

@ -11,6 +11,15 @@ struct RoundView: View {
@Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed @Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@State private var selectedSeedGroup: SeedInterval?
var showVisualDrawView: Binding<Bool> { Binding(
get: { selectedSeedGroup != nil },
set: {
if $0 == false {
selectedSeedGroup = nil
}
}
)}
var round: Round var round: Round
@ -50,6 +59,7 @@ struct RoundView: View {
} }
} else if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) { } else if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) {
Section {
RowButtonView("Placer \(availableSeedGroup.localizedLabel())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : "")) { RowButtonView("Placer \(availableSeedGroup.localizedLabel())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : "")) {
tournament.setSeeds(inRoundIndex: round.index, inSeedGroup: availableSeedGroup) tournament.setSeeds(inRoundIndex: round.index, inSeedGroup: availableSeedGroup)
if tournament.availableSeeds().isEmpty { if tournament.availableSeeds().isEmpty {
@ -57,22 +67,13 @@ struct RoundView: View {
self.isEditingTournamentSeed.wrappedValue = false self.isEditingTournamentSeed.wrappedValue = false
} }
} }
}
if (availableSeedGroup.isFixed() == false) { if (availableSeedGroup.isFixed() == false) {
let seeds = tournament.seeds(inSeedGroup: availableSeedGroup) Section {
let availableSeedSpot = tournament.availableSeedSpot(inRoundIndex: round.index) RowButtonView("Tirage au sort \(availableSeedGroup.localizedLabel()) visuel") {
NavigationLink { self.selectedSeedGroup = availableSeedGroup
SpinDrawView(drawees: seeds, segments: availableSeedSpot) { draws in
draws.forEach { drawResult in
print(seeds[drawResult.drawee].teamLabel())
print(availableSeedSpot[drawResult.drawIndex].matchTitle())
seeds[drawResult.drawee].setSeedPosition(inSpot: availableSeedSpot[drawResult.drawIndex], slot: nil, opposingSeeding: false)
} }
try? dataStore.matches.addOrUpdate(contentOfs: availableSeedSpot)
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: seeds)
}
} label: {
Text("ou proposer le tirage au sort \(availableSeedGroup.localizedLabel())")
} }
} }
} }
@ -97,6 +98,23 @@ struct RoundView: View {
} }
} }
} }
.sheet(isPresented: showVisualDrawView) {
if let availableSeedGroup = selectedSeedGroup {
let seeds = tournament.seeds(inSeedGroup: availableSeedGroup)
let availableSeedSpot = tournament.availableSeedSpot(inRoundIndex: round.index)
NavigationStack {
SpinDrawView(drawees: seeds, segments: availableSeedSpot) { draws in
draws.forEach { drawResult in
print(seeds[drawResult.drawee].teamLabel())
print(availableSeedSpot[drawResult.drawIndex].matchTitle())
seeds[drawResult.drawee].setSeedPosition(inSpot: availableSeedSpot[drawResult.drawIndex], slot: nil, opposingSeeding: false)
}
try? dataStore.matches.addOrUpdate(contentOfs: availableSeedSpot)
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: seeds)
}
}
}
}
.headerProminence(.increased) .headerProminence(.increased)
.toolbar { .toolbar {
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .topBarTrailing) {

@ -95,7 +95,7 @@ struct EditScoreView: View {
dismiss() dismiss()
} }
} footer: { } footer: {
Text("Met à jour le score pour la diffusion, ne termine pas la rencontre") Text("Met à jour le score, ne termine pas la rencontre")
} }
} }
} }

@ -16,7 +16,7 @@ struct TeamRowView: View {
LabeledContent { LabeledContent {
TeamWeightView(team: team, teamPosition: teamPosition) TeamWeightView(team: team, teamPosition: teamPosition)
} label: { } label: {
Text(team.teamLabel(.short)) Text(team.teamLabel(.wide))
if let callDate = team.callDate, displayCallDate { if let callDate = team.callDate, displayCallDate {
Text("Déjà convoquée \(callDate.localizedDate())") Text("Déjà convoquée \(callDate.localizedDate())")
.foregroundStyle(.red) .foregroundStyle(.red)

@ -56,7 +56,7 @@ struct FileImportView: View {
await _startImport(fileContent: fileContent) await _startImport(fileContent: fileContent)
} }
} }
.disabled(fileContent == nil) .disabled(fileContent == nil || convertingFile)
} footer: { } footer: {
if fileProvider == .frenchFederation { if fileProvider == .frenchFederation {
let footerString = "Fichier provenant de [beach-padel.app.fft.fr](\(URLs.beachPadel.rawValue))" let footerString = "Fichier provenant de [beach-padel.app.fft.fr](\(URLs.beachPadel.rawValue))"
@ -95,7 +95,7 @@ struct FileImportView: View {
LabeledContent { LabeledContent {
ProgressView() ProgressView()
} label: { } label: {
Text("Importation en cours") Text("Conversion du fichier en cours")
} }
} }
} }
@ -171,13 +171,14 @@ struct FileImportView: View {
case .success(let fileurls): case .success(let fileurls):
if let selectedFile = fileurls.first { if let selectedFile = fileurls.first {
if selectedFile.startAccessingSecurityScopedResource() { if selectedFile.startAccessingSecurityScopedResource() {
convertingFile = true
errorMessage = nil errorMessage = nil
teams.removeAll() teams.removeAll()
Task { Task {
do { do {
if selectedFile.lastPathComponent.hasSuffix("xls") { if selectedFile.lastPathComponent.hasSuffix("xls") {
convertingFile = true
fileContent = try await CloudConvert.manager.uploadFile(selectedFile) fileContent = try await CloudConvert.manager.uploadFile(selectedFile)
convertingFile = false
} else { } else {
fileContent = try String(contentsOf: selectedFile) fileContent = try String(contentsOf: selectedFile)
} }
@ -242,7 +243,6 @@ struct FileImportView: View {
func _startImport(fileContent: String) async { func _startImport(fileContent: String) async {
await MainActor.run { await MainActor.run {
convertingFile = true
errorMessage = nil errorMessage = nil
teams.removeAll() teams.removeAll()
} }
@ -252,7 +252,6 @@ struct FileImportView: View {
self.teams = await FileImportManager.shared.createTeams(from: fileContent, tournament: tournament, fileProvider: fileProvider) self.teams = await FileImportManager.shared.createTeams(from: fileContent, tournament: tournament, fileProvider: fileProvider)
await MainActor.run { await MainActor.run {
convertingFile = false
didImport = true didImport = true
} }
} }

@ -28,10 +28,16 @@ struct BroadcastView: View {
var body: some View { var body: some View {
@Bindable var tournament = tournament @Bindable var tournament = tournament
List { List {
TipView(tournamentPublishingTip) Section {
TipView(tournamentPublishingTip) { action in
UIApplication.shared.open(URLs.padelClub.url)
}
.tipStyle(tint: nil) .tipStyle(tint: nil)
}
Section {
TipView(tournamentTVBroadcastTip) TipView(tournamentTVBroadcastTip)
.tipStyle(tint: nil) .tipStyle(tint: nil)
}
if tournament.publishManually == false { if tournament.publishManually == false {
Section { Section {

@ -83,11 +83,11 @@ struct TournamentClubSettingsView: View {
private func _courtView(atIndex index: Int, tournamentClub: Club) -> some View { private func _courtView(atIndex index: Int, tournamentClub: Club) -> some View {
if let court = tournamentClub.courts.first(where: { $0.index == index }) { if let court = tournamentClub.courts.first(where: { $0.index == index }) {
LabeledContent { LabeledContent {
if let name = court.name { FooterButtonView("personnaliser") {
Text(name) selectedCourt = court
} }
} label: { } label: {
Text(court.courtIndexTitle()) Text(court.courtTitle())
HStack { HStack {
if court.indoor { if court.indoor {
Text("Couvert") Text("Couvert")

@ -27,7 +27,7 @@ struct TournamentMatchFormatsSettingsView: View {
Section { Section {
LabeledContent { LabeledContent {
StepperView(title: "minutes", count: $tournament.additionalEstimationDuration, step: 5) StepperView(title: "minutes", count: $tournament.additionalEstimationDuration, step: 5, minimum: -10)
} label: { } label: {
Text("Modifier les durées moyennes") Text("Modifier les durées moyennes")
} }

@ -25,6 +25,16 @@ struct TournamentInitView: View {
Text("La date, la catégorie, le niveau, le nombre de terrain, les formats, etc.") Text("La date, la catégorie, le niveau, le nombre de terrain, les formats, etc.")
} }
Section {
NavigationLink(value: Screen.broadcast) {
LabeledContent {
// Text(tournament.isPrivate ? "privée" : "publique")
} label: {
Text("Publication")
}
}
}
Section { Section {
NavigationLink(value: Screen.structure) { NavigationLink(value: Screen.structure) {
LabeledContent { LabeledContent {

@ -72,15 +72,6 @@ struct TournamentView: View {
} }
case .initial: case .initial:
TournamentInitView() TournamentInitView()
NavigationLink(value: Screen.broadcast) {
LabeledContent {
Text(tournament.publishManually ? "manuel" : "auto.")
} label: {
Text("Publication")
}
}
case .build: case .build:
TournamentRunningView(tournament: tournament) TournamentRunningView(tournament: tournament)
@ -153,7 +144,7 @@ struct TournamentView: View {
Text("Classement") Text("Classement")
} }
NavigationLink(value: Screen.broadcast) { NavigationLink(value: Screen.broadcast) {
Text("Diffusion") Text("Publication")
} }
} }
} label: { } label: {

Loading…
Cancel
Save