Corregge scadenza token regia oltre le 8h, tabellone HTML sulla pagina live, pulsanti pausa/ripresa in regia, link admin e broadcast ActionCable diretto. App Android: overlay branding, sync score da regia via WebSocket con reconnect e poll. Co-authored-by: Cursor <cursoragent@cursor.com>
125 lines
3.7 KiB
Ruby
125 lines
3.7 KiB
Ruby
module Public
|
|
module LiveHelper
|
|
def live_score_sets_label(score_state)
|
|
return nil unless score_state
|
|
|
|
"Set #{score_state.current_set} · Set vinti #{score_state.home_sets}-#{score_state.away_sets}"
|
|
end
|
|
|
|
def live_score_partials_label(score_state)
|
|
return nil unless score_state
|
|
|
|
partials = Array(score_state.set_partials)
|
|
return nil if partials.empty?
|
|
|
|
partials.map { |p| format_set_partial_entry(p) }.join(" · ")
|
|
end
|
|
|
|
def live_scheduled_label(datetime)
|
|
return nil unless datetime
|
|
|
|
datetime.in_time_zone.strftime("%d/%m/%Y alle %H:%M")
|
|
end
|
|
|
|
def live_scheduled_relative(datetime)
|
|
return nil unless datetime
|
|
|
|
if datetime.to_date == Time.zone.today
|
|
"Oggi alle #{datetime.strftime('%H:%M')}"
|
|
elsif datetime.to_date == Time.zone.tomorrow
|
|
"Domani alle #{datetime.strftime('%H:%M')}"
|
|
else
|
|
live_scheduled_label(datetime)
|
|
end
|
|
end
|
|
|
|
def live_match_card_heading(match)
|
|
team = match.team
|
|
club_name = team.club&.name.presence || "Società"
|
|
content_tag(:h3, class: "live-card__title") do
|
|
safe_join([
|
|
content_tag(:span, club_name, class: "live-card__club"),
|
|
content_tag(:span, "#{team.name} vs #{match.opponent_name}", class: "live-card__matchup")
|
|
])
|
|
end
|
|
end
|
|
|
|
def live_match_page_heading(match)
|
|
team = match.team
|
|
club_name = team.club&.name.presence || "Società"
|
|
content_tag(:div, class: "live-page-heading") do
|
|
safe_join([
|
|
content_tag(:p, club_name, class: "live-page-heading__club"),
|
|
content_tag(:h1, "#{team.name} vs #{match.opponent_name}", class: "live-page-heading__matchup")
|
|
])
|
|
end
|
|
end
|
|
|
|
def live_score_points_label(match, score_state)
|
|
return "—" unless score_state
|
|
|
|
"#{match.team.name} #{score_state.home_points} - #{score_state.away_points} #{match.opponent_name}"
|
|
end
|
|
|
|
def live_scorebug_columns(score_state)
|
|
unless score_state
|
|
return {
|
|
labels: ["1"],
|
|
home: ["0"],
|
|
away: ["0"],
|
|
live_index: 0
|
|
}
|
|
end
|
|
|
|
partials = Array(score_state.set_partials)
|
|
labels = partials.map { |p| (p["set"] || p[:set]).to_s }
|
|
home = partials.map { |p| (p["home"] || p[:home]).to_s }
|
|
away = partials.map { |p| (p["away"] || p[:away]).to_s }
|
|
labels << score_state.current_set.to_s
|
|
home << score_state.home_points.to_s
|
|
away << score_state.away_points.to_s
|
|
{
|
|
labels: labels,
|
|
home: home,
|
|
away: away,
|
|
live_index: labels.length - 1
|
|
}
|
|
end
|
|
|
|
def live_scorebug_team_label(name, max: 16)
|
|
n = name.to_s
|
|
n.length <= max ? n : "#{n[0, max - 1]}…"
|
|
end
|
|
|
|
# Colore ospite sul tabellone: secondario società se leggibile su bianco, altrimenti blu visitatore.
|
|
def live_scorebug_away_color(team)
|
|
club = team.club
|
|
candidate = club&.effective_secondary_color.presence || "#1565c0"
|
|
return candidate unless light_hex_color?(candidate)
|
|
|
|
"#1565c0"
|
|
end
|
|
|
|
private
|
|
|
|
def light_hex_color?(hex)
|
|
h = hex.to_s.delete_prefix("#")
|
|
return false unless h.match?(/\A\h{6}\z/i)
|
|
|
|
r = h[0..1].to_i(16)
|
|
g = h[2..3].to_i(16)
|
|
b = h[4..5].to_i(16)
|
|
(0.299 * r + 0.587 * g + 0.114 * b) > 200
|
|
end
|
|
|
|
def format_set_partial_entry(partial)
|
|
data = partial.respond_to?(:with_indifferent_access) ? partial.with_indifferent_access : partial
|
|
set_no = data[:set] || data["set"]
|
|
home = data[:home] || data["home"]
|
|
away = data[:away] || data["away"]
|
|
label = set_no.present? ? "Set #{set_no}" : "Set"
|
|
"#{label} #{home}-#{away}"
|
|
end
|
|
end
|
|
end
|