Fix avanzamento quarto basket e regia senza cronometro.

Normalizza il periodo nel backend quando l'app invia "Q1" via cable, così advance_period aggiorna regia e overlay; rimuove i controlli cronometro dalla regia e rende più tollerante il decode iOS al resume sessione.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Emiliano Frascaro
2026-06-20 16:15:44 +02:00
parent c92099a41b
commit 793cfaaaf1
18 changed files with 861 additions and 452 deletions

View File

@@ -34,6 +34,7 @@ module Public
def score def score
cmd = params[:cmd].presence || params[:score_action].presence cmd = params[:cmd].presence || params[:score_action].presence
result = Scoring::ApplyAction.new(session: @session, action: cmd).call result = Scoring::ApplyAction.new(session: @session, action: cmd).call
@session.reload
render json: status_payload.merge( render json: status_payload.merge(
set_won: result.set_won, set_won: result.set_won,
match_won: result.match_won, match_won: result.match_won,

View File

@@ -55,7 +55,7 @@ class ScoreState < ApplicationRecord
end end
def current_period def current_period
(data || {})["period"].to_i.positive? ? (data || {})["period"].to_i : 1 Scoring::PeriodData.number_from((data || {})["period"]) || 1
end end
def current_period_label def current_period_label

View File

@@ -28,6 +28,7 @@ module Scoring
def ensure_period_data(score) def ensure_period_data(score)
data = period_data(score) data = period_data(score)
default_data.each { |k, v| data[k] = v unless data.key?(k) } default_data.each { |k, v| data[k] = v unless data.key?(k) }
PeriodData.normalize_hash!(data)
data data
end end
@@ -43,7 +44,7 @@ module Scoring
end end
def period_label(data) def period_label(data)
period = data["period"].to_i period = PeriodData.number_from(data["period"]) || 1
return "OT" if data["overtime"] return "OT" if data["overtime"]
board = @match.effective_board_type board = @match.effective_board_type
@@ -63,15 +64,17 @@ module Scoring
rules = period_rules rules = period_rules
max_periods = rules.periods max_periods = rules.periods
current = PeriodData.number_from(data["period"]) || 1
if data["overtime"] if data["overtime"]
data["period"] = data["period"].to_i + 1 data["period"] = current + 1
data["clock_secs"] = rules.overtime_duration_secs data["clock_secs"] = rules.overtime_duration_secs
elsif data["period"].to_i >= max_periods elsif current >= max_periods
data["overtime"] = true data["overtime"] = true
data["period"] = max_periods + 1 data["period"] = max_periods + 1
data["clock_secs"] = rules.overtime_duration_secs data["clock_secs"] = rules.overtime_duration_secs
else else
data["period"] = data["period"].to_i + 1 data["period"] = current + 1
data["clock_secs"] = rules.period_duration_secs data["clock_secs"] = rules.period_duration_secs
end end
data["clock_running"] = false data["clock_running"] = false
@@ -109,7 +112,14 @@ module Scoring
score = ensure_score(session) score = ensure_score(session)
data = ensure_period_data(score) data = ensure_period_data(score)
%w[period clock_secs clock_running home_score away_score overtime].each do |key| %w[period clock_secs clock_running home_score away_score overtime].each do |key|
data[key] = payload[key] if payload.key?(key) next unless payload.key?(key)
if key == "period"
period = PeriodData.number_from(payload[key])
data["period"] = period if period&.positive?
else
data[key] = payload[key]
end
end end
save_period_score!(score, data) save_period_score!(score, data)
score score

View File

@@ -0,0 +1,32 @@
module Scoring
# Normalizza `score_states.data["period"]` (intero o etichetta "Q2" / "2° tempo").
module PeriodData
module_function
def number_from(raw)
case raw
when Integer, Float
value = raw.to_i
value.positive? ? value : nil
when String
text = raw.strip
return nil if text.empty?
if (match = text.match(/\AQ(\d+)\z/i))
match[1].to_i
elsif (match = text.match(/\A(\d+)\s*°/))
match[1].to_i
elsif (value = text.to_i).positive?
value
end
end
end
def normalize_hash!(data)
number = number_from(data["period"])
data["period"] = number if number&.positive?
data["period"] = 1 unless data["period"].to_i.positive?
data
end
end
end

View File

@@ -2,7 +2,6 @@
<p class="regia-sets" id="sets-line"><%= live_score_period_label(@match, @score) %></p> <p class="regia-sets" id="sets-line"><%= live_score_period_label(@match, @score) %></p>
<p class="regia-score-line" id="score-line"><%= live_score_points_label(@match, @score) %></p> <p class="regia-score-line" id="score-line"><%= live_score_points_label(@match, @score) %></p>
<p class="regia-partials" id="partials-line" hidden></p> <p class="regia-partials" id="partials-line" hidden></p>
<p class="regia-clock-line" id="clock-line">Cronometro: <%= format_clock_secs(data["clock_secs"]) %></p>
<div class="regia-team-row"> <div class="regia-team-row">
<div> <div>
@@ -13,7 +12,7 @@
<button type="button" class="regia-btn regia-btn--point" data-action="home_point_3" style="width:100%;margin-top:4px">+3</button> <button type="button" class="regia-btn regia-btn--point" data-action="home_point_3" style="width:100%;margin-top:4px">+3</button>
<button type="button" class="regia-btn regia-btn--minus" data-action="home_undo" style="width:100%;margin-top:4px"></button> <button type="button" class="regia-btn regia-btn--minus" data-action="home_undo" style="width:100%;margin-top:4px"></button>
</div> </div>
<div class="regia-center-hint" id="center-hint"><%= format_clock_secs(data["clock_secs"]) %></div> <div class="regia-center-hint" id="center-hint"><%= live_score_period_label(@match, @score) %></div>
<div> <div>
<div class="regia-team-name"><%= @match.opponent_name %></div> <div class="regia-team-name"><%= @match.opponent_name %></div>
<div class="regia-points" id="away-points"><%= data["away_score"] || @score.away_points %></div> <div class="regia-points" id="away-points"><%= data["away_score"] || @score.away_points %></div>
@@ -23,8 +22,4 @@
<button type="button" class="regia-btn regia-btn--minus" data-action="away_undo" style="width:100%;margin-top:4px"></button> <button type="button" class="regia-btn regia-btn--minus" data-action="away_undo" style="width:100%;margin-top:4px"></button>
</div> </div>
</div> </div>
<div class="regia-clock-actions"> <button type="button" class="regia-btn regia-btn--yellow" data-action="advance_period" style="margin-top:12px">Prossimo quarto</button>
<button type="button" class="regia-btn regia-btn--outline" data-action="clock_toggle"><%= data["clock_running"] ? "Pausa" : "Avvia" %> cronometro</button>
<button type="button" class="regia-btn regia-btn--outline" data-action="clock_reset">Reset</button>
<button type="button" class="regia-btn regia-btn--yellow" data-action="advance_period">Prossimo quarto</button>
</div>

View File

@@ -2,7 +2,6 @@
<p class="regia-sets" id="sets-line"><%= live_score_period_label(@match, @score) %></p> <p class="regia-sets" id="sets-line"><%= live_score_period_label(@match, @score) %></p>
<p class="regia-score-line" id="score-line"><%= live_score_points_label(@match, @score) %></p> <p class="regia-score-line" id="score-line"><%= live_score_points_label(@match, @score) %></p>
<p class="regia-partials" id="partials-line" hidden></p> <p class="regia-partials" id="partials-line" hidden></p>
<p class="regia-clock-line" id="clock-line">Cronometro: <%= format_clock_secs(data["clock_secs"]) %></p>
<div class="regia-team-row"> <div class="regia-team-row">
<div> <div>
@@ -11,7 +10,7 @@
<button type="button" class="regia-btn regia-btn--point" data-action="home_point" style="width:100%;margin-top:8px">+1</button> <button type="button" class="regia-btn regia-btn--point" data-action="home_point" style="width:100%;margin-top:8px">+1</button>
<button type="button" class="regia-btn regia-btn--minus" data-action="home_undo" style="width:100%;margin-top:6px"></button> <button type="button" class="regia-btn regia-btn--minus" data-action="home_undo" style="width:100%;margin-top:6px"></button>
</div> </div>
<div class="regia-center-hint" id="center-hint"><%= format_clock_secs(data["clock_secs"]) %></div> <div class="regia-center-hint" id="center-hint"><%= live_score_period_label(@match, @score) %></div>
<div> <div>
<div class="regia-team-name"><%= @match.opponent_name %></div> <div class="regia-team-name"><%= @match.opponent_name %></div>
<div class="regia-points" id="away-points"><%= data["away_score"] || @score.away_points %></div> <div class="regia-points" id="away-points"><%= data["away_score"] || @score.away_points %></div>
@@ -19,8 +18,4 @@
<button type="button" class="regia-btn regia-btn--minus" data-action="away_undo" style="width:100%;margin-top:6px"></button> <button type="button" class="regia-btn regia-btn--minus" data-action="away_undo" style="width:100%;margin-top:6px"></button>
</div> </div>
</div> </div>
<div class="regia-clock-actions"> <button type="button" class="regia-btn regia-btn--yellow" data-action="advance_period" style="margin-top:12px">Prossimo tempo</button>
<button type="button" class="regia-btn regia-btn--outline" data-action="clock_toggle"><%= data["clock_running"] ? "Pausa" : "Avvia" %> cronometro</button>
<button type="button" class="regia-btn regia-btn--outline" data-action="clock_reset">Reset</button>
<button type="button" class="regia-btn regia-btn--yellow" data-action="advance_period">Prossimo tempo</button>
</div>

View File

@@ -29,7 +29,7 @@
<header class="regia-header"> <header class="regia-header">
<h1><%= @team.name %> vs <%= @match.opponent_name %></h1> <h1><%= @team.name %> vs <%= @match.opponent_name %></h1>
<p>Regia · <%= regia_header_subtitle(@match, @score) %></p> <p id="regia-subtitle">Regia · <%= regia_header_subtitle(@match, @score) %></p>
<span id="regia-badge" class="regia-badge <%= @stream_closed ? 'regia-badge--ended' : (@session.paused? ? 'regia-badge--wait' : (@on_air ? 'regia-badge--live' : 'regia-badge--wait')) %>"> <span id="regia-badge" class="regia-badge <%= @stream_closed ? 'regia-badge--ended' : (@session.paused? ? 'regia-badge--wait' : (@on_air ? 'regia-badge--live' : 'regia-badge--wait')) %>">
<%= @stream_closed ? "Terminata" : (@session.paused? ? "In pausa" : (@on_air ? "In onda" : "In attesa")) %> <%= @stream_closed ? "Terminata" : (@session.paused? ? "In pausa" : (@on_air ? "In onda" : "In attesa")) %>
</span> </span>
@@ -93,4 +93,4 @@
</div> </div>
</div> </div>
<script src="/regia.js?v=7"></script> <script src="/regia.js?v=8"></script>

View File

@@ -35,7 +35,8 @@
modalCancel: document.getElementById("modal-cancel"), modalCancel: document.getElementById("modal-cancel"),
preview: document.getElementById("regia-preview"), preview: document.getElementById("regia-preview"),
previewPlaceholder: document.getElementById("regia-preview-placeholder"), previewPlaceholder: document.getElementById("regia-preview-placeholder"),
btnPause: document.getElementById("btn-pause") btnPause: document.getElementById("btn-pause"),
subtitle: document.getElementById("regia-subtitle")
}; };
let pendingAction = null; let pendingAction = null;
@@ -99,6 +100,31 @@
return `${m}:${String(s).padStart(2, "0")}`; return `${m}:${String(s).padStart(2, "0")}`;
} }
function resolvePeriodLabel(score, board) {
const raw = score.period;
if (typeof raw === "string" && raw.trim()) return raw.trim();
if (typeof raw === "number" && raw > 0) {
return board === "basket" ? `Q${raw}` : `${raw}° tempo`;
}
const nested = score.data || {};
const dataPeriod = nested.period ?? nested["period"];
const periodNum = parseInt(dataPeriod, 10);
if (periodNum > 0) {
if (nested.overtime || nested["overtime"]) {
return board === "basket" ? `OT${Math.max(periodNum - 4, 1)}` : "Suppl.";
}
return board === "basket" ? `Q${periodNum}` : `${periodNum}° tempo`;
}
return "—";
}
function updateRegiaSubtitle(periodLabel, board) {
if (!els.subtitle) return;
if (board === "basket" || board === "timed") {
els.subtitle.textContent = `Regia · ${periodLabel}`;
}
}
function applyScorePayload(data) { function applyScorePayload(data) {
const s = data.score; const s = data.score;
if (!s) return; if (!s) return;
@@ -109,8 +135,7 @@
const homeSets = s.home_sets ?? s.homeSets; const homeSets = s.home_sets ?? s.homeSets;
const awaySets = s.away_sets ?? s.awaySets; const awaySets = s.away_sets ?? s.awaySets;
const currentSet = s.current_set ?? s.currentSet; const currentSet = s.current_set ?? s.currentSet;
const period = s.period; const periodLabel = resolvePeriodLabel(s, board);
const clockSecs = s.clock_secs ?? s.clockSecs ?? s.data?.clock_secs;
const awayEl = document.getElementById("away-points"); const awayEl = document.getElementById("away-points");
const centerHint = document.getElementById("center-hint"); const centerHint = document.getElementById("center-hint");
const clockLine = document.getElementById("clock-line"); const clockLine = document.getElementById("clock-line");
@@ -119,11 +144,12 @@
if (awayEl) awayEl.textContent = awayPts; if (awayEl) awayEl.textContent = awayPts;
if (board === "basket" || board === "timed") { if (board === "basket" || board === "timed") {
if (els.setsLine) els.setsLine.textContent = period || "—"; if (els.setsLine) els.setsLine.textContent = periodLabel;
if (els.scoreLine) els.scoreLine.textContent = `${cfg.homeName} ${homePts} - ${awayPts} ${cfg.awayName}`; if (els.scoreLine) els.scoreLine.textContent = `${cfg.homeName} ${homePts} - ${awayPts} ${cfg.awayName}`;
if (centerHint) centerHint.textContent = formatClock(clockSecs); if (centerHint) centerHint.textContent = periodLabel;
if (clockLine) clockLine.textContent = `Cronometro: ${formatClock(clockSecs)}`; updateRegiaSubtitle(periodLabel, board);
} else if (board === "timer") { } else if (board === "timer") {
const clockSecs = s.clock_secs ?? s.clockSecs ?? s.data?.clock_secs;
if (els.setsLine) els.setsLine.textContent = "Cronometro"; if (els.setsLine) els.setsLine.textContent = "Cronometro";
if (clockLine) clockLine.textContent = formatClock(clockSecs, true); if (clockLine) clockLine.textContent = formatClock(clockSecs, true);
} else if (board === "generic") { } else if (board === "generic") {
@@ -184,11 +210,18 @@
async function handleAction(action) { async function handleAction(action) {
const prevHome = els.homePoints?.textContent; const prevHome = els.homePoints?.textContent;
const prevAway = document.getElementById("away-points")?.textContent; const prevAway = document.getElementById("away-points")?.textContent;
const trigger = root.querySelector(`[data-action="${action}"]`);
if (trigger) trigger.disabled = true;
try { try {
const data = await postScore(action); const data = await postScore(action);
applyScorePayload(data); applyScorePayload(data);
setBadge(data); setBadge(data);
if (action === "advance_period") {
const periodLabel = resolvePeriodLabel(data.score || {}, cfg.board);
toast(periodLabel === "—" ? "Periodo aggiornato" : `Ora in ${periodLabel}`);
}
if (cfg.board === "volley" || cfg.board === "racket") { if (cfg.board === "volley" || cfg.board === "racket") {
if (data.set_won && action !== "close_set") { if (data.set_won && action !== "close_set") {
const winner = data.winner === "home" ? cfg.homeName : cfg.awayName; const winner = data.winner === "home" ? cfg.homeName : cfg.awayName;
@@ -204,6 +237,8 @@
const awayEl = document.getElementById("away-points"); const awayEl = document.getElementById("away-points");
if (prevAway != null && awayEl) awayEl.textContent = prevAway; if (prevAway != null && awayEl) awayEl.textContent = prevAway;
toast(e.message || "Errore"); toast(e.message || "Errore");
} finally {
if (trigger) trigger.disabled = false;
} }
} }

View File

@@ -62,6 +62,72 @@ RSpec.describe "Public regia", type: :request do
expect(response.parsed_body.dig("score", "board_type")).to eq("basket") expect(response.parsed_body.dig("score", "board_type")).to eq("basket")
end end
it "avanza il quarto basket via API" do
basket_team = club.teams.create!(name: "U13 Basket", sport_key: "basket")
basket_match = basket_team.matches.create!(opponent_name: "Avversario", sport: "basket")
basket_session = StreamSession.create!(match: basket_match, user: user, platform: "matchlivetv", status: "live")
basket_session.create_score_state!(
board_type: "basket",
home_sets: 0,
away_sets: 0,
home_points: 0,
away_points: 0,
current_set: 1,
data: {
"period" => 1,
"clock_secs" => 600,
"clock_running" => false,
"home_score" => 0,
"away_score" => 4,
"overtime" => false
}
)
token = Sessions::RegiaAccess.new(basket_session).issue_token!
patch public_regia_score_path(token), params: { cmd: "advance_period" }, as: :json
expect(response).to have_http_status(:ok)
body = response.parsed_body
expect(body.dig("score", "period")).to eq("Q2")
expect(body.dig("score", "data", "period")).to eq(2)
expect(basket_session.score_state.reload.data["period"]).to eq(2)
end
it "avanza il quarto basket anche con periodo Q1 corrotto in data" do
basket_team = club.teams.create!(name: "U13 Basket", sport_key: "basket")
basket_match = basket_team.matches.create!(opponent_name: "Avversario", sport: "basket")
basket_session = StreamSession.create!(match: basket_match, user: user, platform: "matchlivetv", status: "live")
basket_session.create_score_state!(
board_type: "basket",
data: {
"period" => "Q1",
"home_score" => 0,
"away_score" => 4,
"clock_secs" => 600,
"clock_running" => false,
"overtime" => false
}
)
token = Sessions::RegiaAccess.new(basket_session).issue_token!
patch public_regia_score_path(token), params: { cmd: "advance_period" }, as: :json
expect(response).to have_http_status(:ok)
expect(response.parsed_body.dig("score", "period")).to eq("Q2")
end
it "non mostra controlli cronometro sulla regia basket" do
basket_team = club.teams.create!(name: "U13 Basket", sport_key: "basket")
basket_match = basket_team.matches.create!(opponent_name: "Avversario", sport: "basket")
basket_session = StreamSession.create!(match: basket_match, user: user, platform: "matchlivetv", status: "live")
basket_session.create_score_state!(board_type: "basket", data: { "period" => 1, "home_score" => 0, "away_score" => 0 })
token = Sessions::RegiaAccess.new(basket_session).issue_token!
get public_regia_path(token)
expect(response).to have_http_status(:ok)
expect(response.body).to include("Prossimo quarto")
expect(response.body).not_to include("cronometro")
expect(response.body).not_to include("Cronometro:")
end
it "mette in pausa e riprende la diretta" do it "mette in pausa e riprende la diretta" do
mtx = instance_double( mtx = instance_double(
Mediamtx::Client, Mediamtx::Client,

View File

@@ -0,0 +1,66 @@
require "rails_helper"
RSpec.describe Scoring::PeriodData do
describe ".number_from" do
it "legge interi e etichette basket/timed" do
expect(described_class.number_from(2)).to eq(2)
expect(described_class.number_from("Q3")).to eq(3)
expect(described_class.number_from("2° tempo")).to eq(2)
expect(described_class.number_from("Q1")).to eq(1)
expect(described_class.number_from("")).to be_nil
end
end
end
RSpec.describe "Basket advance_period con periodo corrotto" do
let!(:user) { User.create!(email: "period@test.it", name: "U", password: "password123", role: "coach") }
let!(:club) { Club.create!(name: "C", sport: "basket", primary_color: "#e53935", secondary_color: "#ffffff") }
let!(:team) { club.teams.create!(name: "U13", sport_key: "basket") }
let!(:match) { team.matches.create!(opponent_name: "Opp", sport: "basket") }
let!(:session) { StreamSession.create!(match: match, user: user, platform: "matchlivetv", status: "live") }
it "avanza il quarto anche se data.period è la stringa Q1 (sync app mobile)" do
session.create_score_state!(
board_type: "basket",
home_points: 0,
away_points: 4,
data: {
"period" => "Q1",
"home_score" => 0,
"away_score" => 4,
"clock_secs" => 600,
"clock_running" => false,
"overtime" => false
}
)
Scoring::ApplyAction.new(session: session, action: "advance_period").call
score = session.score_state.reload
expect(score.data["period"]).to eq(2)
expect(score.current_period_label).to eq("Q2")
expect(score.as_cable_payload[:period]).to eq("Q2")
end
it "normalizza period in sync Action Cable" do
session.create_score_state!(
board_type: "basket",
data: { "period" => 1, "home_score" => 0, "away_score" => 0 }
)
Scoring::SyncState.new(
session: session,
payload: {
"type" => "score_update",
"board_type" => "basket",
"period" => "Q1",
"home_score" => 2,
"away_score" => 1
}
).call
score = session.score_state.reload
expect(score.data["period"]).to eq(1)
expect(score.data["home_score"]).to eq(2)
end
end

View File

@@ -38,7 +38,7 @@ data class ScoreState(
"timeout_away" to timeoutAway, "timeout_away" to timeoutAway,
) )
if (boardType in PERIOD_BOARDS) { if (boardType in PERIOD_BOARDS) {
payload["period"] = periodLabel ?: period.toString() payload["period"] = period
payload["clock_secs"] = clockSecs payload["clock_secs"] = clockSecs
payload["clock_running"] = clockRunning payload["clock_running"] = clockRunning
payload["home_score"] = homePoints payload["home_score"] = homePoints

View File

@@ -7,183 +7,183 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
00BDF215CB7942A799F06774 /* TeamColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6D45B70859402BA3ABD014 /* TeamColorPicker.swift */; }; 05E2509B1F96460F9A8FBDEE /* MatchScoringRulesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51257C93F3A4464F8AA4B5B5 /* MatchScoringRulesTests.swift */; };
045086A670F24B1192E0DF8F /* SessionRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C3663CA3AD648B48EA4405D /* SessionRepository.swift */; }; 0811090F35B647A9AAE98018 /* ApiInstant.swift in Sources */ = {isa = PBXBuildFile; fileRef = F52E5A9320FD4A9C82C64092 /* ApiInstant.swift */; };
08F123F9692D48EA94EBD94D /* KeepScreenOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DC8A3443404B0CAD323B11 /* KeepScreenOn.swift */; }; 0ABF8F2EAEF84F3CB3510FCA /* MatchHubFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C298D589A644368A5B3DB79 /* MatchHubFilter.swift */; };
0CE091822CAA4D88B1BE3AF4 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAEE3C8BBB684FEBA230480A /* LoginScreen.swift */; }; 0AEA80531D74475A9279AAF8 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C77C273929F4A4A9079A55E /* LoginScreen.swift */; };
0E03BE40DAF14E98A35051CE /* ScoreRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA8EB774A34C4E259AFB1C88 /* ScoreRepository.swift */; }; 0B2C36335D034737BD753D22 /* BroadcastControlsOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9652ABD17F34BF7B781F9CB /* BroadcastControlsOverlay.swift */; };
138294291C614F218D71B1CD /* ModalRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3A3F3250284150B0A0BCD4 /* ModalRoutes.swift */; }; 1191C9F3433D4C79BB1D55CA /* DeviceTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD66A152068843A89E25EA2A /* DeviceTelemetry.swift */; };
15EBD3E3D95D4AE5BABB6776 /* ScoreboardElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA61FF84F91473DA84438A8 /* ScoreboardElement.swift */; }; 16D77B1BA1694BC9AAEACACA /* ScoreState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B37C6177BA4FC7AD4DE2C9 /* ScoreState.swift */; };
191F31088FCE4A82932B6FBB /* LiveScoreActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D1C27A80A842A1B531051C /* LiveScoreActions.swift */; }; 17F54C8204F346CCA9EBFF89 /* TokenStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6CC04AA64F244128D7069F7 /* TokenStore.swift */; };
22A2A4F3BBD845C5B4E1DD6E /* DeviceTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5C7905A24E4AE1A0600511 /* DeviceTelemetry.swift */; }; 1B65AFB2A2A54BD69FE9D4D3 /* MatchLiveAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7485A29DA1E4F7EB3D4116D /* MatchLiveAPI.swift */; };
2498A1488A034D058E6997B0 /* ScoreActionDecodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BA0FAD47DC40D48F063FC8 /* ScoreActionDecodeTests.swift */; }; 1DF38DB813DC491C94C206CD /* SponsorElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EF4D8B887F6467699C4E184 /* SponsorElement.swift */; };
284F82D0FB65448BAB38C6BE /* TokenStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D2302B51D94A8984EC6A56 /* TokenStore.swift */; }; 1F26CA550156447B89B3EC01 /* MatchLiveWordmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5396F45B5E40B1B1787C6E /* MatchLiveWordmark.swift */; };
28A607B3D84448308B130ECF /* WatermarkElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DBA84B5B0CA459E89779309 /* WatermarkElement.swift */; }; 2094E19DDAD0464B9CED0495 /* ScoreActionDecodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9493EA978E6460FACFB7831 /* ScoreActionDecodeTests.swift */; };
2D3FAEEE0372415381467FC7 /* ApiDtos.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DF95A27A584535A1511035 /* ApiDtos.swift */; }; 228CC71E4BBA4CF0A7712FDD /* ApiInstantTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EFBCE62B1AD4A318A676B29 /* ApiInstantTests.swift */; };
3027E88493BA43B09B150BA1 /* MatchSessionLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9316C1429F9448ABC7BA7B6 /* MatchSessionLauncher.swift */; }; 252646FBD7F94CCEB49EE534 /* ScoreController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78C62B9683F44AA2A14D424A /* ScoreController.swift */; };
30F21F19C7234BBF8B2B77D4 /* BroadcastPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44FFA851A3BC44A784DF353A /* BroadcastPermissions.swift */; }; 255C09F3A1AB4FCC80DC403D /* KeepScreenOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E3FD0A68DC4FB6BB6F5DC3 /* KeepScreenOn.swift */; };
35FE18027B054D5BBC20DC9C /* MatchScoringRulesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 049297E3B0D44FF8840B8E76 /* MatchScoringRulesTests.swift */; }; 2F05B27C846F4284A533573D /* AuthRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FF6D203D77042EBAF2DB51F /* AuthRepository.swift */; };
39E01672805E4B8A88DA0FA9 /* ActionCableClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D36C4F09E5D04392B0B82EF8 /* ActionCableClient.swift */; }; 2F9195CCAE9949C087CECAA2 /* LiveScoreActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7122CAE2FBF04D59B28E3393 /* LiveScoreActions.swift */; };
3A08990CB238458CA25C07C9 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D603A791C926456D9B565F78 /* ShareSheet.swift */; }; 33848EA261D540879BABC0EC /* LiveBroadcastCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35FA1B77E81F48C5B4E55CD9 /* LiveBroadcastCoordinator.swift */; };
3AA28F966201426380DEE174 /* BroadcastOrientationPolicyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43DEDBA98F24BE996528018 /* BroadcastOrientationPolicyTests.swift */; }; 344B17113ADF4C548146080C /* MatchLiveTv/Resources/Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4F01AFBFEF6044C68CB26E01 /* MatchLiveTv/Resources/Assets.xcassets */; };
4598E75CCCF5492CB2F0B006 /* MatchColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2349A6BFDD4708B821C659 /* MatchColors.swift */; }; 34C4FE9AC892423FA42B0FA1 /* SessionRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87978C769F4E4D468052CC33 /* SessionRepository.swift */; };
464C286CAE724604AF9CC1FD /* MatchSecondaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1144C664590842258CBE9998 /* MatchSecondaryButton.swift */; }; 3D6496F4394A4A8B8280CCD7 /* MatchStatusBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 351CF0707AD942A58C630254 /* MatchStatusBadge.swift */; };
48719B5718B2419E96AE6AF2 /* SessionCableService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8AA247685DD45FD980465B0 /* SessionCableService.swift */; }; 412D04EC8F8344F3941D7774 /* ScoreRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB392D77E64247B3B093F616 /* ScoreRepository.swift */; };
4A67DD768F074E7885DFDF43 /* WizardShellScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E61E730231499C9F119309 /* WizardShellScreen.swift */; }; 44412124BE71497F89A100A7 /* OverlayState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A14E10B5AA8D45859AC6A1A4 /* OverlayState.swift */; };
4A6973ACDCA743B29ACC1E2E /* OverlayRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C397B3162F38497C9AD0C9CF /* OverlayRenderer.swift */; }; 4661478CC7C343379C100A7E /* MatchRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = E00E4AADECC140CDAD8C2AE6 /* MatchRepository.swift */; };
4BD05489BDAB4E309311B1C7 /* BroadcastVideoOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBA94A102E6C4E1BAF934D53 /* BroadcastVideoOrientation.swift */; }; 4B6FFF5D05164AE9AFB2833C /* StepMatchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5FCAE846D294A19A7981CA2 /* StepMatchScreen.swift */; };
4C2639382FE6A0440015AAF3 /* HaishinKit in Frameworks */ = {isa = PBXBuildFile; productRef = DFA0D0CEB1F1428D9E3FB3DB /* HaishinKit */; }; 4BF1F3719177402988F3E680 /* MatchLiveTvApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1FADDBD6A478FBA4D4047 /* MatchLiveTvApp.swift */; };
4C2639392FE6A0440015AAF3 /* RTMPHaishinKit in Frameworks */ = {isa = PBXBuildFile; productRef = AA756D8C68BC4B3D8EC96D5E /* RTMPHaishinKit */; }; 4C2639442FE6D7CF0015AAF3 /* HaishinKit in Frameworks */ = {isa = PBXBuildFile; productRef = 363FFDAD444D4381B6D23159 /* HaishinKit */; };
4CD8A3EB76C14F878BF1026C /* LiveScoreDialogHostTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F42DAF0103FD4213BE778C7C /* LiveScoreDialogHostTests.swift */; }; 4C2639452FE6D7CF0015AAF3 /* RTMPHaishinKit in Frameworks */ = {isa = PBXBuildFile; productRef = 3CEE882EC45E49D49BF6B568 /* RTMPHaishinKit */; };
51B03D8318114D3AB94A41CA /* SplashScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74D65108DA4C4A5BB95C0E51 /* SplashScreen.swift */; }; 4E3828F9935743CCB4B15F01 /* WizardComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 727F818455854A5C95A36750 /* WizardComponents.swift */; };
52DCD38F408B4BAE8A0A673D /* AppContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A62D39BF1BD343E2B314A150 /* AppContainer.swift */; }; 57499374CE314E5C9B19E857 /* OverlayLogoCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = A399280B3F39439986A8B8CA /* OverlayLogoCache.swift */; };
53A492E3510D4C8A9A5C94B7 /* ScoreController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C71579DA2945D5B0FA780C /* ScoreController.swift */; }; 5A085BBBD09B49A98A261FD1 /* StepNetworkTestScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1575FE5CDD584E119971A738 /* StepNetworkTestScreen.swift */; };
59BB3212FCBA4F68B23337F3 /* LiveBroadcastEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD491B8176A0430A9C3AB7B9 /* LiveBroadcastEngine.swift */; }; 5BD7A70803AE4BFCBED02E69 /* WizardSessionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C680C09D954141B3992BAE /* WizardSessionHolder.swift */; };
5A8E598237CF41BFB62B83D8 /* WizardSessionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF24FBB15BA4493EAEA78436 /* WizardSessionHolder.swift */; }; 62147CCDD37243B9AB328357 /* ColorHex.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2944504F54A4FFBBC27890E /* ColorHex.swift */; };
5D4E00AC5D4E44A09E3743DE /* MatchLiveTvApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3458504736B4137A749812C /* MatchLiveTvApp.swift */; }; 62F8E9A68AF84E04B5B25C0E /* LiveBroadcastEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03E8C38FF8F45E3B60876C4 /* LiveBroadcastEngine.swift */; };
5E33700F7C694E9D8EC997D7 /* ScreenOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E31852C7972040328E39C991 /* ScreenOrientation.swift */; }; 6312973A866D4191BA2E2E5E /* BroadcastPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B905649882624CD4BDFBAA1E /* BroadcastPermissions.swift */; };
644B22C2C7E54983A6BE393D /* LiveBroadcastCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB11018606164DAFBDC4E7A1 /* LiveBroadcastCoordinatorTests.swift */; }; 64D51E5990C34E64BBDD6153 /* MediaUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F5C50636970455FBD3C4C90 /* MediaUrl.swift */; };
66539A1D77EA4B368F5BDE2E /* StepMatchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B469A9557164A2682CEA145 /* StepMatchScreen.swift */; }; 6F38CD1E29CE4EDF92D2FCBD /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 218CB473E8054075A604031B /* AppConfig.swift */; };
6C52A9292D694A728A372551 /* ScoreControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C58DA984475413DB55C3E1B /* ScoreControllerTests.swift */; }; 70385A94466D4A2EA11DDB3B /* LivePreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE69BF72BE4435BEDA9133 /* LivePreviewView.swift */; };
6CA1DE649AEE455C994D0E94 /* MediaUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0487DB6D2DEB4508B5EF5FCC /* MediaUrl.swift */; }; 71A4EBF7C11441ED8202C4A5 /* SplashScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91EC9ED467E84061B684745A /* SplashScreen.swift */; };
6CC11041AFC64969BC9195D0 /* MatchScoringRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4974F7EF092B4FC697A30E00 /* MatchScoringRules.swift */; }; 72458A3A5D6D40D8B2B4362A /* ActionCableClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E73FCF20F1D4F148B9CD4B3 /* ActionCableClient.swift */; };
6DAD6078CC8D46FCB1AE0A75 /* MatchLiveWordmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE69B3EE8D0E4D8EAA8B853B /* MatchLiveWordmark.swift */; }; 72B22BECDAD64FE88CD38A25 /* BroadcastOrientationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED568E49E4044838349A540 /* BroadcastOrientationPolicy.swift */; };
6E09F9E1FBB3459B94343BDD /* OverlayLogoCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 224057D043A541C287071B37 /* OverlayLogoCache.swift */; }; 7360468C628E48AF950EF5CB /* StepTransmissionScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DFCC6BD2024FDBAB16BB74 /* StepTransmissionScreen.swift */; };
7862CEBEB345430F908DE135 /* OverlayState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE44F992D17E408D8713CC95 /* OverlayState.swift */; }; 7FAB1EF0F8D3459CB1A05CD5 /* OverlayCanvasRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2481408D6640FB9CC2CB2F /* OverlayCanvasRenderer.swift */; };
7B4182E19F93484B8B0D07DF /* WizardComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3490DEC22A543F890FEA661 /* WizardComponents.swift */; }; 844259AFBAF448C6ADBDE30C /* ApiDtos.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AD2477B899435F8D082A92 /* ApiDtos.swift */; };
7DCAA615F27C4853B8A0F889 /* SponsorElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8799BE797C4B4A409E32E753 /* SponsorElement.swift */; }; 85680F15BAC247B1AA97DC4D /* MatchPrimaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EB0CC339DE745259373D142 /* MatchPrimaryButton.swift */; };
82ADD6499C394031B87D7A96 /* ApiInstant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691EB1B5F9EA4DFB902E0D37 /* ApiInstant.swift */; }; 871F7D73227B4E699B65FE3D /* TeamBrandingEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E32781A593654542B0650E57 /* TeamBrandingEditor.swift */; };
8BAE2CEB56064BA3A3A16B53 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = D17AB6B00BBC4568A6D0457E /* Models.swift */; }; 8B26B443AD5C4FF388D448F5 /* LiveBroadcastCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5D916A7D894E119711065F /* LiveBroadcastCoordinatorTests.swift */; };
91C697AC57284A26A9893DFD /* OverlayMappings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC8DDF8DE68C4281B9062AD0 /* OverlayMappings.swift */; }; 9187B987AC034AAD887F6393 /* BroadcastOrientationPolicyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D291E7B6E7644EC49B08B1E3 /* BroadcastOrientationPolicyTests.swift */; };
91F1D3111F2C4BDFAB7435BF /* MatchScreenScaffold.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8FE87562E85488A946F8C86 /* MatchScreenScaffold.swift */; }; 942E7C8159B2490A9058D20A /* MatchScreenScaffold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324AD8EC837D48F5B6FFCEAA /* MatchScreenScaffold.swift */; };
921A1A2729B244C08A9BD3FD /* BroadcastControlsOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E0E8585555C42A6A220FF29 /* BroadcastControlsOverlay.swift */; }; 953EFFA2B63946A0818C82A1 /* CompactScoreboardElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 994567EE1DE14A20B92F4E96 /* CompactScoreboardElement.swift */; };
96E2427E81E744289D1C9B9B /* BroadcastModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC65D1EBC15F4ECB921A94F5 /* BroadcastModels.swift */; }; A5767FD88F8D4123A68224CD /* BroadcastScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72E46A99EFD841C5A1647DB8 /* BroadcastScreen.swift */; };
991371D458954C06A798AC0E /* LiveBroadcastCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8E0CCB4B0554F96B04BDB07 /* LiveBroadcastCoordinator.swift */; }; ABA512B1D2C7407E892623DE /* WatermarkElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16A9445555754FB7BDAADD3A /* WatermarkElement.swift */; };
994148BB9CCE4E6F800CD89A /* ColorHex.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4770AC3C14D451F89B35533 /* ColorHex.swift */; }; AD41DBD5504E4D3CB34B81B1 /* OverlayMappings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC64A2E1500E4ADB9ACE1A86 /* OverlayMappings.swift */; };
9D241B051BD54105A9D764DD /* BroadcastOrientationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBD03F804A944D6D84464875 /* BroadcastOrientationPolicy.swift */; }; AD9A1CB58F8C44EC92C5B4AE /* MatchScoringRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = B820270757EE42759E42FEEE /* MatchScoringRules.swift */; };
9E770D39394E41838877BC62 /* AuthRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0B5292C4B7344E98043FA55 /* AuthRepository.swift */; }; ADA537BB60354316AB3D343D /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500277E50C1A4646920A8543 /* Models.swift */; };
AEE1728EFF3F491A81B1156B /* LivePreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1123FED73ED4983BFBE9BB6 /* LivePreviewView.swift */; }; B6CA255BE2A840A7B21CDCCB /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638CBB9E0E874F7F95CBE204 /* ShareSheet.swift */; };
B3DD2F8E837649B2B007CEAF /* MatchHubFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4570572C5D4745A990B291D6 /* MatchHubFilter.swift */; }; B9DFB757CD3942AEBC1953F0 /* WizardShellScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828F33DF188D43AFB37FB0FE /* WizardShellScreen.swift */; };
B7D592901EC34D4B97DCE549 /* StepTransmissionScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74D13551050B4A51A21B0A67 /* StepTransmissionScreen.swift */; }; BCA11E5347BE4070B1883A58 /* AppNavHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90C96BCB45B4C70A4EFEDDA /* AppNavHost.swift */; };
C5EEE95F92D44046994659FC /* BroadcastScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E94110FC43754C50AC862D5C /* BroadcastScreen.swift */; }; BDAA05C294674E0A837D27AB /* MatchSecondaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8363E5303ADB4FD78519684F /* MatchSecondaryButton.swift */; };
C6B059D6435243208A8FC338 /* MatchesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40924F02DDFA4CCDA9488D64 /* MatchesScreen.swift */; }; BDF21E4064AC48D2BF2D3182 /* MatchSessionLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99BA29C831B4470DB25B2180 /* MatchSessionLauncher.swift */; };
CAABC65179F6467996D85730 /* UserFacingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5ECE7DA4A94297899495FF /* UserFacingError.swift */; }; C0E26D8B51484304B9234F89 /* BroadcastModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0E9DB4FB233435987DE957D /* BroadcastModels.swift */; };
D015D7ACCFE54071B1831C74 /* MatchPrimaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36263581FBC9465FB59A54A3 /* MatchPrimaryButton.swift */; }; C2479C699DF24364951AFFEC /* Routes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB101F16AF1494E8A143D0A /* Routes.swift */; };
D0BAD147978244529A46C040 /* CompactScoreboardElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B9968E881924270973373DD /* CompactScoreboardElement.swift */; }; C6B8E801C3E449ABBFA44F33 /* MatchColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33DE04949BC459E88BE9366 /* MatchColors.swift */; };
D3C28481960E4E14A0909DCB /* Routes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290C51105D0B4ABE997FA155 /* Routes.swift */; }; D44A9E22D1C241EA83B7A897 /* BroadcastVideoOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0997030621F749A3B9CDF588 /* BroadcastVideoOrientation.swift */; };
D501A7EE3BAD467A9A63E63C /* AppNavHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B41DFCE8AF4993A93F756A /* AppNavHost.swift */; }; D4EED1F5722B435695F1C09D /* ScreenOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60E331937B64477698ACF9B4 /* ScreenOrientation.swift */; };
D77980669AE84165AAF94AF2 /* MatchRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B77E9A6C51421D9AEDFF51 /* MatchRepository.swift */; }; D6ED4D033BA74DFFA968FC50 /* OverlayRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8079EC41BD47469013C0B2 /* OverlayRenderer.swift */; };
D916D4368A9A4298BDB3430F /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07588FE10B4143D8971F8A1F /* AppConfig.swift */; }; D74402BB72E04D8A816BC980 /* SessionCableService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153C1BAFFFD94507B3F4960D /* SessionCableService.swift */; };
EA533D28A4EF4171B410B56E /* ScoreState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 134FD1D616EF4F82A0175E28 /* ScoreState.swift */; }; DAA27DA77F904BA9B59684B1 /* ScoreboardElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F0128206567441BB807BB13 /* ScoreboardElement.swift */; };
EB8D708E665A46B398EB0C4F /* MatchLiveAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BCA039B9842405DBCB38BA5 /* MatchLiveAPI.swift */; }; DF8D47F8D9604F60B03E87F2 /* AppContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FF647CAD4FA457A8F37C5F0 /* AppContainer.swift */; };
EBB063DFDBE443F3BC12A67A /* ApiInstantTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C0FE41B109A41519495E952 /* ApiInstantTests.swift */; }; E2D089A57F9F49D887C0D233 /* ModalRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9818CDD6BBDF4E68B2F56E32 /* ModalRoutes.swift */; };
EE689B65571A474CA19A792C /* OverlayCanvasRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C561AB7965264974822DBD60 /* OverlayCanvasRenderer.swift */; }; E2E74A83D86544BA8FB85AAB /* TeamColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6338B84D52DA4FBA93DAE49A /* TeamColorPicker.swift */; };
EF83C38F78144E0996C33807 /* StepNetworkTestScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0D156DFC16945A3A8467EF0 /* StepNetworkTestScreen.swift */; }; E8D2C2E91DBE41BB9A1B59AF /* UserFacingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E556E7CE8E4407B926500E /* UserFacingError.swift */; };
F13AA7F009F1421FB996956B /* TeamBrandingEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AC1BB5EDAEE43359749B95A /* TeamBrandingEditor.swift */; }; F3907C6CC01447B786FF633F /* MatchesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8258C8C208E4AE2B37636E8 /* MatchesScreen.swift */; };
F13DF021E1084F6C844CB7AB /* MatchStatusBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7FA4E0FD3142D9957B764F /* MatchStatusBadge.swift */; }; FB09138978B3408ABBE91CD9 /* ScoreControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7814A010936047EBB4193446 /* ScoreControllerTests.swift */; };
FE21BE8932864B5D96D1BA41 /* MatchLiveTv/Resources/Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FE0CBD099ED14E62B752AB7F /* MatchLiveTv/Resources/Assets.xcassets */; }; FEE2AE0621F94EA393524C47 /* LiveScoreDialogHostTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740D32B076064CCDBE6A688F /* LiveScoreDialogHostTests.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
ACB2FE70CE4841CCB7A0ACC7 /* PBXContainerItemProxy */ = { 90C62964E51147DCABB6E3C2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 76FC637A5DFB4F018A0D1441 /* Project object */; containerPortal = DBE4153B1FC34F91BC390462 /* Project object */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = AE6E9D532CE6492D8B82687F; remoteGlobalIDString = 2F039DD838234B1F9B1B2FF5;
remoteInfo = MatchLiveTv; remoteInfo = MatchLiveTv;
}; };
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
0487DB6D2DEB4508B5EF5FCC /* MediaUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaUrl.swift; path = MatchLiveTv/Core/MediaUrl.swift; sourceTree = "<group>"; }; 0997030621F749A3B9CDF588 /* BroadcastVideoOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastVideoOrientation.swift; path = MatchLiveTv/Streaming/BroadcastVideoOrientation.swift; sourceTree = "<group>"; };
049297E3B0D44FF8840B8E76 /* MatchScoringRulesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScoringRulesTests.swift; path = MatchLiveTvTests/MatchScoringRulesTests.swift; sourceTree = "<group>"; }; 0FF6D203D77042EBAF2DB51F /* AuthRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthRepository.swift; path = MatchLiveTv/Data/Repository/AuthRepository.swift; sourceTree = "<group>"; };
07588FE10B4143D8971F8A1F /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppConfig.swift; path = MatchLiveTv/Core/AppConfig.swift; sourceTree = "<group>"; }; 153C1BAFFFD94507B3F4960D /* SessionCableService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionCableService.swift; path = MatchLiveTv/Data/Cable/SessionCableService.swift; sourceTree = "<group>"; };
1144C664590842258CBE9998 /* MatchSecondaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchSecondaryButton.swift; path = MatchLiveTv/UI/Components/MatchSecondaryButton.swift; sourceTree = "<group>"; }; 1575FE5CDD584E119971A738 /* StepNetworkTestScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepNetworkTestScreen.swift; path = MatchLiveTv/UI/Wizard/StepNetworkTestScreen.swift; sourceTree = "<group>"; };
134FD1D616EF4F82A0175E28 /* ScoreState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreState.swift; path = MatchLiveTv/Domain/ScoreState.swift; sourceTree = "<group>"; }; 16A9445555754FB7BDAADD3A /* WatermarkElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WatermarkElement.swift; path = MatchLiveTv/Streaming/Overlay/WatermarkElement.swift; sourceTree = "<group>"; };
1C3663CA3AD648B48EA4405D /* SessionRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionRepository.swift; path = MatchLiveTv/Data/Repository/SessionRepository.swift; sourceTree = "<group>"; }; 218CB473E8054075A604031B /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppConfig.swift; path = MatchLiveTv/Core/AppConfig.swift; sourceTree = "<group>"; };
1C58DA984475413DB55C3E1B /* ScoreControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreControllerTests.swift; path = MatchLiveTvTests/ScoreControllerTests.swift; sourceTree = "<group>"; }; 2D5396F45B5E40B1B1787C6E /* MatchLiveWordmark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveWordmark.swift; path = MatchLiveTv/UI/Components/MatchLiveWordmark.swift; sourceTree = "<group>"; };
224057D043A541C287071B37 /* OverlayLogoCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayLogoCache.swift; path = MatchLiveTv/Streaming/Overlay/OverlayLogoCache.swift; sourceTree = "<group>"; }; 324AD8EC837D48F5B6FFCEAA /* MatchScreenScaffold.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScreenScaffold.swift; path = MatchLiveTv/UI/Components/MatchScreenScaffold.swift; sourceTree = "<group>"; };
290C51105D0B4ABE997FA155 /* Routes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Routes.swift; path = MatchLiveTv/UI/Navigation/Routes.swift; sourceTree = "<group>"; }; 351CF0707AD942A58C630254 /* MatchStatusBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchStatusBadge.swift; path = MatchLiveTv/UI/Components/MatchStatusBadge.swift; sourceTree = "<group>"; };
2C3A3F3250284150B0A0BCD4 /* ModalRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ModalRoutes.swift; path = MatchLiveTv/UI/Navigation/ModalRoutes.swift; sourceTree = "<group>"; }; 358F960727AF4821B82A7791 /* MatchLiveTv/Resources/Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MatchLiveTv/Resources/Info.plist; sourceTree = "<group>"; };
36263581FBC9465FB59A54A3 /* MatchPrimaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchPrimaryButton.swift; path = MatchLiveTv/UI/Components/MatchPrimaryButton.swift; sourceTree = "<group>"; }; 35FA1B77E81F48C5B4E55CD9 /* LiveBroadcastCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastCoordinator.swift; path = MatchLiveTv/Streaming/LiveBroadcastCoordinator.swift; sourceTree = "<group>"; };
3C5ECE7DA4A94297899495FF /* UserFacingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UserFacingError.swift; path = MatchLiveTv/Core/UserFacingError.swift; sourceTree = "<group>"; }; 38E556E7CE8E4407B926500E /* UserFacingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UserFacingError.swift; path = MatchLiveTv/Core/UserFacingError.swift; sourceTree = "<group>"; };
40924F02DDFA4CCDA9488D64 /* MatchesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchesScreen.swift; path = MatchLiveTv/UI/Matches/MatchesScreen.swift; sourceTree = "<group>"; }; 3AB101F16AF1494E8A143D0A /* Routes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Routes.swift; path = MatchLiveTv/UI/Navigation/Routes.swift; sourceTree = "<group>"; };
44FFA851A3BC44A784DF353A /* BroadcastPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastPermissions.swift; path = MatchLiveTv/UI/Permissions/BroadcastPermissions.swift; sourceTree = "<group>"; }; 3E73FCF20F1D4F148B9CD4B3 /* ActionCableClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ActionCableClient.swift; path = MatchLiveTv/Data/Cable/ActionCableClient.swift; sourceTree = "<group>"; };
4570572C5D4745A990B291D6 /* MatchHubFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchHubFilter.swift; path = MatchLiveTv/Domain/MatchHubFilter.swift; sourceTree = "<group>"; }; 3EF4D8B887F6467699C4E184 /* SponsorElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SponsorElement.swift; path = MatchLiveTv/Streaming/Overlay/SponsorElement.swift; sourceTree = "<group>"; };
45C19E63F6E14B8A9B34AD29 /* MatchLiveTvTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatchLiveTvTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 4BA1FADDBD6A478FBA4D4047 /* MatchLiveTvApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveTvApp.swift; path = MatchLiveTv/App/MatchLiveTvApp.swift; sourceTree = "<group>"; };
4974F7EF092B4FC697A30E00 /* MatchScoringRules.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScoringRules.swift; path = MatchLiveTv/Domain/MatchScoringRules.swift; sourceTree = "<group>"; }; 4C77C273929F4A4A9079A55E /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LoginScreen.swift; path = MatchLiveTv/UI/Login/LoginScreen.swift; sourceTree = "<group>"; };
4B469A9557164A2682CEA145 /* StepMatchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepMatchScreen.swift; path = MatchLiveTv/UI/Wizard/StepMatchScreen.swift; sourceTree = "<group>"; }; 4F01AFBFEF6044C68CB26E01 /* MatchLiveTv/Resources/Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MatchLiveTv/Resources/Assets.xcassets; sourceTree = "<group>"; };
691EB1B5F9EA4DFB902E0D37 /* ApiInstant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiInstant.swift; path = MatchLiveTv/Core/ApiInstant.swift; sourceTree = "<group>"; }; 500277E50C1A4646920A8543 /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Models.swift; path = MatchLiveTv/Domain/Models.swift; sourceTree = "<group>"; };
6E0E8585555C42A6A220FF29 /* BroadcastControlsOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastControlsOverlay.swift; path = MatchLiveTv/UI/Broadcast/BroadcastControlsOverlay.swift; sourceTree = "<group>"; }; 51257C93F3A4464F8AA4B5B5 /* MatchScoringRulesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScoringRulesTests.swift; path = MatchLiveTvTests/MatchScoringRulesTests.swift; sourceTree = "<group>"; };
6EA61FF84F91473DA84438A8 /* ScoreboardElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreboardElement.swift; path = MatchLiveTv/Streaming/Overlay/ScoreboardElement.swift; sourceTree = "<group>"; }; 56E3FD0A68DC4FB6BB6F5DC3 /* KeepScreenOn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = KeepScreenOn.swift; path = MatchLiveTv/UI/System/KeepScreenOn.swift; sourceTree = "<group>"; };
6F6D45B70859402BA3ABD014 /* TeamColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TeamColorPicker.swift; path = MatchLiveTv/UI/Wizard/TeamColorPicker.swift; sourceTree = "<group>"; }; 60E331937B64477698ACF9B4 /* ScreenOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScreenOrientation.swift; path = MatchLiveTv/UI/System/ScreenOrientation.swift; sourceTree = "<group>"; };
74D13551050B4A51A21B0A67 /* StepTransmissionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepTransmissionScreen.swift; path = MatchLiveTv/UI/Wizard/StepTransmissionScreen.swift; sourceTree = "<group>"; }; 6338B84D52DA4FBA93DAE49A /* TeamColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TeamColorPicker.swift; path = MatchLiveTv/UI/Wizard/TeamColorPicker.swift; sourceTree = "<group>"; };
74D65108DA4C4A5BB95C0E51 /* SplashScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SplashScreen.swift; path = MatchLiveTv/UI/Splash/SplashScreen.swift; sourceTree = "<group>"; }; 638CBB9E0E874F7F95CBE204 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ShareSheet.swift; path = MatchLiveTv/UI/System/ShareSheet.swift; sourceTree = "<group>"; };
76B77E9A6C51421D9AEDFF51 /* MatchRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchRepository.swift; path = MatchLiveTv/Data/Repository/MatchRepository.swift; sourceTree = "<group>"; }; 64DFCC6BD2024FDBAB16BB74 /* StepTransmissionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepTransmissionScreen.swift; path = MatchLiveTv/UI/Wizard/StepTransmissionScreen.swift; sourceTree = "<group>"; };
7B2349A6BFDD4708B821C659 /* MatchColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchColors.swift; path = MatchLiveTv/UI/Theme/MatchColors.swift; sourceTree = "<group>"; }; 6EB0CC339DE745259373D142 /* MatchPrimaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchPrimaryButton.swift; path = MatchLiveTv/UI/Components/MatchPrimaryButton.swift; sourceTree = "<group>"; };
7B9968E881924270973373DD /* CompactScoreboardElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CompactScoreboardElement.swift; path = MatchLiveTv/Streaming/Overlay/CompactScoreboardElement.swift; sourceTree = "<group>"; }; 6F2481408D6640FB9CC2CB2F /* OverlayCanvasRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayCanvasRenderer.swift; path = MatchLiveTv/Streaming/Overlay/OverlayCanvasRenderer.swift; sourceTree = "<group>"; };
8799BE797C4B4A409E32E753 /* SponsorElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SponsorElement.swift; path = MatchLiveTv/Streaming/Overlay/SponsorElement.swift; sourceTree = "<group>"; }; 7122CAE2FBF04D59B28E3393 /* LiveScoreActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveScoreActions.swift; path = MatchLiveTv/UI/Broadcast/LiveScoreActions.swift; sourceTree = "<group>"; };
88C71579DA2945D5B0FA780C /* ScoreController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreController.swift; path = MatchLiveTv/Data/Scoring/ScoreController.swift; sourceTree = "<group>"; }; 727F818455854A5C95A36750 /* WizardComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardComponents.swift; path = MatchLiveTv/UI/Wizard/WizardComponents.swift; sourceTree = "<group>"; };
8DBA84B5B0CA459E89779309 /* WatermarkElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WatermarkElement.swift; path = MatchLiveTv/Streaming/Overlay/WatermarkElement.swift; sourceTree = "<group>"; }; 72E46A99EFD841C5A1647DB8 /* BroadcastScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastScreen.swift; path = MatchLiveTv/UI/Broadcast/BroadcastScreen.swift; sourceTree = "<group>"; };
96BA0FAD47DC40D48F063FC8 /* ScoreActionDecodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreActionDecodeTests.swift; path = MatchLiveTvTests/ScoreActionDecodeTests.swift; sourceTree = "<group>"; }; 740D32B076064CCDBE6A688F /* LiveScoreDialogHostTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveScoreDialogHostTests.swift; path = MatchLiveTvTests/LiveScoreDialogHostTests.swift; sourceTree = "<group>"; };
96E61E730231499C9F119309 /* WizardShellScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardShellScreen.swift; path = MatchLiveTv/UI/Wizard/WizardShellScreen.swift; sourceTree = "<group>"; }; 7814A010936047EBB4193446 /* ScoreControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreControllerTests.swift; path = MatchLiveTvTests/ScoreControllerTests.swift; sourceTree = "<group>"; };
9AC1BB5EDAEE43359749B95A /* TeamBrandingEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TeamBrandingEditor.swift; path = MatchLiveTv/UI/Wizard/TeamBrandingEditor.swift; sourceTree = "<group>"; }; 78C62B9683F44AA2A14D424A /* ScoreController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreController.swift; path = MatchLiveTv/Data/Scoring/ScoreController.swift; sourceTree = "<group>"; };
9BCA039B9842405DBCB38BA5 /* MatchLiveAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveAPI.swift; path = MatchLiveTv/Data/API/MatchLiveAPI.swift; sourceTree = "<group>"; }; 7C298D589A644368A5B3DB79 /* MatchHubFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchHubFilter.swift; path = MatchLiveTv/Domain/MatchHubFilter.swift; sourceTree = "<group>"; };
9C0FE41B109A41519495E952 /* ApiInstantTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiInstantTests.swift; path = MatchLiveTvTests/ApiInstantTests.swift; sourceTree = "<group>"; }; 7F5C50636970455FBD3C4C90 /* MediaUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaUrl.swift; path = MatchLiveTv/Core/MediaUrl.swift; sourceTree = "<group>"; };
A0DC8A3443404B0CAD323B11 /* KeepScreenOn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = KeepScreenOn.swift; path = MatchLiveTv/UI/System/KeepScreenOn.swift; sourceTree = "<group>"; }; 828F33DF188D43AFB37FB0FE /* WizardShellScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardShellScreen.swift; path = MatchLiveTv/UI/Wizard/WizardShellScreen.swift; sourceTree = "<group>"; };
A3B41DFCE8AF4993A93F756A /* AppNavHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppNavHost.swift; path = MatchLiveTv/UI/Navigation/AppNavHost.swift; sourceTree = "<group>"; }; 8363E5303ADB4FD78519684F /* MatchSecondaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchSecondaryButton.swift; path = MatchLiveTv/UI/Components/MatchSecondaryButton.swift; sourceTree = "<group>"; };
A62D39BF1BD343E2B314A150 /* AppContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppContainer.swift; path = MatchLiveTv/Data/AppContainer.swift; sourceTree = "<group>"; }; 87978C769F4E4D468052CC33 /* SessionRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionRepository.swift; path = MatchLiveTv/Data/Repository/SessionRepository.swift; sourceTree = "<group>"; };
A8FE87562E85488A946F8C86 /* MatchScreenScaffold.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScreenScaffold.swift; path = MatchLiveTv/UI/Components/MatchScreenScaffold.swift; sourceTree = "<group>"; }; 8F0128206567441BB807BB13 /* ScoreboardElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreboardElement.swift; path = MatchLiveTv/Streaming/Overlay/ScoreboardElement.swift; sourceTree = "<group>"; };
AAB84103176746DB89E76F33 /* MatchLiveTv.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MatchLiveTv.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8FF647CAD4FA457A8F37C5F0 /* AppContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppContainer.swift; path = MatchLiveTv/Data/AppContainer.swift; sourceTree = "<group>"; };
B1123FED73ED4983BFBE9BB6 /* LivePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LivePreviewView.swift; path = MatchLiveTv/Streaming/Preview/LivePreviewView.swift; sourceTree = "<group>"; }; 91EC9ED467E84061B684745A /* SplashScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SplashScreen.swift; path = MatchLiveTv/UI/Splash/SplashScreen.swift; sourceTree = "<group>"; };
B43DEDBA98F24BE996528018 /* BroadcastOrientationPolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastOrientationPolicyTests.swift; path = MatchLiveTvTests/BroadcastOrientationPolicyTests.swift; sourceTree = "<group>"; }; 9818CDD6BBDF4E68B2F56E32 /* ModalRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ModalRoutes.swift; path = MatchLiveTv/UI/Navigation/ModalRoutes.swift; sourceTree = "<group>"; };
BA7FA4E0FD3142D9957B764F /* MatchStatusBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchStatusBadge.swift; path = MatchLiveTv/UI/Components/MatchStatusBadge.swift; sourceTree = "<group>"; }; 994567EE1DE14A20B92F4E96 /* CompactScoreboardElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CompactScoreboardElement.swift; path = MatchLiveTv/Streaming/Overlay/CompactScoreboardElement.swift; sourceTree = "<group>"; };
BA8EB774A34C4E259AFB1C88 /* ScoreRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreRepository.swift; path = MatchLiveTv/Data/Repository/ScoreRepository.swift; sourceTree = "<group>"; }; 99BA29C831B4470DB25B2180 /* MatchSessionLauncher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchSessionLauncher.swift; path = MatchLiveTv/Data/Repository/MatchSessionLauncher.swift; sourceTree = "<group>"; };
BC5C7905A24E4AE1A0600511 /* DeviceTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeviceTelemetry.swift; path = MatchLiveTv/Core/DeviceTelemetry.swift; sourceTree = "<group>"; }; 9EFBCE62B1AD4A318A676B29 /* ApiInstantTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiInstantTests.swift; path = MatchLiveTvTests/ApiInstantTests.swift; sourceTree = "<group>"; };
BC65D1EBC15F4ECB921A94F5 /* BroadcastModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastModels.swift; path = MatchLiveTv/Streaming/BroadcastModels.swift; sourceTree = "<group>"; }; A0E9DB4FB233435987DE957D /* BroadcastModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastModels.swift; path = MatchLiveTv/Streaming/BroadcastModels.swift; sourceTree = "<group>"; };
BE69B3EE8D0E4D8EAA8B853B /* MatchLiveWordmark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveWordmark.swift; path = MatchLiveTv/UI/Components/MatchLiveWordmark.swift; sourceTree = "<group>"; }; A14E10B5AA8D45859AC6A1A4 /* OverlayState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayState.swift; path = MatchLiveTv/Streaming/Overlay/OverlayState.swift; sourceTree = "<group>"; };
C3458504736B4137A749812C /* MatchLiveTvApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveTvApp.swift; path = MatchLiveTv/App/MatchLiveTvApp.swift; sourceTree = "<group>"; }; A1AD2477B899435F8D082A92 /* ApiDtos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiDtos.swift; path = MatchLiveTv/Data/API/ApiDtos.swift; sourceTree = "<group>"; };
C397B3162F38497C9AD0C9CF /* OverlayRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayRenderer.swift; path = MatchLiveTv/Streaming/Overlay/OverlayRenderer.swift; sourceTree = "<group>"; }; A2DCC5443E58454998461BDB /* MatchLiveTv.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MatchLiveTv.app; sourceTree = BUILT_PRODUCTS_DIR; };
C561AB7965264974822DBD60 /* OverlayCanvasRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayCanvasRenderer.swift; path = MatchLiveTv/Streaming/Overlay/OverlayCanvasRenderer.swift; sourceTree = "<group>"; }; A399280B3F39439986A8B8CA /* OverlayLogoCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayLogoCache.swift; path = MatchLiveTv/Streaming/Overlay/OverlayLogoCache.swift; sourceTree = "<group>"; };
C7D1C27A80A842A1B531051C /* LiveScoreActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveScoreActions.swift; path = MatchLiveTv/UI/Broadcast/LiveScoreActions.swift; sourceTree = "<group>"; }; A5FCAE846D294A19A7981CA2 /* StepMatchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepMatchScreen.swift; path = MatchLiveTv/UI/Wizard/StepMatchScreen.swift; sourceTree = "<group>"; };
C8AA247685DD45FD980465B0 /* SessionCableService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionCableService.swift; path = MatchLiveTv/Data/Cable/SessionCableService.swift; sourceTree = "<group>"; }; A9BE69BF72BE4435BEDA9133 /* LivePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LivePreviewView.swift; path = MatchLiveTv/Streaming/Preview/LivePreviewView.swift; sourceTree = "<group>"; };
C8D2302B51D94A8984EC6A56 /* TokenStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TokenStore.swift; path = MatchLiveTv/Core/TokenStore.swift; sourceTree = "<group>"; }; B2944504F54A4FFBBC27890E /* ColorHex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorHex.swift; path = MatchLiveTv/Core/ColorHex.swift; sourceTree = "<group>"; };
CBA94A102E6C4E1BAF934D53 /* BroadcastVideoOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastVideoOrientation.swift; path = MatchLiveTv/Streaming/BroadcastVideoOrientation.swift; sourceTree = "<group>"; }; B7485A29DA1E4F7EB3D4116D /* MatchLiveAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveAPI.swift; path = MatchLiveTv/Data/API/MatchLiveAPI.swift; sourceTree = "<group>"; };
CD491B8176A0430A9C3AB7B9 /* LiveBroadcastEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastEngine.swift; path = MatchLiveTv/Streaming/LiveBroadcastEngine.swift; sourceTree = "<group>"; }; B820270757EE42759E42FEEE /* MatchScoringRules.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScoringRules.swift; path = MatchLiveTv/Domain/MatchScoringRules.swift; sourceTree = "<group>"; };
D17AB6B00BBC4568A6D0457E /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Models.swift; path = MatchLiveTv/Domain/Models.swift; sourceTree = "<group>"; }; B8258C8C208E4AE2B37636E8 /* MatchesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchesScreen.swift; path = MatchLiveTv/UI/Matches/MatchesScreen.swift; sourceTree = "<group>"; };
D36C4F09E5D04392B0B82EF8 /* ActionCableClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ActionCableClient.swift; path = MatchLiveTv/Data/Cable/ActionCableClient.swift; sourceTree = "<group>"; }; B905649882624CD4BDFBAA1E /* BroadcastPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastPermissions.swift; path = MatchLiveTv/UI/Permissions/BroadcastPermissions.swift; sourceTree = "<group>"; };
D4CD1243AC3D4BB8815BBE83 /* MatchLiveTv/Resources/Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MatchLiveTv/Resources/Info.plist; sourceTree = "<group>"; }; BB5D916A7D894E119711065F /* LiveBroadcastCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastCoordinatorTests.swift; path = MatchLiveTvTests/LiveBroadcastCoordinatorTests.swift; sourceTree = "<group>"; };
D603A791C926456D9B565F78 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ShareSheet.swift; path = MatchLiveTv/UI/System/ShareSheet.swift; sourceTree = "<group>"; }; C33DE04949BC459E88BE9366 /* MatchColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchColors.swift; path = MatchLiveTv/UI/Theme/MatchColors.swift; sourceTree = "<group>"; };
D9316C1429F9448ABC7BA7B6 /* MatchSessionLauncher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchSessionLauncher.swift; path = MatchLiveTv/Data/Repository/MatchSessionLauncher.swift; sourceTree = "<group>"; }; C7B37C6177BA4FC7AD4DE2C9 /* ScoreState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreState.swift; path = MatchLiveTv/Domain/ScoreState.swift; sourceTree = "<group>"; };
DE44F992D17E408D8713CC95 /* OverlayState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayState.swift; path = MatchLiveTv/Streaming/Overlay/OverlayState.swift; sourceTree = "<group>"; }; C90C96BCB45B4C70A4EFEDDA /* AppNavHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppNavHost.swift; path = MatchLiveTv/UI/Navigation/AppNavHost.swift; sourceTree = "<group>"; };
E0B5292C4B7344E98043FA55 /* AuthRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthRepository.swift; path = MatchLiveTv/Data/Repository/AuthRepository.swift; sourceTree = "<group>"; }; CC64A2E1500E4ADB9ACE1A86 /* OverlayMappings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayMappings.swift; path = MatchLiveTv/Streaming/Overlay/OverlayMappings.swift; sourceTree = "<group>"; };
E31852C7972040328E39C991 /* ScreenOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScreenOrientation.swift; path = MatchLiveTv/UI/System/ScreenOrientation.swift; sourceTree = "<group>"; }; CE8079EC41BD47469013C0B2 /* OverlayRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayRenderer.swift; path = MatchLiveTv/Streaming/Overlay/OverlayRenderer.swift; sourceTree = "<group>"; };
E4770AC3C14D451F89B35533 /* ColorHex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorHex.swift; path = MatchLiveTv/Core/ColorHex.swift; sourceTree = "<group>"; }; D291E7B6E7644EC49B08B1E3 /* BroadcastOrientationPolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastOrientationPolicyTests.swift; path = MatchLiveTvTests/BroadcastOrientationPolicyTests.swift; sourceTree = "<group>"; };
E8E0CCB4B0554F96B04BDB07 /* LiveBroadcastCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastCoordinator.swift; path = MatchLiveTv/Streaming/LiveBroadcastCoordinator.swift; sourceTree = "<group>"; }; D6DC6A6529B74BACBD05E817 /* MatchLiveTvTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatchLiveTvTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E94110FC43754C50AC862D5C /* BroadcastScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastScreen.swift; path = MatchLiveTv/UI/Broadcast/BroadcastScreen.swift; sourceTree = "<group>"; }; D7C680C09D954141B3992BAE /* WizardSessionHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardSessionHolder.swift; path = MatchLiveTv/Data/WizardSessionHolder.swift; sourceTree = "<group>"; };
EAEE3C8BBB684FEBA230480A /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LoginScreen.swift; path = MatchLiveTv/UI/Login/LoginScreen.swift; sourceTree = "<group>"; }; D9493EA978E6460FACFB7831 /* ScoreActionDecodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreActionDecodeTests.swift; path = MatchLiveTvTests/ScoreActionDecodeTests.swift; sourceTree = "<group>"; };
EB11018606164DAFBDC4E7A1 /* LiveBroadcastCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastCoordinatorTests.swift; path = MatchLiveTvTests/LiveBroadcastCoordinatorTests.swift; sourceTree = "<group>"; }; DB392D77E64247B3B093F616 /* ScoreRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreRepository.swift; path = MatchLiveTv/Data/Repository/ScoreRepository.swift; sourceTree = "<group>"; };
EBD03F804A944D6D84464875 /* BroadcastOrientationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastOrientationPolicy.swift; path = MatchLiveTv/Streaming/BroadcastOrientationPolicy.swift; sourceTree = "<group>"; }; E00E4AADECC140CDAD8C2AE6 /* MatchRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchRepository.swift; path = MatchLiveTv/Data/Repository/MatchRepository.swift; sourceTree = "<group>"; };
F0D156DFC16945A3A8467EF0 /* StepNetworkTestScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepNetworkTestScreen.swift; path = MatchLiveTv/UI/Wizard/StepNetworkTestScreen.swift; sourceTree = "<group>"; }; E32781A593654542B0650E57 /* TeamBrandingEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TeamBrandingEditor.swift; path = MatchLiveTv/UI/Wizard/TeamBrandingEditor.swift; sourceTree = "<group>"; };
F3490DEC22A543F890FEA661 /* WizardComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardComponents.swift; path = MatchLiveTv/UI/Wizard/WizardComponents.swift; sourceTree = "<group>"; }; E6CC04AA64F244128D7069F7 /* TokenStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TokenStore.swift; path = MatchLiveTv/Core/TokenStore.swift; sourceTree = "<group>"; };
F3DF95A27A584535A1511035 /* ApiDtos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiDtos.swift; path = MatchLiveTv/Data/API/ApiDtos.swift; sourceTree = "<group>"; }; F03E8C38FF8F45E3B60876C4 /* LiveBroadcastEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastEngine.swift; path = MatchLiveTv/Streaming/LiveBroadcastEngine.swift; sourceTree = "<group>"; };
F42DAF0103FD4213BE778C7C /* LiveScoreDialogHostTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveScoreDialogHostTests.swift; path = MatchLiveTvTests/LiveScoreDialogHostTests.swift; sourceTree = "<group>"; }; F52E5A9320FD4A9C82C64092 /* ApiInstant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiInstant.swift; path = MatchLiveTv/Core/ApiInstant.swift; sourceTree = "<group>"; };
FC8DDF8DE68C4281B9062AD0 /* OverlayMappings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayMappings.swift; path = MatchLiveTv/Streaming/Overlay/OverlayMappings.swift; sourceTree = "<group>"; }; F9652ABD17F34BF7B781F9CB /* BroadcastControlsOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastControlsOverlay.swift; path = MatchLiveTv/UI/Broadcast/BroadcastControlsOverlay.swift; sourceTree = "<group>"; };
FE0CBD099ED14E62B752AB7F /* MatchLiveTv/Resources/Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MatchLiveTv/Resources/Assets.xcassets; sourceTree = "<group>"; }; FD66A152068843A89E25EA2A /* DeviceTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeviceTelemetry.swift; path = MatchLiveTv/Core/DeviceTelemetry.swift; sourceTree = "<group>"; };
FF24FBB15BA4493EAEA78436 /* WizardSessionHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardSessionHolder.swift; path = MatchLiveTv/Data/WizardSessionHolder.swift; sourceTree = "<group>"; }; FED568E49E4044838349A540 /* BroadcastOrientationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastOrientationPolicy.swift; path = MatchLiveTv/Streaming/BroadcastOrientationPolicy.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
2DFB0C53187A482B83E1F38B /* Frameworks */ = { EC74ACD5FC794566A431A35D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
4C2639392FE6A0440015AAF3 /* RTMPHaishinKit in Frameworks */, 4C2639452FE6D7CF0015AAF3 /* RTMPHaishinKit in Frameworks */,
4C2639382FE6A0440015AAF3 /* HaishinKit in Frameworks */, 4C2639442FE6D7CF0015AAF3 /* HaishinKit in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
C180AAFADE0640639A940144 /* Frameworks */ = { F4997458E6A441FFAF9F30AD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
@@ -193,108 +193,108 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
14EA3A4718794D36964484DB = { 04C16256D74947F49F3C9F65 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
EB01519A0F5446FABA7B5012 /* MatchLiveTv */, A2DCC5443E58454998461BDB /* MatchLiveTv.app */,
C469ABBC533140A1A97C78AA /* MatchLiveTvTests */, D6DC6A6529B74BACBD05E817 /* MatchLiveTvTests.xctest */,
6668FF0B6F2E4C60861A918C /* Products */,
);
sourceTree = "<group>";
};
6668FF0B6F2E4C60861A918C /* Products */ = {
isa = PBXGroup;
children = (
AAB84103176746DB89E76F33 /* MatchLiveTv.app */,
45C19E63F6E14B8A9B34AD29 /* MatchLiveTvTests.xctest */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
C469ABBC533140A1A97C78AA /* MatchLiveTvTests */ = { 24B89ABF583C445F8BE6725C /* MatchLiveTvTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
9C0FE41B109A41519495E952 /* ApiInstantTests.swift */, 9EFBCE62B1AD4A318A676B29 /* ApiInstantTests.swift */,
B43DEDBA98F24BE996528018 /* BroadcastOrientationPolicyTests.swift */, D291E7B6E7644EC49B08B1E3 /* BroadcastOrientationPolicyTests.swift */,
EB11018606164DAFBDC4E7A1 /* LiveBroadcastCoordinatorTests.swift */, BB5D916A7D894E119711065F /* LiveBroadcastCoordinatorTests.swift */,
F42DAF0103FD4213BE778C7C /* LiveScoreDialogHostTests.swift */, 740D32B076064CCDBE6A688F /* LiveScoreDialogHostTests.swift */,
049297E3B0D44FF8840B8E76 /* MatchScoringRulesTests.swift */, 51257C93F3A4464F8AA4B5B5 /* MatchScoringRulesTests.swift */,
96BA0FAD47DC40D48F063FC8 /* ScoreActionDecodeTests.swift */, D9493EA978E6460FACFB7831 /* ScoreActionDecodeTests.swift */,
1C58DA984475413DB55C3E1B /* ScoreControllerTests.swift */, 7814A010936047EBB4193446 /* ScoreControllerTests.swift */,
); );
name = MatchLiveTvTests; name = MatchLiveTvTests;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
EB01519A0F5446FABA7B5012 /* MatchLiveTv */ = { 64400CD6009C4B9FB7362229 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
C3458504736B4137A749812C /* MatchLiveTvApp.swift */, EA914F8374EB40228298872E /* MatchLiveTv */,
691EB1B5F9EA4DFB902E0D37 /* ApiInstant.swift */, 24B89ABF583C445F8BE6725C /* MatchLiveTvTests */,
07588FE10B4143D8971F8A1F /* AppConfig.swift */, 04C16256D74947F49F3C9F65 /* Products */,
E4770AC3C14D451F89B35533 /* ColorHex.swift */, );
BC5C7905A24E4AE1A0600511 /* DeviceTelemetry.swift */, sourceTree = "<group>";
0487DB6D2DEB4508B5EF5FCC /* MediaUrl.swift */, };
C8D2302B51D94A8984EC6A56 /* TokenStore.swift */, EA914F8374EB40228298872E /* MatchLiveTv */ = {
3C5ECE7DA4A94297899495FF /* UserFacingError.swift */, isa = PBXGroup;
F3DF95A27A584535A1511035 /* ApiDtos.swift */, children = (
9BCA039B9842405DBCB38BA5 /* MatchLiveAPI.swift */, 4BA1FADDBD6A478FBA4D4047 /* MatchLiveTvApp.swift */,
A62D39BF1BD343E2B314A150 /* AppContainer.swift */, F52E5A9320FD4A9C82C64092 /* ApiInstant.swift */,
D36C4F09E5D04392B0B82EF8 /* ActionCableClient.swift */, 218CB473E8054075A604031B /* AppConfig.swift */,
C8AA247685DD45FD980465B0 /* SessionCableService.swift */, B2944504F54A4FFBBC27890E /* ColorHex.swift */,
E0B5292C4B7344E98043FA55 /* AuthRepository.swift */, FD66A152068843A89E25EA2A /* DeviceTelemetry.swift */,
76B77E9A6C51421D9AEDFF51 /* MatchRepository.swift */, 7F5C50636970455FBD3C4C90 /* MediaUrl.swift */,
D9316C1429F9448ABC7BA7B6 /* MatchSessionLauncher.swift */, E6CC04AA64F244128D7069F7 /* TokenStore.swift */,
BA8EB774A34C4E259AFB1C88 /* ScoreRepository.swift */, 38E556E7CE8E4407B926500E /* UserFacingError.swift */,
1C3663CA3AD648B48EA4405D /* SessionRepository.swift */, A1AD2477B899435F8D082A92 /* ApiDtos.swift */,
88C71579DA2945D5B0FA780C /* ScoreController.swift */, B7485A29DA1E4F7EB3D4116D /* MatchLiveAPI.swift */,
FF24FBB15BA4493EAEA78436 /* WizardSessionHolder.swift */, 8FF647CAD4FA457A8F37C5F0 /* AppContainer.swift */,
4570572C5D4745A990B291D6 /* MatchHubFilter.swift */, 3E73FCF20F1D4F148B9CD4B3 /* ActionCableClient.swift */,
4974F7EF092B4FC697A30E00 /* MatchScoringRules.swift */, 153C1BAFFFD94507B3F4960D /* SessionCableService.swift */,
D17AB6B00BBC4568A6D0457E /* Models.swift */, 0FF6D203D77042EBAF2DB51F /* AuthRepository.swift */,
134FD1D616EF4F82A0175E28 /* ScoreState.swift */, E00E4AADECC140CDAD8C2AE6 /* MatchRepository.swift */,
BC65D1EBC15F4ECB921A94F5 /* BroadcastModels.swift */, 99BA29C831B4470DB25B2180 /* MatchSessionLauncher.swift */,
EBD03F804A944D6D84464875 /* BroadcastOrientationPolicy.swift */, DB392D77E64247B3B093F616 /* ScoreRepository.swift */,
CBA94A102E6C4E1BAF934D53 /* BroadcastVideoOrientation.swift */, 87978C769F4E4D468052CC33 /* SessionRepository.swift */,
E8E0CCB4B0554F96B04BDB07 /* LiveBroadcastCoordinator.swift */, 78C62B9683F44AA2A14D424A /* ScoreController.swift */,
CD491B8176A0430A9C3AB7B9 /* LiveBroadcastEngine.swift */, D7C680C09D954141B3992BAE /* WizardSessionHolder.swift */,
7B9968E881924270973373DD /* CompactScoreboardElement.swift */, 7C298D589A644368A5B3DB79 /* MatchHubFilter.swift */,
C561AB7965264974822DBD60 /* OverlayCanvasRenderer.swift */, B820270757EE42759E42FEEE /* MatchScoringRules.swift */,
224057D043A541C287071B37 /* OverlayLogoCache.swift */, 500277E50C1A4646920A8543 /* Models.swift */,
FC8DDF8DE68C4281B9062AD0 /* OverlayMappings.swift */, C7B37C6177BA4FC7AD4DE2C9 /* ScoreState.swift */,
C397B3162F38497C9AD0C9CF /* OverlayRenderer.swift */, A0E9DB4FB233435987DE957D /* BroadcastModels.swift */,
DE44F992D17E408D8713CC95 /* OverlayState.swift */, FED568E49E4044838349A540 /* BroadcastOrientationPolicy.swift */,
6EA61FF84F91473DA84438A8 /* ScoreboardElement.swift */, 0997030621F749A3B9CDF588 /* BroadcastVideoOrientation.swift */,
8799BE797C4B4A409E32E753 /* SponsorElement.swift */, 35FA1B77E81F48C5B4E55CD9 /* LiveBroadcastCoordinator.swift */,
8DBA84B5B0CA459E89779309 /* WatermarkElement.swift */, F03E8C38FF8F45E3B60876C4 /* LiveBroadcastEngine.swift */,
B1123FED73ED4983BFBE9BB6 /* LivePreviewView.swift */, 994567EE1DE14A20B92F4E96 /* CompactScoreboardElement.swift */,
6E0E8585555C42A6A220FF29 /* BroadcastControlsOverlay.swift */, 6F2481408D6640FB9CC2CB2F /* OverlayCanvasRenderer.swift */,
E94110FC43754C50AC862D5C /* BroadcastScreen.swift */, A399280B3F39439986A8B8CA /* OverlayLogoCache.swift */,
C7D1C27A80A842A1B531051C /* LiveScoreActions.swift */, CC64A2E1500E4ADB9ACE1A86 /* OverlayMappings.swift */,
BE69B3EE8D0E4D8EAA8B853B /* MatchLiveWordmark.swift */, CE8079EC41BD47469013C0B2 /* OverlayRenderer.swift */,
36263581FBC9465FB59A54A3 /* MatchPrimaryButton.swift */, A14E10B5AA8D45859AC6A1A4 /* OverlayState.swift */,
A8FE87562E85488A946F8C86 /* MatchScreenScaffold.swift */, 8F0128206567441BB807BB13 /* ScoreboardElement.swift */,
1144C664590842258CBE9998 /* MatchSecondaryButton.swift */, 3EF4D8B887F6467699C4E184 /* SponsorElement.swift */,
BA7FA4E0FD3142D9957B764F /* MatchStatusBadge.swift */, 16A9445555754FB7BDAADD3A /* WatermarkElement.swift */,
EAEE3C8BBB684FEBA230480A /* LoginScreen.swift */, A9BE69BF72BE4435BEDA9133 /* LivePreviewView.swift */,
40924F02DDFA4CCDA9488D64 /* MatchesScreen.swift */, F9652ABD17F34BF7B781F9CB /* BroadcastControlsOverlay.swift */,
A3B41DFCE8AF4993A93F756A /* AppNavHost.swift */, 72E46A99EFD841C5A1647DB8 /* BroadcastScreen.swift */,
2C3A3F3250284150B0A0BCD4 /* ModalRoutes.swift */, 7122CAE2FBF04D59B28E3393 /* LiveScoreActions.swift */,
290C51105D0B4ABE997FA155 /* Routes.swift */, 2D5396F45B5E40B1B1787C6E /* MatchLiveWordmark.swift */,
44FFA851A3BC44A784DF353A /* BroadcastPermissions.swift */, 6EB0CC339DE745259373D142 /* MatchPrimaryButton.swift */,
74D65108DA4C4A5BB95C0E51 /* SplashScreen.swift */, 324AD8EC837D48F5B6FFCEAA /* MatchScreenScaffold.swift */,
A0DC8A3443404B0CAD323B11 /* KeepScreenOn.swift */, 8363E5303ADB4FD78519684F /* MatchSecondaryButton.swift */,
E31852C7972040328E39C991 /* ScreenOrientation.swift */, 351CF0707AD942A58C630254 /* MatchStatusBadge.swift */,
D603A791C926456D9B565F78 /* ShareSheet.swift */, 4C77C273929F4A4A9079A55E /* LoginScreen.swift */,
7B2349A6BFDD4708B821C659 /* MatchColors.swift */, B8258C8C208E4AE2B37636E8 /* MatchesScreen.swift */,
4B469A9557164A2682CEA145 /* StepMatchScreen.swift */, C90C96BCB45B4C70A4EFEDDA /* AppNavHost.swift */,
F0D156DFC16945A3A8467EF0 /* StepNetworkTestScreen.swift */, 9818CDD6BBDF4E68B2F56E32 /* ModalRoutes.swift */,
74D13551050B4A51A21B0A67 /* StepTransmissionScreen.swift */, 3AB101F16AF1494E8A143D0A /* Routes.swift */,
9AC1BB5EDAEE43359749B95A /* TeamBrandingEditor.swift */, B905649882624CD4BDFBAA1E /* BroadcastPermissions.swift */,
6F6D45B70859402BA3ABD014 /* TeamColorPicker.swift */, 91EC9ED467E84061B684745A /* SplashScreen.swift */,
F3490DEC22A543F890FEA661 /* WizardComponents.swift */, 56E3FD0A68DC4FB6BB6F5DC3 /* KeepScreenOn.swift */,
96E61E730231499C9F119309 /* WizardShellScreen.swift */, 60E331937B64477698ACF9B4 /* ScreenOrientation.swift */,
FE0CBD099ED14E62B752AB7F /* MatchLiveTv/Resources/Assets.xcassets */, 638CBB9E0E874F7F95CBE204 /* ShareSheet.swift */,
D4CD1243AC3D4BB8815BBE83 /* MatchLiveTv/Resources/Info.plist */, C33DE04949BC459E88BE9366 /* MatchColors.swift */,
A5FCAE846D294A19A7981CA2 /* StepMatchScreen.swift */,
1575FE5CDD584E119971A738 /* StepNetworkTestScreen.swift */,
64DFCC6BD2024FDBAB16BB74 /* StepTransmissionScreen.swift */,
E32781A593654542B0650E57 /* TeamBrandingEditor.swift */,
6338B84D52DA4FBA93DAE49A /* TeamColorPicker.swift */,
727F818455854A5C95A36750 /* WizardComponents.swift */,
828F33DF188D43AFB37FB0FE /* WizardShellScreen.swift */,
4F01AFBFEF6044C68CB26E01 /* MatchLiveTv/Resources/Assets.xcassets */,
358F960727AF4821B82A7791 /* MatchLiveTv/Resources/Info.plist */,
); );
name = MatchLiveTv; name = MatchLiveTv;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -302,30 +302,13 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
64F84AC8A424490D945D5B65 /* MatchLiveTvTests */ = { 2F039DD838234B1F9B1B2FF5 /* MatchLiveTv */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = E3DA5397819945D09DC337F6 /* Build configuration list for PBXNativeTarget "MatchLiveTvTests" */; buildConfigurationList = 7F122D777A6E41C9BD148CDD /* Build configuration list for PBXNativeTarget "MatchLiveTv" */;
buildPhases = ( buildPhases = (
3245C286B7A54008850C0923 /* Sources */, AD28C1C2220D4921862D734A /* Sources */,
C180AAFADE0640639A940144 /* Frameworks */, EC74ACD5FC794566A431A35D /* Frameworks */,
); CA170C64969345F0974EA381 /* Resources */,
buildRules = (
);
dependencies = (
4264391B98534ED485BCB343 /* PBXTargetDependency */,
);
name = MatchLiveTvTests;
productName = MatchLiveTvTests;
productReference = 45C19E63F6E14B8A9B34AD29 /* MatchLiveTvTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
AE6E9D532CE6492D8B82687F /* MatchLiveTv */ = {
isa = PBXNativeTarget;
buildConfigurationList = 002C5EF177A5409AAE23DB38 /* Build configuration list for PBXNativeTarget "MatchLiveTv" */;
buildPhases = (
AC8B6077C49C4F0086F06F1B /* Sources */,
2DFB0C53187A482B83E1F38B /* Frameworks */,
1C0CE5A5B45A41CBA8B910D1 /* Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -333,23 +316,40 @@
); );
name = MatchLiveTv; name = MatchLiveTv;
packageProductDependencies = ( packageProductDependencies = (
DFA0D0CEB1F1428D9E3FB3DB /* HaishinKit */, 363FFDAD444D4381B6D23159 /* HaishinKit */,
AA756D8C68BC4B3D8EC96D5E /* RTMPHaishinKit */, 3CEE882EC45E49D49BF6B568 /* RTMPHaishinKit */,
); );
productName = MatchLiveTv; productName = MatchLiveTv;
productReference = AAB84103176746DB89E76F33 /* MatchLiveTv.app */; productReference = A2DCC5443E58454998461BDB /* MatchLiveTv.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
F441C7131D0345549D8CA917 /* MatchLiveTvTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 271ADC46052246A38FB0DFCE /* Build configuration list for PBXNativeTarget "MatchLiveTvTests" */;
buildPhases = (
79D8DB6A21534CC695AEAAD3 /* Sources */,
F4997458E6A441FFAF9F30AD /* Frameworks */,
);
buildRules = (
);
dependencies = (
953DB6F101304B388EBFB376 /* PBXTargetDependency */,
);
name = MatchLiveTvTests;
productName = MatchLiveTvTests;
productReference = D6DC6A6529B74BACBD05E817 /* MatchLiveTvTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
76FC637A5DFB4F018A0D1441 /* Project object */ = { DBE4153B1FC34F91BC390462 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
BuildIndependentTargetsInParallel = 0; BuildIndependentTargetsInParallel = 0;
LastSwiftUpdateCheck = 1600; LastSwiftUpdateCheck = 1600;
}; };
buildConfigurationList = 27F2A4CC59994B3CA41841F5 /* Build configuration list for PBXProject "MatchLiveTv" */; buildConfigurationList = 1E22BBCE2E7C4E1DBD22BF81 /* Build configuration list for PBXProject "MatchLiveTv" */;
compatibilityVersion = "Xcode 15.0"; compatibilityVersion = "Xcode 15.0";
developmentRegion = it; developmentRegion = it;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
@@ -358,130 +358,164 @@
en, en,
Base, Base,
); );
mainGroup = 14EA3A4718794D36964484DB; mainGroup = 64400CD6009C4B9FB7362229;
packageReferences = ( packageReferences = (
2DAE333E666A41BE8A5F1148 /* XCRemoteSwiftPackageReference "HaishinKit" */, 3FD2C0913F9E4659A9B8920D /* XCRemoteSwiftPackageReference "HaishinKit" */,
); );
productRefGroup = 6668FF0B6F2E4C60861A918C /* Products */; productRefGroup = 04C16256D74947F49F3C9F65 /* Products */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
AE6E9D532CE6492D8B82687F /* MatchLiveTv */, 2F039DD838234B1F9B1B2FF5 /* MatchLiveTv */,
64F84AC8A424490D945D5B65 /* MatchLiveTvTests */, F441C7131D0345549D8CA917 /* MatchLiveTvTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */ /* Begin PBXResourcesBuildPhase section */
1C0CE5A5B45A41CBA8B910D1 /* Resources */ = { CA170C64969345F0974EA381 /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
FE21BE8932864B5D96D1BA41 /* MatchLiveTv/Resources/Assets.xcassets in Resources */, 344B17113ADF4C548146080C /* MatchLiveTv/Resources/Assets.xcassets in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
3245C286B7A54008850C0923 /* Sources */ = { 79D8DB6A21534CC695AEAAD3 /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
EBB063DFDBE443F3BC12A67A /* ApiInstantTests.swift in Sources */, 228CC71E4BBA4CF0A7712FDD /* ApiInstantTests.swift in Sources */,
3AA28F966201426380DEE174 /* BroadcastOrientationPolicyTests.swift in Sources */, 9187B987AC034AAD887F6393 /* BroadcastOrientationPolicyTests.swift in Sources */,
644B22C2C7E54983A6BE393D /* LiveBroadcastCoordinatorTests.swift in Sources */, 8B26B443AD5C4FF388D448F5 /* LiveBroadcastCoordinatorTests.swift in Sources */,
4CD8A3EB76C14F878BF1026C /* LiveScoreDialogHostTests.swift in Sources */, FEE2AE0621F94EA393524C47 /* LiveScoreDialogHostTests.swift in Sources */,
35FE18027B054D5BBC20DC9C /* MatchScoringRulesTests.swift in Sources */, 05E2509B1F96460F9A8FBDEE /* MatchScoringRulesTests.swift in Sources */,
2498A1488A034D058E6997B0 /* ScoreActionDecodeTests.swift in Sources */, 2094E19DDAD0464B9CED0495 /* ScoreActionDecodeTests.swift in Sources */,
6C52A9292D694A728A372551 /* ScoreControllerTests.swift in Sources */, FB09138978B3408ABBE91CD9 /* ScoreControllerTests.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
AC8B6077C49C4F0086F06F1B /* Sources */ = { AD28C1C2220D4921862D734A /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
5D4E00AC5D4E44A09E3743DE /* MatchLiveTvApp.swift in Sources */, 4BF1F3719177402988F3E680 /* MatchLiveTvApp.swift in Sources */,
82ADD6499C394031B87D7A96 /* ApiInstant.swift in Sources */, 0811090F35B647A9AAE98018 /* ApiInstant.swift in Sources */,
D916D4368A9A4298BDB3430F /* AppConfig.swift in Sources */, 6F38CD1E29CE4EDF92D2FCBD /* AppConfig.swift in Sources */,
994148BB9CCE4E6F800CD89A /* ColorHex.swift in Sources */, 62147CCDD37243B9AB328357 /* ColorHex.swift in Sources */,
22A2A4F3BBD845C5B4E1DD6E /* DeviceTelemetry.swift in Sources */, 1191C9F3433D4C79BB1D55CA /* DeviceTelemetry.swift in Sources */,
6CA1DE649AEE455C994D0E94 /* MediaUrl.swift in Sources */, 64D51E5990C34E64BBDD6153 /* MediaUrl.swift in Sources */,
284F82D0FB65448BAB38C6BE /* TokenStore.swift in Sources */, 17F54C8204F346CCA9EBFF89 /* TokenStore.swift in Sources */,
CAABC65179F6467996D85730 /* UserFacingError.swift in Sources */, E8D2C2E91DBE41BB9A1B59AF /* UserFacingError.swift in Sources */,
2D3FAEEE0372415381467FC7 /* ApiDtos.swift in Sources */, 844259AFBAF448C6ADBDE30C /* ApiDtos.swift in Sources */,
EB8D708E665A46B398EB0C4F /* MatchLiveAPI.swift in Sources */, 1B65AFB2A2A54BD69FE9D4D3 /* MatchLiveAPI.swift in Sources */,
52DCD38F408B4BAE8A0A673D /* AppContainer.swift in Sources */, DF8D47F8D9604F60B03E87F2 /* AppContainer.swift in Sources */,
39E01672805E4B8A88DA0FA9 /* ActionCableClient.swift in Sources */, 72458A3A5D6D40D8B2B4362A /* ActionCableClient.swift in Sources */,
48719B5718B2419E96AE6AF2 /* SessionCableService.swift in Sources */, D74402BB72E04D8A816BC980 /* SessionCableService.swift in Sources */,
9E770D39394E41838877BC62 /* AuthRepository.swift in Sources */, 2F05B27C846F4284A533573D /* AuthRepository.swift in Sources */,
D77980669AE84165AAF94AF2 /* MatchRepository.swift in Sources */, 4661478CC7C343379C100A7E /* MatchRepository.swift in Sources */,
3027E88493BA43B09B150BA1 /* MatchSessionLauncher.swift in Sources */, BDF21E4064AC48D2BF2D3182 /* MatchSessionLauncher.swift in Sources */,
0E03BE40DAF14E98A35051CE /* ScoreRepository.swift in Sources */, 412D04EC8F8344F3941D7774 /* ScoreRepository.swift in Sources */,
045086A670F24B1192E0DF8F /* SessionRepository.swift in Sources */, 34C4FE9AC892423FA42B0FA1 /* SessionRepository.swift in Sources */,
53A492E3510D4C8A9A5C94B7 /* ScoreController.swift in Sources */, 252646FBD7F94CCEB49EE534 /* ScoreController.swift in Sources */,
5A8E598237CF41BFB62B83D8 /* WizardSessionHolder.swift in Sources */, 5BD7A70803AE4BFCBED02E69 /* WizardSessionHolder.swift in Sources */,
B3DD2F8E837649B2B007CEAF /* MatchHubFilter.swift in Sources */, 0ABF8F2EAEF84F3CB3510FCA /* MatchHubFilter.swift in Sources */,
6CC11041AFC64969BC9195D0 /* MatchScoringRules.swift in Sources */, AD9A1CB58F8C44EC92C5B4AE /* MatchScoringRules.swift in Sources */,
8BAE2CEB56064BA3A3A16B53 /* Models.swift in Sources */, ADA537BB60354316AB3D343D /* Models.swift in Sources */,
EA533D28A4EF4171B410B56E /* ScoreState.swift in Sources */, 16D77B1BA1694BC9AAEACACA /* ScoreState.swift in Sources */,
96E2427E81E744289D1C9B9B /* BroadcastModels.swift in Sources */, C0E26D8B51484304B9234F89 /* BroadcastModels.swift in Sources */,
9D241B051BD54105A9D764DD /* BroadcastOrientationPolicy.swift in Sources */, 72B22BECDAD64FE88CD38A25 /* BroadcastOrientationPolicy.swift in Sources */,
4BD05489BDAB4E309311B1C7 /* BroadcastVideoOrientation.swift in Sources */, D44A9E22D1C241EA83B7A897 /* BroadcastVideoOrientation.swift in Sources */,
991371D458954C06A798AC0E /* LiveBroadcastCoordinator.swift in Sources */, 33848EA261D540879BABC0EC /* LiveBroadcastCoordinator.swift in Sources */,
59BB3212FCBA4F68B23337F3 /* LiveBroadcastEngine.swift in Sources */, 62F8E9A68AF84E04B5B25C0E /* LiveBroadcastEngine.swift in Sources */,
D0BAD147978244529A46C040 /* CompactScoreboardElement.swift in Sources */, 953EFFA2B63946A0818C82A1 /* CompactScoreboardElement.swift in Sources */,
EE689B65571A474CA19A792C /* OverlayCanvasRenderer.swift in Sources */, 7FAB1EF0F8D3459CB1A05CD5 /* OverlayCanvasRenderer.swift in Sources */,
6E09F9E1FBB3459B94343BDD /* OverlayLogoCache.swift in Sources */, 57499374CE314E5C9B19E857 /* OverlayLogoCache.swift in Sources */,
91C697AC57284A26A9893DFD /* OverlayMappings.swift in Sources */, AD41DBD5504E4D3CB34B81B1 /* OverlayMappings.swift in Sources */,
4A6973ACDCA743B29ACC1E2E /* OverlayRenderer.swift in Sources */, D6ED4D033BA74DFFA968FC50 /* OverlayRenderer.swift in Sources */,
7862CEBEB345430F908DE135 /* OverlayState.swift in Sources */, 44412124BE71497F89A100A7 /* OverlayState.swift in Sources */,
15EBD3E3D95D4AE5BABB6776 /* ScoreboardElement.swift in Sources */, DAA27DA77F904BA9B59684B1 /* ScoreboardElement.swift in Sources */,
7DCAA615F27C4853B8A0F889 /* SponsorElement.swift in Sources */, 1DF38DB813DC491C94C206CD /* SponsorElement.swift in Sources */,
28A607B3D84448308B130ECF /* WatermarkElement.swift in Sources */, ABA512B1D2C7407E892623DE /* WatermarkElement.swift in Sources */,
AEE1728EFF3F491A81B1156B /* LivePreviewView.swift in Sources */, 70385A94466D4A2EA11DDB3B /* LivePreviewView.swift in Sources */,
921A1A2729B244C08A9BD3FD /* BroadcastControlsOverlay.swift in Sources */, 0B2C36335D034737BD753D22 /* BroadcastControlsOverlay.swift in Sources */,
C5EEE95F92D44046994659FC /* BroadcastScreen.swift in Sources */, A5767FD88F8D4123A68224CD /* BroadcastScreen.swift in Sources */,
191F31088FCE4A82932B6FBB /* LiveScoreActions.swift in Sources */, 2F9195CCAE9949C087CECAA2 /* LiveScoreActions.swift in Sources */,
6DAD6078CC8D46FCB1AE0A75 /* MatchLiveWordmark.swift in Sources */, 1F26CA550156447B89B3EC01 /* MatchLiveWordmark.swift in Sources */,
D015D7ACCFE54071B1831C74 /* MatchPrimaryButton.swift in Sources */, 85680F15BAC247B1AA97DC4D /* MatchPrimaryButton.swift in Sources */,
91F1D3111F2C4BDFAB7435BF /* MatchScreenScaffold.swift in Sources */, 942E7C8159B2490A9058D20A /* MatchScreenScaffold.swift in Sources */,
464C286CAE724604AF9CC1FD /* MatchSecondaryButton.swift in Sources */, BDAA05C294674E0A837D27AB /* MatchSecondaryButton.swift in Sources */,
F13DF021E1084F6C844CB7AB /* MatchStatusBadge.swift in Sources */, 3D6496F4394A4A8B8280CCD7 /* MatchStatusBadge.swift in Sources */,
0CE091822CAA4D88B1BE3AF4 /* LoginScreen.swift in Sources */, 0AEA80531D74475A9279AAF8 /* LoginScreen.swift in Sources */,
C6B059D6435243208A8FC338 /* MatchesScreen.swift in Sources */, F3907C6CC01447B786FF633F /* MatchesScreen.swift in Sources */,
D501A7EE3BAD467A9A63E63C /* AppNavHost.swift in Sources */, BCA11E5347BE4070B1883A58 /* AppNavHost.swift in Sources */,
138294291C614F218D71B1CD /* ModalRoutes.swift in Sources */, E2D089A57F9F49D887C0D233 /* ModalRoutes.swift in Sources */,
D3C28481960E4E14A0909DCB /* Routes.swift in Sources */, C2479C699DF24364951AFFEC /* Routes.swift in Sources */,
30F21F19C7234BBF8B2B77D4 /* BroadcastPermissions.swift in Sources */, 6312973A866D4191BA2E2E5E /* BroadcastPermissions.swift in Sources */,
51B03D8318114D3AB94A41CA /* SplashScreen.swift in Sources */, 71A4EBF7C11441ED8202C4A5 /* SplashScreen.swift in Sources */,
08F123F9692D48EA94EBD94D /* KeepScreenOn.swift in Sources */, 255C09F3A1AB4FCC80DC403D /* KeepScreenOn.swift in Sources */,
5E33700F7C694E9D8EC997D7 /* ScreenOrientation.swift in Sources */, D4EED1F5722B435695F1C09D /* ScreenOrientation.swift in Sources */,
3A08990CB238458CA25C07C9 /* ShareSheet.swift in Sources */, B6CA255BE2A840A7B21CDCCB /* ShareSheet.swift in Sources */,
4598E75CCCF5492CB2F0B006 /* MatchColors.swift in Sources */, C6B8E801C3E449ABBFA44F33 /* MatchColors.swift in Sources */,
66539A1D77EA4B368F5BDE2E /* StepMatchScreen.swift in Sources */, 4B6FFF5D05164AE9AFB2833C /* StepMatchScreen.swift in Sources */,
EF83C38F78144E0996C33807 /* StepNetworkTestScreen.swift in Sources */, 5A085BBBD09B49A98A261FD1 /* StepNetworkTestScreen.swift in Sources */,
B7D592901EC34D4B97DCE549 /* StepTransmissionScreen.swift in Sources */, 7360468C628E48AF950EF5CB /* StepTransmissionScreen.swift in Sources */,
F13AA7F009F1421FB996956B /* TeamBrandingEditor.swift in Sources */, 871F7D73227B4E699B65FE3D /* TeamBrandingEditor.swift in Sources */,
00BDF215CB7942A799F06774 /* TeamColorPicker.swift in Sources */, E2E74A83D86544BA8FB85AAB /* TeamColorPicker.swift in Sources */,
7B4182E19F93484B8B0D07DF /* WizardComponents.swift in Sources */, 4E3828F9935743CCB4B15F01 /* WizardComponents.swift in Sources */,
4A67DD768F074E7885DFDF43 /* WizardShellScreen.swift in Sources */, B9DFB757CD3942AEBC1953F0 /* WizardShellScreen.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
4264391B98534ED485BCB343 /* PBXTargetDependency */ = { 953DB6F101304B388EBFB376 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = AE6E9D532CE6492D8B82687F /* MatchLiveTv */; target = 2F039DD838234B1F9B1B2FF5 /* MatchLiveTv */;
targetProxy = ACB2FE70CE4841CCB7A0ACC7 /* PBXContainerItemProxy */; targetProxy = 90C62964E51147DCABB6E3C2 /* PBXContainerItemProxy */;
}; };
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
10AA1592F59B4796984A3DF8 /* Release */ = { 10CF510EECBA46A28C005559 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
2A2B61A669994F488438E767 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 21;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MARKETING_VERSION = 2.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.matchlivetv.match-live-tv.tests";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MatchLiveTv.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/MatchLiveTv";
};
name = Debug;
};
3F95B64C066F4446ACEDEEFA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
SWIFT_VERSION = 5.0;
};
name = Release;
};
4F2ACFA1B72745E696F93445 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
API_BASE_URL = "https://www.matchlivetv.it"; API_BASE_URL = "https://www.matchlivetv.it";
@@ -507,15 +541,7 @@
}; };
name = Release; name = Release;
}; };
13D89B468B1A4BC7A4C411CC /* Debug */ = { C6FDF65D61EE4467A5089156 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
3D4B16FD3007411E80F55942 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
API_BASE_URL = "https://www.matchlivetv.it"; API_BASE_URL = "https://www.matchlivetv.it";
@@ -542,33 +568,7 @@
}; };
name = Debug; name = Debug;
}; };
4112889F91F94934ADAC5A6E /* Release */ = { E9E462592C9D4C8CB7EF2F7B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
SWIFT_VERSION = 5.0;
};
name = Release;
};
8EEBF4BEA19A487B9CA09A7E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 21;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MARKETING_VERSION = 2.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.matchlivetv.match-live-tv.tests";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MatchLiveTv.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/MatchLiveTv";
};
name = Debug;
};
E449653FF06F4DCDB2AFC77A /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
@@ -589,29 +589,29 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
002C5EF177A5409AAE23DB38 /* Build configuration list for PBXNativeTarget "MatchLiveTv" */ = { 1E22BBCE2E7C4E1DBD22BF81 /* Build configuration list for PBXProject "MatchLiveTv" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
3D4B16FD3007411E80F55942 /* Debug */, 10CF510EECBA46A28C005559 /* Debug */,
10AA1592F59B4796984A3DF8 /* Release */, 3F95B64C066F4446ACEDEEFA /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
27F2A4CC59994B3CA41841F5 /* Build configuration list for PBXProject "MatchLiveTv" */ = { 271ADC46052246A38FB0DFCE /* Build configuration list for PBXNativeTarget "MatchLiveTvTests" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
13D89B468B1A4BC7A4C411CC /* Debug */, 2A2B61A669994F488438E767 /* Debug */,
4112889F91F94934ADAC5A6E /* Release */, E9E462592C9D4C8CB7EF2F7B /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
E3DA5397819945D09DC337F6 /* Build configuration list for PBXNativeTarget "MatchLiveTvTests" */ = { 7F122D777A6E41C9BD148CDD /* Build configuration list for PBXNativeTarget "MatchLiveTv" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
8EEBF4BEA19A487B9CA09A7E /* Debug */, C6FDF65D61EE4467A5089156 /* Debug */,
E449653FF06F4DCDB2AFC77A /* Release */, 4F2ACFA1B72745E696F93445 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
@@ -619,7 +619,7 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
2DAE333E666A41BE8A5F1148 /* XCRemoteSwiftPackageReference "HaishinKit" */ = { 3FD2C0913F9E4659A9B8920D /* XCRemoteSwiftPackageReference "HaishinKit" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/shogo4405/HaishinKit.swift"; repositoryURL = "https://github.com/shogo4405/HaishinKit.swift";
requirement = { requirement = {
@@ -630,17 +630,17 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
AA756D8C68BC4B3D8EC96D5E /* RTMPHaishinKit */ = { 363FFDAD444D4381B6D23159 /* HaishinKit */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 2DAE333E666A41BE8A5F1148 /* XCRemoteSwiftPackageReference "HaishinKit" */; package = 3FD2C0913F9E4659A9B8920D /* XCRemoteSwiftPackageReference "HaishinKit" */;
productName = RTMPHaishinKit;
};
DFA0D0CEB1F1428D9E3FB3DB /* HaishinKit */ = {
isa = XCSwiftPackageProductDependency;
package = 2DAE333E666A41BE8A5F1148 /* XCRemoteSwiftPackageReference "HaishinKit" */;
productName = HaishinKit; productName = HaishinKit;
}; };
3CEE882EC45E49D49BF6B568 /* RTMPHaishinKit */ = {
isa = XCSwiftPackageProductDependency;
package = 3FD2C0913F9E4659A9B8920D /* XCRemoteSwiftPackageReference "HaishinKit" */;
productName = RTMPHaishinKit;
};
/* End XCSwiftPackageProductDependency section */ /* End XCSwiftPackageProductDependency section */
}; };
rootObject = 76FC637A5DFB4F018A0D1441 /* Project object */; rootObject = DBE4153B1FC34F91BC390462 /* Project object */;
} }

