|
|
|
|
@ -27,7 +27,10 @@ struct MatchDetailView: View { |
|
|
|
|
@State private var showDetails: Bool = false |
|
|
|
|
@State private var contactType: ContactType? = nil |
|
|
|
|
@State private var sentError: ContactManagerError? = nil |
|
|
|
|
@State private var showSubscriptionView: Bool = false |
|
|
|
|
// @State private var showSubscriptionView: Bool = false |
|
|
|
|
|
|
|
|
|
@State var showSubscriptionView: Bool = false |
|
|
|
|
@State var showUserCreationView: Bool = false |
|
|
|
|
|
|
|
|
|
var messageSentFailed: Binding<Bool> { |
|
|
|
|
Binding { |
|
|
|
|
@ -65,52 +68,6 @@ struct MatchDetailView: View { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var quickLookHeader: some View { |
|
|
|
|
Section { |
|
|
|
|
HStack { |
|
|
|
|
Menu { |
|
|
|
|
Button("Non défini") { |
|
|
|
|
match.removeCourt() |
|
|
|
|
save() |
|
|
|
|
} |
|
|
|
|
if let tournament = match.currentTournament() { |
|
|
|
|
ForEach(0..<tournament.courtCount, id: \.self) { courtIndex in |
|
|
|
|
Button(tournament.courtName(atIndex: courtIndex)) { |
|
|
|
|
match.setCourt(courtIndex) |
|
|
|
|
save() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} label: { |
|
|
|
|
VStack(alignment: .leading) { |
|
|
|
|
Text("terrain").font(.footnote).foregroundStyle(.secondary) |
|
|
|
|
if let courtName = match.courtName() { |
|
|
|
|
Text(courtName) |
|
|
|
|
.foregroundStyle(Color.master) |
|
|
|
|
.underline() |
|
|
|
|
} else { |
|
|
|
|
Text("Choisir") |
|
|
|
|
.foregroundStyle(Color.master) |
|
|
|
|
.underline() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Spacer() |
|
|
|
|
MatchDateView(match: match, showPrefix: true) |
|
|
|
|
} |
|
|
|
|
.font(.title) |
|
|
|
|
.buttonStyle(.plain) |
|
|
|
|
} footer: { |
|
|
|
|
// if match.hasWalkoutTeam() == false { |
|
|
|
|
// if let weatherData = match.weatherData { |
|
|
|
|
// HStack { |
|
|
|
|
// WeatherView(weatherData: weatherData) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
List { |
|
|
|
|
if match.hasWalkoutTeam() == false { |
|
|
|
|
@ -130,7 +87,7 @@ struct MatchDetailView: View { |
|
|
|
|
showDetails = true |
|
|
|
|
} |
|
|
|
|
Spacer() |
|
|
|
|
MenuWarningView(teams: match.teams(), message: match.matchWarningMessage(), umpireMail: dataStore.user.email, subject: match.matchWarningSubject(), contactType: $contactType) |
|
|
|
|
MenuWarningView(tournament: self.match.currentTournament()!, teams: match.teams(), message: match.matchWarningMessage(), umpireMail: dataStore.user.email, subject: match.matchWarningSubject(), contactType: $contactType) |
|
|
|
|
.buttonStyle(.borderless) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -139,21 +96,12 @@ struct MatchDetailView: View { |
|
|
|
|
if match.isReady() { |
|
|
|
|
Section { |
|
|
|
|
RowButtonView("Saisir les résultats", systemImage: "list.clipboard") { |
|
|
|
|
do { |
|
|
|
|
if let tournament = self.match.currentTournament() { |
|
|
|
|
try tournament.payIfNecessary() |
|
|
|
|
scoreType = .edition |
|
|
|
|
} else { |
|
|
|
|
self.showSubscriptionView = true |
|
|
|
|
} |
|
|
|
|
} catch { |
|
|
|
|
self.showSubscriptionView = true |
|
|
|
|
} |
|
|
|
|
self._editScores() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let players = match.teams().flatMap { $0.players() } |
|
|
|
|
let players = self.match.teams().flatMap { $0.players() } |
|
|
|
|
let unpaid = players.filter({ $0.hasPaid() == false }) |
|
|
|
|
|
|
|
|
|
if unpaid.isEmpty == false { |
|
|
|
|
@ -186,6 +134,14 @@ struct MatchDetailView: View { |
|
|
|
|
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.sheet(isPresented: self.$showUserCreationView, content: { |
|
|
|
|
NavigationStack { |
|
|
|
|
LoginView(reason: LoginReason.loginRequiredForFeature) { _ in |
|
|
|
|
self.showUserCreationView = false |
|
|
|
|
self._editScores() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.sheet(item: $scoreType, onDismiss: { |
|
|
|
|
if match.hasEnded() { |
|
|
|
|
dismiss() |
|
|
|
|
@ -195,37 +151,37 @@ struct MatchDetailView: View { |
|
|
|
|
EditScoreView(matchDescriptor: matchDescriptor) |
|
|
|
|
.tint(.master) |
|
|
|
|
|
|
|
|
|
// switch scoreType { |
|
|
|
|
// case .edition: |
|
|
|
|
// let matchDescriptor = MatchDescriptor(match: match) |
|
|
|
|
// EditScoreView(matchDescriptor: matchDescriptor) |
|
|
|
|
// case .live: |
|
|
|
|
// if let score = match.score { |
|
|
|
|
// if score.sets.isEmpty { |
|
|
|
|
// SplashView(score: score) |
|
|
|
|
// } else { |
|
|
|
|
// NewLiveScoringView(score: score) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
// case .prepare: |
|
|
|
|
// if match.freeMatchTeams.isEmpty == false { |
|
|
|
|
// EditFreeMatchView(match: match) |
|
|
|
|
// } else { |
|
|
|
|
// PrepareMatchView(match: match) |
|
|
|
|
// } |
|
|
|
|
// case .stat: |
|
|
|
|
// if let score = match.score { |
|
|
|
|
// MatchStatView() |
|
|
|
|
// .environmentObject(score) |
|
|
|
|
// } |
|
|
|
|
// case .health: |
|
|
|
|
// HealthKitView(match: match) |
|
|
|
|
// .presentationDetents([.medium]) |
|
|
|
|
// case .feeling: |
|
|
|
|
// if let feedbackData = match.feedbackData { |
|
|
|
|
// FeedbackView(feedbackData: feedbackData) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
// switch scoreType { |
|
|
|
|
// case .edition: |
|
|
|
|
// let matchDescriptor = MatchDescriptor(match: match) |
|
|
|
|
// EditScoreView(matchDescriptor: matchDescriptor) |
|
|
|
|
// case .live: |
|
|
|
|
// if let score = match.score { |
|
|
|
|
// if score.sets.isEmpty { |
|
|
|
|
// SplashView(score: score) |
|
|
|
|
// } else { |
|
|
|
|
// NewLiveScoringView(score: score) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
// case .prepare: |
|
|
|
|
// if match.freeMatchTeams.isEmpty == false { |
|
|
|
|
// EditFreeMatchView(match: match) |
|
|
|
|
// } else { |
|
|
|
|
// PrepareMatchView(match: match) |
|
|
|
|
// } |
|
|
|
|
// case .stat: |
|
|
|
|
// if let score = match.score { |
|
|
|
|
// MatchStatView() |
|
|
|
|
// .environmentObject(score) |
|
|
|
|
// } |
|
|
|
|
// case .health: |
|
|
|
|
// HealthKitView(match: match) |
|
|
|
|
// .presentationDetents([.medium]) |
|
|
|
|
// case .feeling: |
|
|
|
|
// if let feedbackData = match.feedbackData { |
|
|
|
|
// FeedbackView(feedbackData: feedbackData) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
.alert("Un problème est survenu", isPresented: messageSentFailed) { |
|
|
|
|
@ -239,47 +195,35 @@ struct MatchDetailView: View { |
|
|
|
|
Group { |
|
|
|
|
switch contactType { |
|
|
|
|
case .message(_, let recipients, let body, _): |
|
|
|
|
if Guard.main.paymentForNewTournament() != nil { |
|
|
|
|
MessageComposeView(recipients: recipients, body: body) { result in |
|
|
|
|
switch result { |
|
|
|
|
case .cancelled: |
|
|
|
|
break |
|
|
|
|
case .failed: |
|
|
|
|
self.sentError = .messageFailed |
|
|
|
|
case .sent: |
|
|
|
|
if networkMonitor.connected == false { |
|
|
|
|
self.sentError = .messageNotSent |
|
|
|
|
} |
|
|
|
|
@unknown default: |
|
|
|
|
break |
|
|
|
|
MessageComposeView(recipients: recipients, body: body) { result in |
|
|
|
|
switch result { |
|
|
|
|
case .cancelled: |
|
|
|
|
break |
|
|
|
|
case .failed: |
|
|
|
|
self.sentError = .messageFailed |
|
|
|
|
case .sent: |
|
|
|
|
if networkMonitor.connected == false { |
|
|
|
|
self.sentError = .messageNotSent |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
NavigationStack { |
|
|
|
|
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) |
|
|
|
|
@unknown default: |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
case .mail(_, let recipients, let bccRecipients, let body, let subject, _): |
|
|
|
|
if Guard.main.paymentForNewTournament() != nil { |
|
|
|
|
MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in |
|
|
|
|
switch result { |
|
|
|
|
case .cancelled, .saved: |
|
|
|
|
self.contactType = nil |
|
|
|
|
case .failed: |
|
|
|
|
MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in |
|
|
|
|
switch result { |
|
|
|
|
case .cancelled, .saved: |
|
|
|
|
self.contactType = nil |
|
|
|
|
case .failed: |
|
|
|
|
self.contactType = nil |
|
|
|
|
self.sentError = .mailFailed |
|
|
|
|
case .sent: |
|
|
|
|
if networkMonitor.connected == false { |
|
|
|
|
self.contactType = nil |
|
|
|
|
self.sentError = .mailFailed |
|
|
|
|
case .sent: |
|
|
|
|
if networkMonitor.connected == false { |
|
|
|
|
self.contactType = nil |
|
|
|
|
self.sentError = .mailNotSent |
|
|
|
|
} |
|
|
|
|
@unknown default: |
|
|
|
|
break |
|
|
|
|
self.sentError = .mailNotSent |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
NavigationStack { |
|
|
|
|
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) |
|
|
|
|
@unknown default: |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -326,6 +270,52 @@ struct MatchDetailView: View { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var quickLookHeader: some View { |
|
|
|
|
Section { |
|
|
|
|
HStack { |
|
|
|
|
Menu { |
|
|
|
|
Button("Non défini") { |
|
|
|
|
match.removeCourt() |
|
|
|
|
save() |
|
|
|
|
} |
|
|
|
|
if let tournament = match.currentTournament() { |
|
|
|
|
ForEach(0..<tournament.courtCount, id: \.self) { courtIndex in |
|
|
|
|
Button(tournament.courtName(atIndex: courtIndex)) { |
|
|
|
|
match.setCourt(courtIndex) |
|
|
|
|
save() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} label: { |
|
|
|
|
VStack(alignment: .leading) { |
|
|
|
|
Text("terrain").font(.footnote).foregroundStyle(.secondary) |
|
|
|
|
if let courtName = match.courtName() { |
|
|
|
|
Text(courtName) |
|
|
|
|
.foregroundStyle(Color.master) |
|
|
|
|
.underline() |
|
|
|
|
} else { |
|
|
|
|
Text("Choisir") |
|
|
|
|
.foregroundStyle(Color.master) |
|
|
|
|
.underline() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Spacer() |
|
|
|
|
MatchDateView(match: match, showPrefix: true) |
|
|
|
|
} |
|
|
|
|
.font(.title) |
|
|
|
|
.buttonStyle(.plain) |
|
|
|
|
} footer: { |
|
|
|
|
// if match.hasWalkoutTeam() == false { |
|
|
|
|
// if let weatherData = match.weatherData { |
|
|
|
|
// HStack { |
|
|
|
|
// WeatherView(weatherData: weatherData) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
enum ScoreType: Int, Identifiable, Hashable { |
|
|
|
|
var id: Int { |
|
|
|
|
self.rawValue |
|
|
|
|
@ -442,6 +432,34 @@ struct MatchDetailView: View { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate func _editScores() { |
|
|
|
|
|
|
|
|
|
self._verifyUser { |
|
|
|
|
self._payTournamentAndExecute { |
|
|
|
|
self.scoreType = .edition |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate func _verifyUser(_ handler: () -> ()) { |
|
|
|
|
if Store.main.userId != nil { |
|
|
|
|
handler() |
|
|
|
|
} else { |
|
|
|
|
self.showUserCreationView = true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate func _payTournamentAndExecute(_ handler: () -> ()) { |
|
|
|
|
guard let tournament = self.match.currentTournament() else { fatalError("missing tournament") } |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
try tournament.payIfNecessary() |
|
|
|
|
handler() |
|
|
|
|
} catch { |
|
|
|
|
self.showSubscriptionView = true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private func save() { |
|
|
|
|
do { |
|
|
|
|
try dataStore.matches.addOrUpdate(instance: match) |
|
|
|
|
|