Porting SwiftUI da Android (auth, hub, wizard, broadcast RTMP, overlay, scoring board-aware), reload hub al ritorno da diretta, decodifica score tollerante e documentazione allineata. Co-authored-by: Cursor <cursoragent@cursor.com>
148 lines
5.2 KiB
Swift
148 lines
5.2 KiB
Swift
import SwiftUI
|
|
|
|
struct StepTransmissionScreen: View {
|
|
@ObservedObject var container: AppContainer
|
|
let match: Match
|
|
let onBack: () -> Void
|
|
let onNext: () -> Void
|
|
let onError: (String) -> Void
|
|
|
|
@State private var team: Team?
|
|
@State private var platform = "matchlivetv"
|
|
@State private var privacy = "public"
|
|
@State private var creating = false
|
|
|
|
private var youtubeReady: Bool {
|
|
team?.isYoutubeReady == true
|
|
}
|
|
|
|
private var youtubeSubtitle: String {
|
|
guard let team else { return "Canale in attivazione" }
|
|
if !team.canUseYoutube { return "Premium Light o Full" }
|
|
if !team.isYoutubeReady { return "Canale in attivazione" }
|
|
return team.youtubeDestinationLabel
|
|
}
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(alignment: .leading, spacing: 0) {
|
|
if let plan = team?.planName {
|
|
Text("Piano \(plan)")
|
|
.font(MatchTypography.bodyMedium)
|
|
.foregroundStyle(MatchColors.textSecondary)
|
|
.padding(.bottom, 12)
|
|
}
|
|
|
|
Text("Piattaforma")
|
|
.font(MatchTypography.headlineMedium)
|
|
|
|
WizardPlatformCard(
|
|
title: "Match Live TV",
|
|
subtitle: "Diretta sul nostro sito (incluso)",
|
|
selected: platform == "matchlivetv",
|
|
onClick: { platform = "matchlivetv" }
|
|
)
|
|
.padding(.top, 12)
|
|
|
|
WizardPlatformCard(
|
|
title: "YouTube Live",
|
|
subtitle: youtubeSubtitle,
|
|
selected: platform == "youtube",
|
|
enabled: youtubeReady,
|
|
badge: team?.canUseYoutube == false ? "Premium" : nil,
|
|
onClick: selectYoutube
|
|
)
|
|
.padding(.top, 8)
|
|
|
|
Text("Visibilità")
|
|
.font(MatchTypography.headlineMedium)
|
|
.padding(.top, 24)
|
|
|
|
HStack(spacing: 8) {
|
|
WizardChoiceButton(
|
|
label: "PUBBLICO",
|
|
selected: privacy == "public",
|
|
action: { privacy = "public" }
|
|
)
|
|
.frame(maxWidth: .infinity)
|
|
WizardChoiceButton(
|
|
label: "NON IN ELENCO",
|
|
selected: privacy == "unlisted",
|
|
action: { privacy = "unlisted" }
|
|
)
|
|
.frame(maxWidth: .infinity)
|
|
}
|
|
.padding(.top, 12)
|
|
|
|
Text(visibilityDescription)
|
|
.font(MatchTypography.bodyMedium)
|
|
.foregroundStyle(MatchColors.textSecondary)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
.padding(.top, 8)
|
|
|
|
Text("La partita resta sempre visibile nel backend della squadra per tutta la durata dell'abbonamento.")
|
|
.font(MatchTypography.bodyMedium)
|
|
.foregroundStyle(MatchColors.textSecondary)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
.padding(.top, 6)
|
|
|
|
WizardFooterButtons(
|
|
onBack: onBack,
|
|
forwardLabel: "AVANTI >",
|
|
forwardLoading: creating,
|
|
onForward: createSessionAndContinue
|
|
)
|
|
.padding(.top, 32)
|
|
}
|
|
.padding(.horizontal, 20)
|
|
.padding(.top, 12)
|
|
.padding(.bottom, 32)
|
|
}
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
|
.task {
|
|
if let cached = container.wizardSession.team {
|
|
team = cached
|
|
} else {
|
|
team = await container.matchRepository.fetchTeam(teamId: match.teamId)
|
|
container.wizardSession.team = team
|
|
}
|
|
}
|
|
}
|
|
|
|
private var visibilityDescription: String {
|
|
if privacy == "public" {
|
|
return "Compare nell'elenco dirette su MatchLiveTV.it, nelle ricerche e sul canale YouTube (se selezionato)."
|
|
}
|
|
return "Non compare negli elenchi pubblici né nelle ricerche. Solo chi ha il link può guardare."
|
|
}
|
|
|
|
private func selectYoutube() {
|
|
if youtubeReady {
|
|
platform = "youtube"
|
|
} else {
|
|
onError("YouTube non disponibile per questa squadra")
|
|
}
|
|
}
|
|
|
|
private func createSessionAndContinue() {
|
|
creating = true
|
|
Task {
|
|
do {
|
|
let session = try await container.sessionRepository.createSession(
|
|
matchId: match.id,
|
|
platform: platform,
|
|
privacyStatus: privacy,
|
|
youtubeChannel: platform == "youtube" ? team?.effectiveYoutubeChannel : nil
|
|
)
|
|
container.wizardSession.session = session
|
|
onNext()
|
|
} catch {
|
|
if let message = UserFacingError.message(for: error) {
|
|
onError(message)
|
|
}
|
|
}
|
|
creating = false
|
|
}
|
|
}
|
|
}
|