View File

@@ -3,28 +3,28 @@
<BuildAction parallelizeBuildables="YES" buildImplicitDependencies="YES"> <BuildAction parallelizeBuildables="YES" buildImplicitDependencies="YES">
<BuildActionEntries> <BuildActionEntries>
<BuildActionEntry buildForTesting="YES" buildForRunning="YES" buildForProfiling="YES" buildForArchiving="YES" buildForAnalyzing="YES"> <BuildActionEntry buildForTesting="YES" buildForRunning="YES" buildForProfiling="YES" buildForArchiving="YES" buildForAnalyzing="YES">
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="AE6E9D532CE6492D8B82687F" BuildableName="MatchLiveTv.app" BlueprintName="MatchLiveTv" ReferencedContainer="container:MatchLiveTv.xcodeproj"/> <BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="2F039DD838234B1F9B1B2FF5" BuildableName="MatchLiveTv.app" BlueprintName="MatchLiveTv" ReferencedContainer="container:MatchLiveTv.xcodeproj"/>
</BuildActionEntry> </BuildActionEntry>
<BuildActionEntry buildForTesting="YES" buildForRunning="NO" buildForProfiling="NO" buildForArchiving="NO" buildForAnalyzing="NO"> <BuildActionEntry buildForTesting="YES" buildForRunning="NO" buildForProfiling="NO" buildForArchiving="NO" buildForAnalyzing="NO">
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="64F84AC8A424490D945D5B65" BuildableName="MatchLiveTvTests.xctest" BlueprintName="MatchLiveTvTests" ReferencedContainer="container:MatchLiveTv.xcodeproj"/> <BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="F441C7131D0345549D8CA917" BuildableName="MatchLiveTvTests.xctest" BlueprintName="MatchLiveTvTests" ReferencedContainer="container:MatchLiveTv.xcodeproj"/>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction buildConfiguration="Debug" selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv="YES"> <TestAction buildConfiguration="Debug" selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv="YES">
<Testables> <Testables>
<TestableReference skipped="NO"> <TestableReference skipped="NO">
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="64F84AC8A424490D945D5B65" BuildableName="MatchLiveTvTests.xctest" BlueprintName="MatchLiveTvTests" ReferencedContainer="container:MatchLiveTv.xcodeproj"/> <BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="F441C7131D0345549D8CA917" BuildableName="MatchLiveTvTests.xctest" BlueprintName="MatchLiveTvTests" ReferencedContainer="container:MatchLiveTv.xcodeproj"/>
</TestableReference> </TestableReference>
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction buildConfiguration="Debug" selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle="0" useCustomWorkingDirectory="NO" ignoresPersistentStateOnLaunch="NO" debugDocumentVersioning="YES" debugServiceExtension="internal" allowLocationSimulation="YES"> <LaunchAction buildConfiguration="Debug" selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle="0" useCustomWorkingDirectory="NO" ignoresPersistentStateOnLaunch="NO" debugDocumentVersioning="YES" debugServiceExtension="internal" allowLocationSimulation="YES">
<BuildableProductRunnable runnableDebuggingMode="0"> <BuildableProductRunnable runnableDebuggingMode="0">
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="AE6E9D532CE6492D8B82687F" BuildableName="MatchLiveTv.app" BlueprintName="MatchLiveTv" ReferencedContainer="container:MatchLiveTv.xcodeproj"/> <BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="2F039DD838234B1F9B1B2FF5" BuildableName="MatchLiveTv.app" BlueprintName="MatchLiveTv" ReferencedContainer="container:MatchLiveTv.xcodeproj"/>
</BuildableProductRunnable> </BuildableProductRunnable>
</LaunchAction> </LaunchAction>
<ProfileAction buildConfiguration="Release" shouldUseLaunchSchemeArgsEnv="YES" savedToolIdentifier="" useCustomWorkingDirectory="NO" debugDocumentVersioning="YES"> <ProfileAction buildConfiguration="Release" shouldUseLaunchSchemeArgsEnv="YES" savedToolIdentifier="" useCustomWorkingDirectory="NO" debugDocumentVersioning="YES">
<BuildableProductRunnable runnableDebuggingMode="0"> <BuildableProductRunnable runnableDebuggingMode="0">
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="AE6E9D532CE6492D8B82687F" BuildableName="MatchLiveTv.app" BlueprintName="MatchLiveTv" ReferencedContainer="container:MatchLiveTv.xcodeproj"/> <BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="2F039DD838234B1F9B1B2FF5" BuildableName="MatchLiveTv.app" BlueprintName="MatchLiveTv" ReferencedContainer="container:MatchLiveTv.xcodeproj"/>
</BuildableProductRunnable> </BuildableProductRunnable>
</ProfileAction> </ProfileAction>
<AnalyzeAction buildConfiguration="Debug"/> <AnalyzeAction buildConfiguration="Debug"/>

View File

@@ -235,8 +235,8 @@ struct ScoreStateDto: Decodable {
let awayPoints: Int? let awayPoints: Int?
let currentSet: Int? let currentSet: Int?
let setPartials: [SetPartialDto]? let setPartials: [SetPartialDto]?
let timeoutHome: Bool? let timeoutHome: FlexibleBool?
let timeoutAway: Bool? let timeoutAway: FlexibleBool?
let period: FlexiblePeriod? let period: FlexiblePeriod?
let clockSecs: Int? let clockSecs: Int?
let clockRunning: FlexibleBool? let clockRunning: FlexibleBool?
@@ -256,8 +256,8 @@ struct ScoreStateDto: Decodable {
setPartials: (setPartials ?? []).map { setPartials: (setPartials ?? []).map {
SetPartial(set: $0.set ?? 1, home: $0.home ?? 0, away: $0.away ?? 0) SetPartial(set: $0.set ?? 1, home: $0.home ?? 0, away: $0.away ?? 0)
}, },
timeoutHome: timeoutHome ?? false, timeoutHome: timeoutHome?.value ?? false,
timeoutAway: timeoutAway ?? false, timeoutAway: timeoutAway?.value ?? false,
boardType: board, boardType: board,
period: parsePeriodNumber(periodLabel, currentSet: currentSet), period: parsePeriodNumber(periodLabel, currentSet: currentSet),
periodLabel: periodLabel, periodLabel: periodLabel,
@@ -331,6 +331,30 @@ struct ScoreStateDataDto: Decodable {
let clockRunning: FlexibleBool? let clockRunning: FlexibleBool?
let period: Int? let period: Int?
let overtime: FlexibleBool? let overtime: FlexibleBool?
enum CodingKeys: String, CodingKey {
case homeScore, awayScore, clockSecs, clockRunning, period, overtime
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
homeScore = Self.decodeInt(container, key: .homeScore)
awayScore = Self.decodeInt(container, key: .awayScore)
clockSecs = Self.decodeInt(container, key: .clockSecs)
clockRunning = try? container.decode(FlexibleBool.self, forKey: .clockRunning)
period = Self.decodeInt(container, key: .period)
overtime = try? container.decode(FlexibleBool.self, forKey: .overtime)
}
private static func decodeInt(
_ container: KeyedDecodingContainer<CodingKeys>,
key: CodingKeys
) -> Int? {
if let value = try? container.decode(Int.self, forKey: key) { return value }
if let text = try? container.decode(String.self, forKey: key), let value = Int(text) { return value }
if let value = try? container.decode(Double.self, forKey: key) { return Int(value) }
return nil
}
} }
struct ScoreActionRequest: Encodable { struct ScoreActionRequest: Encodable {

View File

@@ -36,7 +36,8 @@ struct ScoreState: Equatable, Sendable {
"timeout_away": timeoutAway, "timeout_away": timeoutAway,
] ]
if Self.periodBoards.contains(boardType) { if Self.periodBoards.contains(boardType) {
payload["period"] = periodLabel ?? "\(period)" // Il backend si aspetta un intero in sync Action Cable (non "Q1").
payload["period"] = period
payload["clock_secs"] = clockSecs payload["clock_secs"] = clockSecs
payload["clock_running"] = clockRunning payload["clock_running"] = clockRunning
payload["home_score"] = homePoints payload["home_score"] = homePoints

View File

@@ -99,4 +99,139 @@ final class ScoreActionDecodeTests: XCTestCase {
XCTAssertEqual(score.clockSecs, 600) XCTAssertEqual(score.clockSecs, 600)
XCTAssertFalse(score.clockRunning) XCTAssertFalse(score.clockRunning)
} }
func testDecodesResumeSessionDetailWithBasketScore() throws {
let json = """
{
"id": "420fd5b9-b2ad-45af-9c1d-569c654866f8",
"match_id": "e887ce1d-10ee-4680-8323-79bb8f11e0aa",
"status": "paused",
"platform": "matchlivetv",
"rtmp_ingest_url": "rtmp://localhost:1935/live/key",
"hls_playback_url": "http://localhost:8888/live/key/index.m3u8",
"watch_page_url": "http://localhost:3000/live/abc",
"share_url": "http://localhost:3000/live/abc",
"youtube_watch_url": null,
"youtube_broadcast_id": null,
"youtube_ready": false,
"privacy_status": "unlisted",
"quality_preset": "720p_30_2.5mbps",
"target_bitrate": 2500000,
"started_at": "2026-06-19T10:30:00.000Z",
"disconnection_count": 0,
"score": {
"type": "score_update",
"board_type": "basket",
"home_sets": 0,
"away_sets": 0,
"home_points": 42,
"away_points": 38,
"current_set": 1,
"set_partials": [],
"timeout_home": false,
"timeout_away": false,
"period": "Q3",
"clock_secs": 312,
"clock_running": true,
"data": {
"home_score": 42,
"away_score": 38,
"period": 3,
"clock_secs": 312,
"clock_running": true,
"overtime": false
}
},
"devices": [
{
"type": "device_state",
"battery": 85,
"network": "wifi",
"bitrate": 2100,
"fps": 30,
"status": "paused"
}
]
}
""".data(using: .utf8)!
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
let score = try XCTUnwrap(dto.score?.toDomain())
XCTAssertEqual(score.homePoints, 42)
XCTAssertEqual(score.periodLabel, "Q3")
XCTAssertEqual(dto.status, "paused")
}
func testDecodesBasketScoreWithNumericTimeouts() throws {
let json = """
{
"id": "a",
"match_id": "b",
"status": "paused",
"platform": "matchlivetv",
"score": {
"board_type": "basket",
"home_points": 10,
"away_points": 8,
"period": "Q2",
"clock_secs": 600,
"clock_running": false,
"timeout_home": 0,
"timeout_away": 0,
"data": { "home_score": 10, "away_score": 8, "period": 2, "overtime": false }
}
}
""".data(using: .utf8)!
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
XCTAssertEqual(dto.score?.toDomain().homePoints, 10)
}
func testDecodesBasketScoreWithStringPeriodInData() throws {
let json = """
{
"id": "a",
"match_id": "b",
"status": "paused",
"platform": "matchlivetv",
"score": {
"board_type": "basket",
"home_points": 10,
"away_points": 8,
"period": "Q2",
"clock_secs": 600,
"clock_running": false,
"data": { "period": "2", "home_score": 10, "away_score": 8, "overtime": false }
}
}
""".data(using: .utf8)!
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
XCTAssertEqual(dto.score?.toDomain().period, 2)
}
func testDecodesCableAdvancePeriodPayload() throws {
let json = """
{
"type": "score_update",
"board_type": "basket",
"home_points": 0,
"away_points": 4,
"period": "Q2",
"clock_secs": 600,
"clock_running": false,
"data": {
"period": 2,
"home_score": 0,
"away_score": 4,
"clock_secs": 600,
"clock_running": false,
"overtime": false
}
}
""".data(using: .utf8)!
let score = ScoreState.fromCablePayload(try JSONSerialization.jsonObject(with: json) as! [String: Any])
XCTAssertEqual(score.period, 2)
XCTAssertEqual(score.periodLabel, "Q2")
XCTAssertEqual(score.homePoints, 0)
XCTAssertEqual(score.awayPoints, 4)
XCTAssertGreaterThan(score.progressKey(), ScoreState(boardType: "basket", period: 1, periodLabel: "Q1").progressKey())
}
} }

View File

@@ -101,4 +101,23 @@ final class ScoreControllerTests: XCTestCase {
XCTAssertEqual(controller.score.homePoints, 6) XCTAssertEqual(controller.score.homePoints, 6)
XCTAssertEqual(controller.score.awayPoints, 7) XCTAssertEqual(controller.score.awayPoints, 7)
} }
func testCableAdvancePeriodUpdatesOverlayState() {
let controller = ScoreController(
scoreRepository: ScoreRepository(api: MatchLiveAPI()),
sessionCable: SessionCableService()
)
var local = ScoreState(boardType: "basket", period: 1, periodLabel: "Q1")
local.homePoints = 0
local.awayPoints = 4
controller.bind(sessionId: "session-1", initial: local)
var remote = ScoreState(boardType: "basket", period: 2, periodLabel: "Q2")
remote.homePoints = 0
remote.awayPoints = 4
controller.applyRemote(remote, source: .cable)
XCTAssertEqual(controller.score.periodLabel, "Q2")
XCTAssertEqual(controller.score.period, 2)
}
} }

View File

@@ -98,7 +98,37 @@ score = s.get("score") or {}
assert s.get("status") in ("live", "connecting", "reconnecting", "idle"), s.get("status") assert s.get("status") in ("live", "connecting", "reconnecting", "idle"), s.get("status")
assert score.get("board_type") in ("volley", "racket", "basket", "timed", "generic", "timer"), score assert score.get("board_type") in ("volley", "racket", "basket", "timed", "generic", "timer"), score
assert score.get("current_set") == 2, score assert score.get("current_set") == 2, score
print("GET /sessions/:id OK — Riprendi diretta payload valido") print("GET /sessions/:id OK — Riprendi diretta payload valido (volley)")
PY
echo "== API: sessione basket in pausa + Riprendi diretta =="
BASKET_MATCH=$(curl -sf -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$API/api/v1/teams/$TEAM_ID/matches" \
-d '{"opponent_name":"E2E Basket","sport_key":"basket"}')
BASKET_MATCH_ID=$(echo "$BASKET_MATCH" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
BASKET_SESSION=$(curl -sf -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$API/api/v1/matches/$BASKET_MATCH_ID/sessions" \
-d '{"platform":"matchlivetv","privacy_status":"unlisted","quality_preset":"720p_30_2.5mbps"}')
BASKET_SESSION_ID=$(echo "$BASKET_SESSION" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
curl -sf -X PATCH -H "$AUTH" "$API/api/v1/sessions/$BASKET_SESSION_ID/start" > /dev/null
for _ in $(seq 1 5); do
curl -sf -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$API/api/v1/sessions/$BASKET_SESSION_ID/score_action" \
-d '{"score_action":"home_point"}' > /dev/null
done
curl -sf -X PATCH -H "$AUTH" "$API/api/v1/sessions/$BASKET_SESSION_ID/pause" > /dev/null
BASKET_RESUME=$(curl -sf -H "$AUTH" "$API/api/v1/sessions/$BASKET_SESSION_ID")
python3 - <<PY
import json
s = json.loads('''$BASKET_RESUME''')
score = s.get("score") or {}
assert s.get("status") == "paused", s.get("status")
assert score.get("board_type") == "basket", score
assert score.get("home_points") == 5, score
assert score.get("period", "").startswith("Q"), score.get("period")
print("GET /sessions/:id OK — Riprendi diretta payload valido (basket)")
PY PY
echo "== E2E iOS completato: app avviata sul simulatore, API scoring/resume OK ==" echo "== E2E iOS completato: app avviata sul simulatore, API scoring/resume OK =="