diff --git a/backend/app/controllers/public/regia_controller.rb b/backend/app/controllers/public/regia_controller.rb index 3b7def0..9da7c1c 100644 --- a/backend/app/controllers/public/regia_controller.rb +++ b/backend/app/controllers/public/regia_controller.rb @@ -17,7 +17,10 @@ module Public @score = @session.score_state || Scoring::Engine.ensure_score_for(@session) @rules = Scoring::Rules.from_match(@match) @stream_closed = @session.terminal? - @on_air = !@stream_closed && mediamtx_stream_playable?(@session) + @on_air = !@stream_closed && ( + mediamtx_stream_playable?(@session) || + @session.status.in?(%w[connecting live reconnecting paused]) + ) @regia_share_url = request.original_url @regia_share_title = "Regia — #{@team.name} vs #{@match.opponent_name}" @live_share_url = @session.share_url @@ -70,17 +73,18 @@ module Public score = @session.score_state closed = @session.terminal? playable = !closed && mediamtx_stream_playable?(@session) + publisher_online = !closed && mediamtx_publisher_online?(@session) { status: @session.status, paused: @session.paused?, stream_closed: closed, - live: !closed && (@session.live? || @session.paused? || mediamtx_publisher_online?(@session)), - on_air: playable, - publisher_online: !closed && mediamtx_publisher_online?(@session), + live: !closed && (@session.live? || @session.paused? || publisher_online), + on_air: playable || (!closed && @session.status.in?(%w[connecting live reconnecting paused])), + publisher_online: publisher_online, ended_at: @session.ended_at, home_name: @session.match.team.name, away_name: @session.match.opponent_name, - points_target: Scoring::Rules.from_match(@session.match).points_target(score&.current_set || 1), + points_target: Scoring::Rules.points_target_for_match(@session.match, current_set: score&.current_set || 1), score: score&.as_cable_payload } end diff --git a/backend/app/services/scoring/rules.rb b/backend/app/services/scoring/rules.rb index 054c502..f2090a3 100644 --- a/backend/app/services/scoring/rules.rb +++ b/backend/app/services/scoring/rules.rb @@ -45,6 +45,11 @@ module Scoring current_set >= max_sets ? @points_deciding_set : @points_per_set end + def self.points_target_for_match(match, current_set: 1) + rules = from_match(match) + rules.is_a?(Rules) ? rules.points_target(current_set) : 0 + end + def set_winner_from_points(home_points:, away_points:, current_set:) target = points_target(current_set) if home_points >= target && (home_points - away_points) >= @min_point_lead diff --git a/backend/app/views/public/regia/show.html.erb b/backend/app/views/public/regia/show.html.erb index 181d2e0..a8002bf 100644 --- a/backend/app/views/public/regia/show.html.erb +++ b/backend/app/views/public/regia/show.html.erb @@ -93,4 +93,4 @@ - + diff --git a/backend/public/regia.js b/backend/public/regia.js index b8939b7..e591180 100644 --- a/backend/public/regia.js +++ b/backend/public/regia.js @@ -174,7 +174,10 @@ headers: { "Content-Type": "application/json", Accept: "application/json" }, body: JSON.stringify({ cmd: action }) }); - if (!res.ok) throw new Error("Errore aggiornamento punteggio"); + if (!res.ok) { + const body = await res.json().catch(() => ({})); + throw new Error(body.error || "Errore aggiornamento punteggio"); + } return res.json(); } diff --git a/backend/spec/requests/public/regia_spec.rb b/backend/spec/requests/public/regia_spec.rb index 3ff4e85..f01e0da 100644 --- a/backend/spec/requests/public/regia_spec.rb +++ b/backend/spec/requests/public/regia_spec.rb @@ -25,6 +25,43 @@ RSpec.describe "Public regia", type: :request do expect(session.score_state.reload.home_points).to eq(1) end + it "aggiorna il punteggio basket via API senza errore 500" do + basket_team = club.teams.create!(name: "U13 Basket", sport_key: "basket") + basket_match = basket_team.matches.create!( + opponent_name: "Avversario", + sport: "basket", + scoring_rules: { "periods" => 4, "period_duration_secs" => 600, "overtime_duration_secs" => 300 } + ) + 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" => 0, + "overtime" => false + } + ) + token = Sessions::RegiaAccess.new(basket_session).issue_token! + + patch public_regia_score_path(token), params: { cmd: "home_point" }, as: :json + expect(response).to have_http_status(:ok) + body = response.parsed_body + expect(body.dig("score", "home_points")).to eq(1) + expect(body["points_target"]).to eq(0) + + get public_regia_status_path(token) + expect(response).to have_http_status(:ok) + expect(response.parsed_body.dig("score", "board_type")).to eq("basket") + end + it "mette in pausa e riprende la diretta" do mtx = instance_double( Mediamtx::Client, diff --git a/native/ios/MatchLiveTv.xcodeproj/project.pbxproj b/native/ios/MatchLiveTv.xcodeproj/project.pbxproj index 532857a..f61cedf 100644 --- a/native/ios/MatchLiveTv.xcodeproj/project.pbxproj +++ b/native/ios/MatchLiveTv.xcodeproj/project.pbxproj @@ -7,181 +7,183 @@ objects = { /* Begin PBXBuildFile section */ - 01BBD9C8228A4654BE791A09 /* WizardSessionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = E61DFC0396BF4C7CA7224E89 /* WizardSessionHolder.swift */; }; - 0712F271074B47B992C54B02 /* CompactScoreboardElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B52CD9228B48FA85CC2D44 /* CompactScoreboardElement.swift */; }; - 0747277C94AD48939CBAE80B /* ScoreboardElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9E1CBDE54A15BAFCE1AD /* ScoreboardElement.swift */; }; - 07C244E32A4D48A185963C6C /* ScoreControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79438470374D4CB6B2969CCA /* ScoreControllerTests.swift */; }; - 1C71C5745AF541A793FBD415 /* TeamBrandingEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9E84FF89324A4E929A68EA /* TeamBrandingEditor.swift */; }; - 1DE6EABFB67F4046957C9B88 /* StepMatchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09528E80CD2840E0B9DEBAD2 /* StepMatchScreen.swift */; }; - 266CD29FA3C048CC9413460A /* OverlayCanvasRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBADDB48408844F39BFD1DC2 /* OverlayCanvasRenderer.swift */; }; - 2757AF56199F46A49036C307 /* MatchScreenScaffold.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD9CC837B7E847F4B294522D /* MatchScreenScaffold.swift */; }; - 306216CA292D4974B612AC06 /* SponsorElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A0F1558C174BD584AE0377 /* SponsorElement.swift */; }; - 3477E99DCB6843BB8037EB21 /* WizardComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC184551A43F44E09E536D29 /* WizardComponents.swift */; }; - 3628957732604F1597784B04 /* OverlayRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 677CE6F23F0445D9A30A52A9 /* OverlayRenderer.swift */; }; - 38938AED35E94A99A4921FF3 /* OverlayState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA971C263254BDC95AC2423 /* OverlayState.swift */; }; - 3C4DD1CE0BFA4CD9928234CD /* BroadcastVideoOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46179BF6DAB34804A72D8DDB /* BroadcastVideoOrientation.swift */; }; - 4236C0FB1B10435EB03C39DF /* MatchesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E28D48159B4487C9AE867D2 /* MatchesScreen.swift */; }; - 44519A77D19C46218318593E /* OverlayMappings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC3BD7FC07E4BB29B022564 /* OverlayMappings.swift */; }; - 49586D0F50AA4BE692FDCF3F /* AppNavHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2E617EAB1E4F65A7A6B5B0 /* AppNavHost.swift */; }; - 4958D62D7A8944EAB3E54F18 /* ScoreState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880F5D2B2B13497891706E0A /* ScoreState.swift */; }; - 4B1080F3C1354A89A859ACC6 /* MatchRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAC77F0B59AE4202BDEE66E1 /* MatchRepository.swift */; }; - 4C26392C2FE69A090015AAF3 /* HaishinKit in Frameworks */ = {isa = PBXBuildFile; productRef = 3242173ACEDC4B288ACD56E4 /* HaishinKit */; }; - 4C26392D2FE69A090015AAF3 /* RTMPHaishinKit in Frameworks */ = {isa = PBXBuildFile; productRef = F3539A3AB0894C54992DB7D5 /* RTMPHaishinKit */; }; - 57B21B3B008A4345AEDFD7D2 /* ColorHex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818D265485A3445DAB7EAC48 /* ColorHex.swift */; }; - 5C80FF3E9F574F4EA2FDFEFF /* DeviceTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92ABFE7C0ADC4F69B66FFAF6 /* DeviceTelemetry.swift */; }; - 639783D4083F4049B5424C52 /* MediaUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA461A50E47740818FDC5890 /* MediaUrl.swift */; }; - 674D6A9F61D742DF95F93C5B /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66D5B274FF34093901B981B /* AppConfig.swift */; }; - 7DC17CB11FC246378F6624C0 /* TeamColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 573991C190AD43BBBDDD186C /* TeamColorPicker.swift */; }; - 7F7C79F0C4EA4B06A5A2E4BA /* ScreenOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E44D4F87459404B805ACEC8 /* ScreenOrientation.swift */; }; - 815C82E2C5C54746ABF73BEE /* SplashScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17256285CF354F0D8E4B33A3 /* SplashScreen.swift */; }; - 82D6D70F2E554414961F27C3 /* MatchScoringRulesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC6D82784F44CF2885999DD /* MatchScoringRulesTests.swift */; }; - 830325BE85674DD6A31CE672 /* WatermarkElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 073D0DFED0B3415DA15C8B28 /* WatermarkElement.swift */; }; - 832E24DBB2844E9895717F6F /* LiveScoreActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E98F8C22FB6416EB90F19BB /* LiveScoreActions.swift */; }; - 83E38DFBBFFF4412BF2ABEE9 /* MatchSecondaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D0D3DB5F3834E1587D1F187 /* MatchSecondaryButton.swift */; }; - 89F47A469F6044B9A92D647A /* LivePreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F07B021AC24DCAA217238C /* LivePreviewView.swift */; }; - 8CDFA36E735A4A94A5A60DBF /* BroadcastControlsOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 810AA10E867B4CC08328EC0D /* BroadcastControlsOverlay.swift */; }; - 8DB866F0F33A4F3BAA074660 /* Routes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F27D4CBFFA47DF9A9AB9A9 /* Routes.swift */; }; - 8DE2FE7CF4A34222B2D3066A /* ApiDtos.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AB5819FE32342F1961F256E /* ApiDtos.swift */; }; - 9102501263E1477BAA6DEDD1 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2C8DD5093B84D5FBE360C23 /* Models.swift */; }; - 95848029AD4D4683B80DEA8C /* ScoreRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7176501FD1A4F06AC1F6557 /* ScoreRepository.swift */; }; - 9770A3D9677F42AC942E98A4 /* BroadcastScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FB7EC31451F4C07BB2DD674 /* BroadcastScreen.swift */; }; - 9A208AE54E434798BD5DF06F /* WizardShellScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6BA4AD8A2004074977D9F6A /* WizardShellScreen.swift */; }; - 9EAD5508F44243409C697F41 /* BroadcastOrientationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA3A9BC8EFD47EEB2BD629D /* BroadcastOrientationPolicy.swift */; }; - 9EDC5C176D2E40F29455CCEF /* ScoreActionDecodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70D09D7B58C4E67B59A7770 /* ScoreActionDecodeTests.swift */; }; - 9EF4BA3F81C341B4ACAB643F /* StepNetworkTestScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BF5EDE52B0A4E75BBA200AC /* StepNetworkTestScreen.swift */; }; - A3D8F65EBA8B479485321837 /* SessionCableService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AD019C7B9EF4063AF3933A6 /* SessionCableService.swift */; }; - AB3DF660C79648CFAECB03CF /* MatchStatusBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951726866CB945DD917376C7 /* MatchStatusBadge.swift */; }; - ABE74DCBA6804EDEB5398F8F /* MatchPrimaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE0C26984E50402281861375 /* MatchPrimaryButton.swift */; }; - B578A98681A8413DBFEF58CA /* MatchColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC3A6C1489646CA8DB996D0 /* MatchColors.swift */; }; - B5937876D40F4E21A63DB92A /* ApiInstant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5853956279E94634BFC1660C /* ApiInstant.swift */; }; - B86EA543F6114B198D334FAF /* LiveBroadcastEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2671666828B04BF7A91B1539 /* LiveBroadcastEngine.swift */; }; - BAE5062DD4B749E6BC569CCA /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8D6C06908D433AA4E4DF03 /* ShareSheet.swift */; }; - BB73AB6E535F473EA6C1D232 /* MatchSessionLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D079A45CFC474FBAA96F57D1 /* MatchSessionLauncher.swift */; }; - BD2628C89CAD450ABF613183 /* BroadcastPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19DBD17AD504442A518E471 /* BroadcastPermissions.swift */; }; - C0CA6EBDA3E84641AFEC3A12 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 136E90D700FD44D89C9D5659 /* LoginScreen.swift */; }; - C1D94B81E44C4BFD8351B165 /* LiveBroadcastCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF2A0A2676F8406FAACB786B /* LiveBroadcastCoordinatorTests.swift */; }; - C9B2434416364C4BB263BB3F /* LiveBroadcastCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E22842CB3AF4514965D3791 /* LiveBroadcastCoordinator.swift */; }; - CBEE59E2E2DE4C058FF42022 /* MatchHubFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A264DB29100D404EA570CF47 /* MatchHubFilter.swift */; }; - CCB2F270DD464E608046A60C /* MatchLiveTvApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FAE643838541119B344969 /* MatchLiveTvApp.swift */; }; - CEACB53FE13049B9959896F1 /* ScoreController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9525D894BB924BFFBC2D244C /* ScoreController.swift */; }; - D1334C2CFEC145328396B7EC /* ActionCableClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEB49B33F26E4F9FBC5B8984 /* ActionCableClient.swift */; }; - D3C0878AD7354D41B540AD5B /* AppContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34DE015C16C54795A496C968 /* AppContainer.swift */; }; - D67C481FC7DE46C6B7AD09C4 /* AuthRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4E8DCB47E8409BA1BE8D1D /* AuthRepository.swift */; }; - D6F532927A6345339AD2149D /* TokenStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E7E256AA201434EBD01B7D4 /* TokenStore.swift */; }; - DFC67AC6380B41BC8A8CE866 /* ApiInstantTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9E9DB7BBCBA4E35A0583979 /* ApiInstantTests.swift */; }; - E054E5E1703A4876B4E13F64 /* MatchScoringRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10F4515DE324DC0ABFF8B24 /* MatchScoringRules.swift */; }; - E5B931C144DA46819918A5EC /* MatchLiveAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA738A8723C440598F1B4A4 /* MatchLiveAPI.swift */; }; - E75B414604CB429A9CCE797C /* BroadcastModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E128E2B501C45419220F030 /* BroadcastModels.swift */; }; - E93FDA6122664F67A5448E2D /* UserFacingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6BA18F615214E4184E199B2 /* UserFacingError.swift */; }; - EA206B930BD448D3AC1E2578 /* OverlayLogoCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B8BC4646CE4707B112E02E /* OverlayLogoCache.swift */; }; - EB3C108379594E7EBCBCE016 /* ModalRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EDC8F2206484D8C9916E260 /* ModalRoutes.swift */; }; - EED290CEF4A141608F7BE515 /* KeepScreenOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FBA01162B004E85821F206B /* KeepScreenOn.swift */; }; - EF984C15882E4E328BFCDA74 /* SessionRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8E47E0A55F44A59F78C729 /* SessionRepository.swift */; }; - F05733319E284083A5AA2784 /* MatchLiveTv/Resources/Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A6A99927A66246AF84CF8FC5 /* MatchLiveTv/Resources/Assets.xcassets */; }; - F212F8F1DA0C42619D13D30E /* StepTransmissionScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3AA2F7662C04600BB71F47C /* StepTransmissionScreen.swift */; }; - F36DADA0DA9245A48E3DDB29 /* BroadcastOrientationPolicyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 177C409B72684FE7A3A977B8 /* BroadcastOrientationPolicyTests.swift */; }; - F5B6F5CD2D9245BDB8E81055 /* MatchLiveWordmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AD24618CFB64DCB846C25A2 /* MatchLiveWordmark.swift */; }; + 00BDF215CB7942A799F06774 /* TeamColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6D45B70859402BA3ABD014 /* TeamColorPicker.swift */; }; + 045086A670F24B1192E0DF8F /* SessionRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C3663CA3AD648B48EA4405D /* SessionRepository.swift */; }; + 08F123F9692D48EA94EBD94D /* KeepScreenOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DC8A3443404B0CAD323B11 /* KeepScreenOn.swift */; }; + 0CE091822CAA4D88B1BE3AF4 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAEE3C8BBB684FEBA230480A /* LoginScreen.swift */; }; + 0E03BE40DAF14E98A35051CE /* ScoreRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA8EB774A34C4E259AFB1C88 /* ScoreRepository.swift */; }; + 138294291C614F218D71B1CD /* ModalRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3A3F3250284150B0A0BCD4 /* ModalRoutes.swift */; }; + 15EBD3E3D95D4AE5BABB6776 /* ScoreboardElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA61FF84F91473DA84438A8 /* ScoreboardElement.swift */; }; + 191F31088FCE4A82932B6FBB /* LiveScoreActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D1C27A80A842A1B531051C /* LiveScoreActions.swift */; }; + 22A2A4F3BBD845C5B4E1DD6E /* DeviceTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5C7905A24E4AE1A0600511 /* DeviceTelemetry.swift */; }; + 2498A1488A034D058E6997B0 /* ScoreActionDecodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BA0FAD47DC40D48F063FC8 /* ScoreActionDecodeTests.swift */; }; + 284F82D0FB65448BAB38C6BE /* TokenStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D2302B51D94A8984EC6A56 /* TokenStore.swift */; }; + 28A607B3D84448308B130ECF /* WatermarkElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DBA84B5B0CA459E89779309 /* WatermarkElement.swift */; }; + 2D3FAEEE0372415381467FC7 /* ApiDtos.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DF95A27A584535A1511035 /* ApiDtos.swift */; }; + 3027E88493BA43B09B150BA1 /* MatchSessionLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9316C1429F9448ABC7BA7B6 /* MatchSessionLauncher.swift */; }; + 30F21F19C7234BBF8B2B77D4 /* BroadcastPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44FFA851A3BC44A784DF353A /* BroadcastPermissions.swift */; }; + 35FE18027B054D5BBC20DC9C /* MatchScoringRulesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 049297E3B0D44FF8840B8E76 /* MatchScoringRulesTests.swift */; }; + 39E01672805E4B8A88DA0FA9 /* ActionCableClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D36C4F09E5D04392B0B82EF8 /* ActionCableClient.swift */; }; + 3A08990CB238458CA25C07C9 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D603A791C926456D9B565F78 /* ShareSheet.swift */; }; + 3AA28F966201426380DEE174 /* BroadcastOrientationPolicyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43DEDBA98F24BE996528018 /* BroadcastOrientationPolicyTests.swift */; }; + 4598E75CCCF5492CB2F0B006 /* MatchColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2349A6BFDD4708B821C659 /* MatchColors.swift */; }; + 464C286CAE724604AF9CC1FD /* MatchSecondaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1144C664590842258CBE9998 /* MatchSecondaryButton.swift */; }; + 48719B5718B2419E96AE6AF2 /* SessionCableService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8AA247685DD45FD980465B0 /* SessionCableService.swift */; }; + 4A67DD768F074E7885DFDF43 /* WizardShellScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E61E730231499C9F119309 /* WizardShellScreen.swift */; }; + 4A6973ACDCA743B29ACC1E2E /* OverlayRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C397B3162F38497C9AD0C9CF /* OverlayRenderer.swift */; }; + 4BD05489BDAB4E309311B1C7 /* BroadcastVideoOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBA94A102E6C4E1BAF934D53 /* BroadcastVideoOrientation.swift */; }; + 4C2639382FE6A0440015AAF3 /* HaishinKit in Frameworks */ = {isa = PBXBuildFile; productRef = DFA0D0CEB1F1428D9E3FB3DB /* HaishinKit */; }; + 4C2639392FE6A0440015AAF3 /* RTMPHaishinKit in Frameworks */ = {isa = PBXBuildFile; productRef = AA756D8C68BC4B3D8EC96D5E /* RTMPHaishinKit */; }; + 4CD8A3EB76C14F878BF1026C /* LiveScoreDialogHostTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F42DAF0103FD4213BE778C7C /* LiveScoreDialogHostTests.swift */; }; + 51B03D8318114D3AB94A41CA /* SplashScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74D65108DA4C4A5BB95C0E51 /* SplashScreen.swift */; }; + 52DCD38F408B4BAE8A0A673D /* AppContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A62D39BF1BD343E2B314A150 /* AppContainer.swift */; }; + 53A492E3510D4C8A9A5C94B7 /* ScoreController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C71579DA2945D5B0FA780C /* ScoreController.swift */; }; + 59BB3212FCBA4F68B23337F3 /* LiveBroadcastEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD491B8176A0430A9C3AB7B9 /* LiveBroadcastEngine.swift */; }; + 5A8E598237CF41BFB62B83D8 /* WizardSessionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF24FBB15BA4493EAEA78436 /* WizardSessionHolder.swift */; }; + 5D4E00AC5D4E44A09E3743DE /* MatchLiveTvApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3458504736B4137A749812C /* MatchLiveTvApp.swift */; }; + 5E33700F7C694E9D8EC997D7 /* ScreenOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E31852C7972040328E39C991 /* ScreenOrientation.swift */; }; + 644B22C2C7E54983A6BE393D /* LiveBroadcastCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB11018606164DAFBDC4E7A1 /* LiveBroadcastCoordinatorTests.swift */; }; + 66539A1D77EA4B368F5BDE2E /* StepMatchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B469A9557164A2682CEA145 /* StepMatchScreen.swift */; }; + 6C52A9292D694A728A372551 /* ScoreControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C58DA984475413DB55C3E1B /* ScoreControllerTests.swift */; }; + 6CA1DE649AEE455C994D0E94 /* MediaUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0487DB6D2DEB4508B5EF5FCC /* MediaUrl.swift */; }; + 6CC11041AFC64969BC9195D0 /* MatchScoringRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4974F7EF092B4FC697A30E00 /* MatchScoringRules.swift */; }; + 6DAD6078CC8D46FCB1AE0A75 /* MatchLiveWordmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE69B3EE8D0E4D8EAA8B853B /* MatchLiveWordmark.swift */; }; + 6E09F9E1FBB3459B94343BDD /* OverlayLogoCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 224057D043A541C287071B37 /* OverlayLogoCache.swift */; }; + 7862CEBEB345430F908DE135 /* OverlayState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE44F992D17E408D8713CC95 /* OverlayState.swift */; }; + 7B4182E19F93484B8B0D07DF /* WizardComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3490DEC22A543F890FEA661 /* WizardComponents.swift */; }; + 7DCAA615F27C4853B8A0F889 /* SponsorElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8799BE797C4B4A409E32E753 /* SponsorElement.swift */; }; + 82ADD6499C394031B87D7A96 /* ApiInstant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691EB1B5F9EA4DFB902E0D37 /* ApiInstant.swift */; }; + 8BAE2CEB56064BA3A3A16B53 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = D17AB6B00BBC4568A6D0457E /* Models.swift */; }; + 91C697AC57284A26A9893DFD /* OverlayMappings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC8DDF8DE68C4281B9062AD0 /* OverlayMappings.swift */; }; + 91F1D3111F2C4BDFAB7435BF /* MatchScreenScaffold.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8FE87562E85488A946F8C86 /* MatchScreenScaffold.swift */; }; + 921A1A2729B244C08A9BD3FD /* BroadcastControlsOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E0E8585555C42A6A220FF29 /* BroadcastControlsOverlay.swift */; }; + 96E2427E81E744289D1C9B9B /* BroadcastModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC65D1EBC15F4ECB921A94F5 /* BroadcastModels.swift */; }; + 991371D458954C06A798AC0E /* LiveBroadcastCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8E0CCB4B0554F96B04BDB07 /* LiveBroadcastCoordinator.swift */; }; + 994148BB9CCE4E6F800CD89A /* ColorHex.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4770AC3C14D451F89B35533 /* ColorHex.swift */; }; + 9D241B051BD54105A9D764DD /* BroadcastOrientationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBD03F804A944D6D84464875 /* BroadcastOrientationPolicy.swift */; }; + 9E770D39394E41838877BC62 /* AuthRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0B5292C4B7344E98043FA55 /* AuthRepository.swift */; }; + AEE1728EFF3F491A81B1156B /* LivePreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1123FED73ED4983BFBE9BB6 /* LivePreviewView.swift */; }; + B3DD2F8E837649B2B007CEAF /* MatchHubFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4570572C5D4745A990B291D6 /* MatchHubFilter.swift */; }; + B7D592901EC34D4B97DCE549 /* StepTransmissionScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74D13551050B4A51A21B0A67 /* StepTransmissionScreen.swift */; }; + C5EEE95F92D44046994659FC /* BroadcastScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E94110FC43754C50AC862D5C /* BroadcastScreen.swift */; }; + C6B059D6435243208A8FC338 /* MatchesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40924F02DDFA4CCDA9488D64 /* MatchesScreen.swift */; }; + CAABC65179F6467996D85730 /* UserFacingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5ECE7DA4A94297899495FF /* UserFacingError.swift */; }; + D015D7ACCFE54071B1831C74 /* MatchPrimaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36263581FBC9465FB59A54A3 /* MatchPrimaryButton.swift */; }; + D0BAD147978244529A46C040 /* CompactScoreboardElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B9968E881924270973373DD /* CompactScoreboardElement.swift */; }; + D3C28481960E4E14A0909DCB /* Routes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290C51105D0B4ABE997FA155 /* Routes.swift */; }; + D501A7EE3BAD467A9A63E63C /* AppNavHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B41DFCE8AF4993A93F756A /* AppNavHost.swift */; }; + D77980669AE84165AAF94AF2 /* MatchRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B77E9A6C51421D9AEDFF51 /* MatchRepository.swift */; }; + D916D4368A9A4298BDB3430F /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07588FE10B4143D8971F8A1F /* AppConfig.swift */; }; + EA533D28A4EF4171B410B56E /* ScoreState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 134FD1D616EF4F82A0175E28 /* ScoreState.swift */; }; + EB8D708E665A46B398EB0C4F /* MatchLiveAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BCA039B9842405DBCB38BA5 /* MatchLiveAPI.swift */; }; + EBB063DFDBE443F3BC12A67A /* ApiInstantTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C0FE41B109A41519495E952 /* ApiInstantTests.swift */; }; + EE689B65571A474CA19A792C /* OverlayCanvasRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C561AB7965264974822DBD60 /* OverlayCanvasRenderer.swift */; }; + EF83C38F78144E0996C33807 /* StepNetworkTestScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0D156DFC16945A3A8467EF0 /* StepNetworkTestScreen.swift */; }; + F13AA7F009F1421FB996956B /* TeamBrandingEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AC1BB5EDAEE43359749B95A /* TeamBrandingEditor.swift */; }; + F13DF021E1084F6C844CB7AB /* MatchStatusBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7FA4E0FD3142D9957B764F /* MatchStatusBadge.swift */; }; + FE21BE8932864B5D96D1BA41 /* MatchLiveTv/Resources/Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FE0CBD099ED14E62B752AB7F /* MatchLiveTv/Resources/Assets.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - E0F627D71C6349F1857AFED5 /* PBXContainerItemProxy */ = { + ACB2FE70CE4841CCB7A0ACC7 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 72A102A7C8964137A464FF32 /* Project object */; + containerPortal = 76FC637A5DFB4F018A0D1441 /* Project object */; proxyType = 1; - remoteGlobalIDString = 553940DB807C4DBFB63E9FFE; + remoteGlobalIDString = AE6E9D532CE6492D8B82687F; remoteInfo = MatchLiveTv; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 073D0DFED0B3415DA15C8B28 /* WatermarkElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WatermarkElement.swift; path = MatchLiveTv/Streaming/Overlay/WatermarkElement.swift; sourceTree = ""; }; - 09528E80CD2840E0B9DEBAD2 /* StepMatchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepMatchScreen.swift; path = MatchLiveTv/UI/Wizard/StepMatchScreen.swift; sourceTree = ""; }; - 0AD019C7B9EF4063AF3933A6 /* SessionCableService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionCableService.swift; path = MatchLiveTv/Data/Cable/SessionCableService.swift; sourceTree = ""; }; - 136E90D700FD44D89C9D5659 /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LoginScreen.swift; path = MatchLiveTv/UI/Login/LoginScreen.swift; sourceTree = ""; }; - 17256285CF354F0D8E4B33A3 /* SplashScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SplashScreen.swift; path = MatchLiveTv/UI/Splash/SplashScreen.swift; sourceTree = ""; }; - 177C409B72684FE7A3A977B8 /* BroadcastOrientationPolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastOrientationPolicyTests.swift; path = MatchLiveTvTests/BroadcastOrientationPolicyTests.swift; sourceTree = ""; }; - 18B8BC4646CE4707B112E02E /* OverlayLogoCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayLogoCache.swift; path = MatchLiveTv/Streaming/Overlay/OverlayLogoCache.swift; sourceTree = ""; }; - 1E128E2B501C45419220F030 /* BroadcastModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastModels.swift; path = MatchLiveTv/Streaming/BroadcastModels.swift; sourceTree = ""; }; - 1F2E617EAB1E4F65A7A6B5B0 /* AppNavHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppNavHost.swift; path = MatchLiveTv/UI/Navigation/AppNavHost.swift; sourceTree = ""; }; - 24FAE643838541119B344969 /* MatchLiveTvApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveTvApp.swift; path = MatchLiveTv/App/MatchLiveTvApp.swift; sourceTree = ""; }; - 2671666828B04BF7A91B1539 /* LiveBroadcastEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastEngine.swift; path = MatchLiveTv/Streaming/LiveBroadcastEngine.swift; sourceTree = ""; }; - 2C8D6C06908D433AA4E4DF03 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ShareSheet.swift; path = MatchLiveTv/UI/System/ShareSheet.swift; sourceTree = ""; }; - 2C9E84FF89324A4E929A68EA /* TeamBrandingEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TeamBrandingEditor.swift; path = MatchLiveTv/UI/Wizard/TeamBrandingEditor.swift; sourceTree = ""; }; - 2CC3BD7FC07E4BB29B022564 /* OverlayMappings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayMappings.swift; path = MatchLiveTv/Streaming/Overlay/OverlayMappings.swift; sourceTree = ""; }; - 2E98F8C22FB6416EB90F19BB /* LiveScoreActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveScoreActions.swift; path = MatchLiveTv/UI/Broadcast/LiveScoreActions.swift; sourceTree = ""; }; - 2EDC8F2206484D8C9916E260 /* ModalRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ModalRoutes.swift; path = MatchLiveTv/UI/Navigation/ModalRoutes.swift; sourceTree = ""; }; - 34DE015C16C54795A496C968 /* AppContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppContainer.swift; path = MatchLiveTv/Data/AppContainer.swift; sourceTree = ""; }; - 3AA971C263254BDC95AC2423 /* OverlayState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayState.swift; path = MatchLiveTv/Streaming/Overlay/OverlayState.swift; sourceTree = ""; }; - 3FBA01162B004E85821F206B /* KeepScreenOn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = KeepScreenOn.swift; path = MatchLiveTv/UI/System/KeepScreenOn.swift; sourceTree = ""; }; - 46179BF6DAB34804A72D8DDB /* BroadcastVideoOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastVideoOrientation.swift; path = MatchLiveTv/Streaming/BroadcastVideoOrientation.swift; sourceTree = ""; }; - 573991C190AD43BBBDDD186C /* TeamColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TeamColorPicker.swift; path = MatchLiveTv/UI/Wizard/TeamColorPicker.swift; sourceTree = ""; }; - 5853956279E94634BFC1660C /* ApiInstant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiInstant.swift; path = MatchLiveTv/Core/ApiInstant.swift; sourceTree = ""; }; - 5AD24618CFB64DCB846C25A2 /* MatchLiveWordmark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveWordmark.swift; path = MatchLiveTv/UI/Components/MatchLiveWordmark.swift; sourceTree = ""; }; - 5C49570E1FB3460BBEB502FC /* MatchLiveTvTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatchLiveTvTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 5E22842CB3AF4514965D3791 /* LiveBroadcastCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastCoordinator.swift; path = MatchLiveTv/Streaming/LiveBroadcastCoordinator.swift; sourceTree = ""; }; - 5FB7EC31451F4C07BB2DD674 /* BroadcastScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastScreen.swift; path = MatchLiveTv/UI/Broadcast/BroadcastScreen.swift; sourceTree = ""; }; - 677CE6F23F0445D9A30A52A9 /* OverlayRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayRenderer.swift; path = MatchLiveTv/Streaming/Overlay/OverlayRenderer.swift; sourceTree = ""; }; - 79438470374D4CB6B2969CCA /* ScoreControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreControllerTests.swift; path = MatchLiveTvTests/ScoreControllerTests.swift; sourceTree = ""; }; - 7BF5EDE52B0A4E75BBA200AC /* StepNetworkTestScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepNetworkTestScreen.swift; path = MatchLiveTv/UI/Wizard/StepNetworkTestScreen.swift; sourceTree = ""; }; - 7C4E8DCB47E8409BA1BE8D1D /* AuthRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthRepository.swift; path = MatchLiveTv/Data/Repository/AuthRepository.swift; sourceTree = ""; }; - 7E28D48159B4487C9AE867D2 /* MatchesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchesScreen.swift; path = MatchLiveTv/UI/Matches/MatchesScreen.swift; sourceTree = ""; }; - 810AA10E867B4CC08328EC0D /* BroadcastControlsOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastControlsOverlay.swift; path = MatchLiveTv/UI/Broadcast/BroadcastControlsOverlay.swift; sourceTree = ""; }; - 818D265485A3445DAB7EAC48 /* ColorHex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorHex.swift; path = MatchLiveTv/Core/ColorHex.swift; sourceTree = ""; }; - 81F07B021AC24DCAA217238C /* LivePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LivePreviewView.swift; path = MatchLiveTv/Streaming/Preview/LivePreviewView.swift; sourceTree = ""; }; - 880F5D2B2B13497891706E0A /* ScoreState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreState.swift; path = MatchLiveTv/Domain/ScoreState.swift; sourceTree = ""; }; - 8D0D3DB5F3834E1587D1F187 /* MatchSecondaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchSecondaryButton.swift; path = MatchLiveTv/UI/Components/MatchSecondaryButton.swift; sourceTree = ""; }; - 8E44D4F87459404B805ACEC8 /* ScreenOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScreenOrientation.swift; path = MatchLiveTv/UI/System/ScreenOrientation.swift; sourceTree = ""; }; - 8E7E256AA201434EBD01B7D4 /* TokenStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TokenStore.swift; path = MatchLiveTv/Core/TokenStore.swift; sourceTree = ""; }; - 92ABFE7C0ADC4F69B66FFAF6 /* DeviceTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeviceTelemetry.swift; path = MatchLiveTv/Core/DeviceTelemetry.swift; sourceTree = ""; }; - 951726866CB945DD917376C7 /* MatchStatusBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchStatusBadge.swift; path = MatchLiveTv/UI/Components/MatchStatusBadge.swift; sourceTree = ""; }; - 9525D894BB924BFFBC2D244C /* ScoreController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreController.swift; path = MatchLiveTv/Data/Scoring/ScoreController.swift; sourceTree = ""; }; - 9A8F9E1CBDE54A15BAFCE1AD /* ScoreboardElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreboardElement.swift; path = MatchLiveTv/Streaming/Overlay/ScoreboardElement.swift; sourceTree = ""; }; - 9AB5819FE32342F1961F256E /* ApiDtos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiDtos.swift; path = MatchLiveTv/Data/API/ApiDtos.swift; sourceTree = ""; }; - A19DBD17AD504442A518E471 /* BroadcastPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastPermissions.swift; path = MatchLiveTv/UI/Permissions/BroadcastPermissions.swift; sourceTree = ""; }; - A1B52CD9228B48FA85CC2D44 /* CompactScoreboardElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CompactScoreboardElement.swift; path = MatchLiveTv/Streaming/Overlay/CompactScoreboardElement.swift; sourceTree = ""; }; - A264DB29100D404EA570CF47 /* MatchHubFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchHubFilter.swift; path = MatchLiveTv/Domain/MatchHubFilter.swift; sourceTree = ""; }; - A2C8DD5093B84D5FBE360C23 /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Models.swift; path = MatchLiveTv/Domain/Models.swift; sourceTree = ""; }; - A66D5B274FF34093901B981B /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppConfig.swift; path = MatchLiveTv/Core/AppConfig.swift; sourceTree = ""; }; - A6A99927A66246AF84CF8FC5 /* MatchLiveTv/Resources/Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MatchLiveTv/Resources/Assets.xcassets; sourceTree = ""; }; - A70D09D7B58C4E67B59A7770 /* ScoreActionDecodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreActionDecodeTests.swift; path = MatchLiveTvTests/ScoreActionDecodeTests.swift; sourceTree = ""; }; - AB5EAF0FD4BE4B14B5B029B8 /* MatchLiveTv/Resources/Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MatchLiveTv/Resources/Info.plist; sourceTree = ""; }; - B10F4515DE324DC0ABFF8B24 /* MatchScoringRules.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScoringRules.swift; path = MatchLiveTv/Domain/MatchScoringRules.swift; sourceTree = ""; }; - B165DBC9A0DA4C62824D41C3 /* MatchLiveTv.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MatchLiveTv.app; sourceTree = BUILT_PRODUCTS_DIR; }; - B5A0F1558C174BD584AE0377 /* SponsorElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SponsorElement.swift; path = MatchLiveTv/Streaming/Overlay/SponsorElement.swift; sourceTree = ""; }; - BA461A50E47740818FDC5890 /* MediaUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaUrl.swift; path = MatchLiveTv/Core/MediaUrl.swift; sourceTree = ""; }; - BAC77F0B59AE4202BDEE66E1 /* MatchRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchRepository.swift; path = MatchLiveTv/Data/Repository/MatchRepository.swift; sourceTree = ""; }; - BEB49B33F26E4F9FBC5B8984 /* ActionCableClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ActionCableClient.swift; path = MatchLiveTv/Data/Cable/ActionCableClient.swift; sourceTree = ""; }; - BFA3A9BC8EFD47EEB2BD629D /* BroadcastOrientationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastOrientationPolicy.swift; path = MatchLiveTv/Streaming/BroadcastOrientationPolicy.swift; sourceTree = ""; }; - BFA738A8723C440598F1B4A4 /* MatchLiveAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveAPI.swift; path = MatchLiveTv/Data/API/MatchLiveAPI.swift; sourceTree = ""; }; - CD9CC837B7E847F4B294522D /* MatchScreenScaffold.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScreenScaffold.swift; path = MatchLiveTv/UI/Components/MatchScreenScaffold.swift; sourceTree = ""; }; - CF2A0A2676F8406FAACB786B /* LiveBroadcastCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastCoordinatorTests.swift; path = MatchLiveTvTests/LiveBroadcastCoordinatorTests.swift; sourceTree = ""; }; - D079A45CFC474FBAA96F57D1 /* MatchSessionLauncher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchSessionLauncher.swift; path = MatchLiveTv/Data/Repository/MatchSessionLauncher.swift; sourceTree = ""; }; - D5F27D4CBFFA47DF9A9AB9A9 /* Routes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Routes.swift; path = MatchLiveTv/UI/Navigation/Routes.swift; sourceTree = ""; }; - D7176501FD1A4F06AC1F6557 /* ScoreRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreRepository.swift; path = MatchLiveTv/Data/Repository/ScoreRepository.swift; sourceTree = ""; }; - DC8E47E0A55F44A59F78C729 /* SessionRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionRepository.swift; path = MatchLiveTv/Data/Repository/SessionRepository.swift; sourceTree = ""; }; - DFC3A6C1489646CA8DB996D0 /* MatchColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchColors.swift; path = MatchLiveTv/UI/Theme/MatchColors.swift; sourceTree = ""; }; - E3AA2F7662C04600BB71F47C /* StepTransmissionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepTransmissionScreen.swift; path = MatchLiveTv/UI/Wizard/StepTransmissionScreen.swift; sourceTree = ""; }; - E61DFC0396BF4C7CA7224E89 /* WizardSessionHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardSessionHolder.swift; path = MatchLiveTv/Data/WizardSessionHolder.swift; sourceTree = ""; }; - E6BA18F615214E4184E199B2 /* UserFacingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UserFacingError.swift; path = MatchLiveTv/Core/UserFacingError.swift; sourceTree = ""; }; - EEC6D82784F44CF2885999DD /* MatchScoringRulesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScoringRulesTests.swift; path = MatchLiveTvTests/MatchScoringRulesTests.swift; sourceTree = ""; }; - F6BA4AD8A2004074977D9F6A /* WizardShellScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardShellScreen.swift; path = MatchLiveTv/UI/Wizard/WizardShellScreen.swift; sourceTree = ""; }; - F9E9DB7BBCBA4E35A0583979 /* ApiInstantTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiInstantTests.swift; path = MatchLiveTvTests/ApiInstantTests.swift; sourceTree = ""; }; - FBADDB48408844F39BFD1DC2 /* OverlayCanvasRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayCanvasRenderer.swift; path = MatchLiveTv/Streaming/Overlay/OverlayCanvasRenderer.swift; sourceTree = ""; }; - FC184551A43F44E09E536D29 /* WizardComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardComponents.swift; path = MatchLiveTv/UI/Wizard/WizardComponents.swift; sourceTree = ""; }; - FE0C26984E50402281861375 /* MatchPrimaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchPrimaryButton.swift; path = MatchLiveTv/UI/Components/MatchPrimaryButton.swift; sourceTree = ""; }; + 0487DB6D2DEB4508B5EF5FCC /* MediaUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaUrl.swift; path = MatchLiveTv/Core/MediaUrl.swift; sourceTree = ""; }; + 049297E3B0D44FF8840B8E76 /* MatchScoringRulesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScoringRulesTests.swift; path = MatchLiveTvTests/MatchScoringRulesTests.swift; sourceTree = ""; }; + 07588FE10B4143D8971F8A1F /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppConfig.swift; path = MatchLiveTv/Core/AppConfig.swift; sourceTree = ""; }; + 1144C664590842258CBE9998 /* MatchSecondaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchSecondaryButton.swift; path = MatchLiveTv/UI/Components/MatchSecondaryButton.swift; sourceTree = ""; }; + 134FD1D616EF4F82A0175E28 /* ScoreState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreState.swift; path = MatchLiveTv/Domain/ScoreState.swift; sourceTree = ""; }; + 1C3663CA3AD648B48EA4405D /* SessionRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionRepository.swift; path = MatchLiveTv/Data/Repository/SessionRepository.swift; sourceTree = ""; }; + 1C58DA984475413DB55C3E1B /* ScoreControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreControllerTests.swift; path = MatchLiveTvTests/ScoreControllerTests.swift; sourceTree = ""; }; + 224057D043A541C287071B37 /* OverlayLogoCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayLogoCache.swift; path = MatchLiveTv/Streaming/Overlay/OverlayLogoCache.swift; sourceTree = ""; }; + 290C51105D0B4ABE997FA155 /* Routes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Routes.swift; path = MatchLiveTv/UI/Navigation/Routes.swift; sourceTree = ""; }; + 2C3A3F3250284150B0A0BCD4 /* ModalRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ModalRoutes.swift; path = MatchLiveTv/UI/Navigation/ModalRoutes.swift; sourceTree = ""; }; + 36263581FBC9465FB59A54A3 /* MatchPrimaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchPrimaryButton.swift; path = MatchLiveTv/UI/Components/MatchPrimaryButton.swift; sourceTree = ""; }; + 3C5ECE7DA4A94297899495FF /* UserFacingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UserFacingError.swift; path = MatchLiveTv/Core/UserFacingError.swift; sourceTree = ""; }; + 40924F02DDFA4CCDA9488D64 /* MatchesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchesScreen.swift; path = MatchLiveTv/UI/Matches/MatchesScreen.swift; sourceTree = ""; }; + 44FFA851A3BC44A784DF353A /* BroadcastPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastPermissions.swift; path = MatchLiveTv/UI/Permissions/BroadcastPermissions.swift; sourceTree = ""; }; + 4570572C5D4745A990B291D6 /* MatchHubFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchHubFilter.swift; path = MatchLiveTv/Domain/MatchHubFilter.swift; sourceTree = ""; }; + 45C19E63F6E14B8A9B34AD29 /* MatchLiveTvTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatchLiveTvTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 4974F7EF092B4FC697A30E00 /* MatchScoringRules.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScoringRules.swift; path = MatchLiveTv/Domain/MatchScoringRules.swift; sourceTree = ""; }; + 4B469A9557164A2682CEA145 /* StepMatchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepMatchScreen.swift; path = MatchLiveTv/UI/Wizard/StepMatchScreen.swift; sourceTree = ""; }; + 691EB1B5F9EA4DFB902E0D37 /* ApiInstant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiInstant.swift; path = MatchLiveTv/Core/ApiInstant.swift; sourceTree = ""; }; + 6E0E8585555C42A6A220FF29 /* BroadcastControlsOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastControlsOverlay.swift; path = MatchLiveTv/UI/Broadcast/BroadcastControlsOverlay.swift; sourceTree = ""; }; + 6EA61FF84F91473DA84438A8 /* ScoreboardElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreboardElement.swift; path = MatchLiveTv/Streaming/Overlay/ScoreboardElement.swift; sourceTree = ""; }; + 6F6D45B70859402BA3ABD014 /* TeamColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TeamColorPicker.swift; path = MatchLiveTv/UI/Wizard/TeamColorPicker.swift; sourceTree = ""; }; + 74D13551050B4A51A21B0A67 /* StepTransmissionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepTransmissionScreen.swift; path = MatchLiveTv/UI/Wizard/StepTransmissionScreen.swift; sourceTree = ""; }; + 74D65108DA4C4A5BB95C0E51 /* SplashScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SplashScreen.swift; path = MatchLiveTv/UI/Splash/SplashScreen.swift; sourceTree = ""; }; + 76B77E9A6C51421D9AEDFF51 /* MatchRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchRepository.swift; path = MatchLiveTv/Data/Repository/MatchRepository.swift; sourceTree = ""; }; + 7B2349A6BFDD4708B821C659 /* MatchColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchColors.swift; path = MatchLiveTv/UI/Theme/MatchColors.swift; sourceTree = ""; }; + 7B9968E881924270973373DD /* CompactScoreboardElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CompactScoreboardElement.swift; path = MatchLiveTv/Streaming/Overlay/CompactScoreboardElement.swift; sourceTree = ""; }; + 8799BE797C4B4A409E32E753 /* SponsorElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SponsorElement.swift; path = MatchLiveTv/Streaming/Overlay/SponsorElement.swift; sourceTree = ""; }; + 88C71579DA2945D5B0FA780C /* ScoreController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreController.swift; path = MatchLiveTv/Data/Scoring/ScoreController.swift; sourceTree = ""; }; + 8DBA84B5B0CA459E89779309 /* WatermarkElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WatermarkElement.swift; path = MatchLiveTv/Streaming/Overlay/WatermarkElement.swift; sourceTree = ""; }; + 96BA0FAD47DC40D48F063FC8 /* ScoreActionDecodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreActionDecodeTests.swift; path = MatchLiveTvTests/ScoreActionDecodeTests.swift; sourceTree = ""; }; + 96E61E730231499C9F119309 /* WizardShellScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardShellScreen.swift; path = MatchLiveTv/UI/Wizard/WizardShellScreen.swift; sourceTree = ""; }; + 9AC1BB5EDAEE43359749B95A /* TeamBrandingEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TeamBrandingEditor.swift; path = MatchLiveTv/UI/Wizard/TeamBrandingEditor.swift; sourceTree = ""; }; + 9BCA039B9842405DBCB38BA5 /* MatchLiveAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveAPI.swift; path = MatchLiveTv/Data/API/MatchLiveAPI.swift; sourceTree = ""; }; + 9C0FE41B109A41519495E952 /* ApiInstantTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiInstantTests.swift; path = MatchLiveTvTests/ApiInstantTests.swift; sourceTree = ""; }; + A0DC8A3443404B0CAD323B11 /* KeepScreenOn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = KeepScreenOn.swift; path = MatchLiveTv/UI/System/KeepScreenOn.swift; sourceTree = ""; }; + A3B41DFCE8AF4993A93F756A /* AppNavHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppNavHost.swift; path = MatchLiveTv/UI/Navigation/AppNavHost.swift; sourceTree = ""; }; + A62D39BF1BD343E2B314A150 /* AppContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppContainer.swift; path = MatchLiveTv/Data/AppContainer.swift; sourceTree = ""; }; + A8FE87562E85488A946F8C86 /* MatchScreenScaffold.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchScreenScaffold.swift; path = MatchLiveTv/UI/Components/MatchScreenScaffold.swift; sourceTree = ""; }; + AAB84103176746DB89E76F33 /* MatchLiveTv.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MatchLiveTv.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B1123FED73ED4983BFBE9BB6 /* LivePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LivePreviewView.swift; path = MatchLiveTv/Streaming/Preview/LivePreviewView.swift; sourceTree = ""; }; + B43DEDBA98F24BE996528018 /* BroadcastOrientationPolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastOrientationPolicyTests.swift; path = MatchLiveTvTests/BroadcastOrientationPolicyTests.swift; sourceTree = ""; }; + BA7FA4E0FD3142D9957B764F /* MatchStatusBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchStatusBadge.swift; path = MatchLiveTv/UI/Components/MatchStatusBadge.swift; sourceTree = ""; }; + BA8EB774A34C4E259AFB1C88 /* ScoreRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScoreRepository.swift; path = MatchLiveTv/Data/Repository/ScoreRepository.swift; sourceTree = ""; }; + BC5C7905A24E4AE1A0600511 /* DeviceTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeviceTelemetry.swift; path = MatchLiveTv/Core/DeviceTelemetry.swift; sourceTree = ""; }; + BC65D1EBC15F4ECB921A94F5 /* BroadcastModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastModels.swift; path = MatchLiveTv/Streaming/BroadcastModels.swift; sourceTree = ""; }; + BE69B3EE8D0E4D8EAA8B853B /* MatchLiveWordmark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveWordmark.swift; path = MatchLiveTv/UI/Components/MatchLiveWordmark.swift; sourceTree = ""; }; + C3458504736B4137A749812C /* MatchLiveTvApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchLiveTvApp.swift; path = MatchLiveTv/App/MatchLiveTvApp.swift; sourceTree = ""; }; + C397B3162F38497C9AD0C9CF /* OverlayRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayRenderer.swift; path = MatchLiveTv/Streaming/Overlay/OverlayRenderer.swift; sourceTree = ""; }; + C561AB7965264974822DBD60 /* OverlayCanvasRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayCanvasRenderer.swift; path = MatchLiveTv/Streaming/Overlay/OverlayCanvasRenderer.swift; sourceTree = ""; }; + C7D1C27A80A842A1B531051C /* LiveScoreActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveScoreActions.swift; path = MatchLiveTv/UI/Broadcast/LiveScoreActions.swift; sourceTree = ""; }; + C8AA247685DD45FD980465B0 /* SessionCableService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionCableService.swift; path = MatchLiveTv/Data/Cable/SessionCableService.swift; sourceTree = ""; }; + C8D2302B51D94A8984EC6A56 /* TokenStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TokenStore.swift; path = MatchLiveTv/Core/TokenStore.swift; sourceTree = ""; }; + CBA94A102E6C4E1BAF934D53 /* BroadcastVideoOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastVideoOrientation.swift; path = MatchLiveTv/Streaming/BroadcastVideoOrientation.swift; sourceTree = ""; }; + CD491B8176A0430A9C3AB7B9 /* LiveBroadcastEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastEngine.swift; path = MatchLiveTv/Streaming/LiveBroadcastEngine.swift; sourceTree = ""; }; + D17AB6B00BBC4568A6D0457E /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Models.swift; path = MatchLiveTv/Domain/Models.swift; sourceTree = ""; }; + D36C4F09E5D04392B0B82EF8 /* ActionCableClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ActionCableClient.swift; path = MatchLiveTv/Data/Cable/ActionCableClient.swift; sourceTree = ""; }; + D4CD1243AC3D4BB8815BBE83 /* MatchLiveTv/Resources/Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MatchLiveTv/Resources/Info.plist; sourceTree = ""; }; + D603A791C926456D9B565F78 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ShareSheet.swift; path = MatchLiveTv/UI/System/ShareSheet.swift; sourceTree = ""; }; + D9316C1429F9448ABC7BA7B6 /* MatchSessionLauncher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MatchSessionLauncher.swift; path = MatchLiveTv/Data/Repository/MatchSessionLauncher.swift; sourceTree = ""; }; + DE44F992D17E408D8713CC95 /* OverlayState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayState.swift; path = MatchLiveTv/Streaming/Overlay/OverlayState.swift; sourceTree = ""; }; + E0B5292C4B7344E98043FA55 /* AuthRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthRepository.swift; path = MatchLiveTv/Data/Repository/AuthRepository.swift; sourceTree = ""; }; + E31852C7972040328E39C991 /* ScreenOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScreenOrientation.swift; path = MatchLiveTv/UI/System/ScreenOrientation.swift; sourceTree = ""; }; + E4770AC3C14D451F89B35533 /* ColorHex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorHex.swift; path = MatchLiveTv/Core/ColorHex.swift; sourceTree = ""; }; + E8E0CCB4B0554F96B04BDB07 /* LiveBroadcastCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastCoordinator.swift; path = MatchLiveTv/Streaming/LiveBroadcastCoordinator.swift; sourceTree = ""; }; + E94110FC43754C50AC862D5C /* BroadcastScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastScreen.swift; path = MatchLiveTv/UI/Broadcast/BroadcastScreen.swift; sourceTree = ""; }; + EAEE3C8BBB684FEBA230480A /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LoginScreen.swift; path = MatchLiveTv/UI/Login/LoginScreen.swift; sourceTree = ""; }; + EB11018606164DAFBDC4E7A1 /* LiveBroadcastCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveBroadcastCoordinatorTests.swift; path = MatchLiveTvTests/LiveBroadcastCoordinatorTests.swift; sourceTree = ""; }; + EBD03F804A944D6D84464875 /* BroadcastOrientationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BroadcastOrientationPolicy.swift; path = MatchLiveTv/Streaming/BroadcastOrientationPolicy.swift; sourceTree = ""; }; + F0D156DFC16945A3A8467EF0 /* StepNetworkTestScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StepNetworkTestScreen.swift; path = MatchLiveTv/UI/Wizard/StepNetworkTestScreen.swift; sourceTree = ""; }; + F3490DEC22A543F890FEA661 /* WizardComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardComponents.swift; path = MatchLiveTv/UI/Wizard/WizardComponents.swift; sourceTree = ""; }; + F3DF95A27A584535A1511035 /* ApiDtos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ApiDtos.swift; path = MatchLiveTv/Data/API/ApiDtos.swift; sourceTree = ""; }; + F42DAF0103FD4213BE778C7C /* LiveScoreDialogHostTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveScoreDialogHostTests.swift; path = MatchLiveTvTests/LiveScoreDialogHostTests.swift; sourceTree = ""; }; + FC8DDF8DE68C4281B9062AD0 /* OverlayMappings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OverlayMappings.swift; path = MatchLiveTv/Streaming/Overlay/OverlayMappings.swift; sourceTree = ""; }; + FE0CBD099ED14E62B752AB7F /* MatchLiveTv/Resources/Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MatchLiveTv/Resources/Assets.xcassets; sourceTree = ""; }; + FF24FBB15BA4493EAEA78436 /* WizardSessionHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WizardSessionHolder.swift; path = MatchLiveTv/Data/WizardSessionHolder.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 085E7F6CFD2B4475AC00D329 /* Frameworks */ = { + 2DFB0C53187A482B83E1F38B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 4C26392D2FE69A090015AAF3 /* RTMPHaishinKit in Frameworks */, - 4C26392C2FE69A090015AAF3 /* HaishinKit in Frameworks */, + 4C2639392FE6A0440015AAF3 /* RTMPHaishinKit in Frameworks */, + 4C2639382FE6A0440015AAF3 /* HaishinKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 521337FFC4E94E5880B1F174 /* Frameworks */ = { + C180AAFADE0640639A940144 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( @@ -191,121 +193,139 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 033861C6E3D248C6A4CEFAF6 /* Products */ = { + 14EA3A4718794D36964484DB = { isa = PBXGroup; children = ( - B165DBC9A0DA4C62824D41C3 /* MatchLiveTv.app */, - 5C49570E1FB3460BBEB502FC /* MatchLiveTvTests.xctest */, + EB01519A0F5446FABA7B5012 /* MatchLiveTv */, + C469ABBC533140A1A97C78AA /* MatchLiveTvTests */, + 6668FF0B6F2E4C60861A918C /* Products */, + ); + sourceTree = ""; + }; + 6668FF0B6F2E4C60861A918C /* Products */ = { + isa = PBXGroup; + children = ( + AAB84103176746DB89E76F33 /* MatchLiveTv.app */, + 45C19E63F6E14B8A9B34AD29 /* MatchLiveTvTests.xctest */, ); name = Products; sourceTree = ""; }; - 631A87449B654E888E88BF77 = { + C469ABBC533140A1A97C78AA /* MatchLiveTvTests */ = { isa = PBXGroup; children = ( - 705BD051C8004C5AA632BB29 /* MatchLiveTv */, - 8658B6D49A814C9981463B85 /* MatchLiveTvTests */, - 033861C6E3D248C6A4CEFAF6 /* Products */, - ); - sourceTree = ""; - }; - 705BD051C8004C5AA632BB29 /* MatchLiveTv */ = { - isa = PBXGroup; - children = ( - 24FAE643838541119B344969 /* MatchLiveTvApp.swift */, - 5853956279E94634BFC1660C /* ApiInstant.swift */, - A66D5B274FF34093901B981B /* AppConfig.swift */, - 818D265485A3445DAB7EAC48 /* ColorHex.swift */, - 92ABFE7C0ADC4F69B66FFAF6 /* DeviceTelemetry.swift */, - BA461A50E47740818FDC5890 /* MediaUrl.swift */, - 8E7E256AA201434EBD01B7D4 /* TokenStore.swift */, - E6BA18F615214E4184E199B2 /* UserFacingError.swift */, - 9AB5819FE32342F1961F256E /* ApiDtos.swift */, - BFA738A8723C440598F1B4A4 /* MatchLiveAPI.swift */, - 34DE015C16C54795A496C968 /* AppContainer.swift */, - BEB49B33F26E4F9FBC5B8984 /* ActionCableClient.swift */, - 0AD019C7B9EF4063AF3933A6 /* SessionCableService.swift */, - 7C4E8DCB47E8409BA1BE8D1D /* AuthRepository.swift */, - BAC77F0B59AE4202BDEE66E1 /* MatchRepository.swift */, - D079A45CFC474FBAA96F57D1 /* MatchSessionLauncher.swift */, - D7176501FD1A4F06AC1F6557 /* ScoreRepository.swift */, - DC8E47E0A55F44A59F78C729 /* SessionRepository.swift */, - 9525D894BB924BFFBC2D244C /* ScoreController.swift */, - E61DFC0396BF4C7CA7224E89 /* WizardSessionHolder.swift */, - A264DB29100D404EA570CF47 /* MatchHubFilter.swift */, - B10F4515DE324DC0ABFF8B24 /* MatchScoringRules.swift */, - A2C8DD5093B84D5FBE360C23 /* Models.swift */, - 880F5D2B2B13497891706E0A /* ScoreState.swift */, - 1E128E2B501C45419220F030 /* BroadcastModels.swift */, - BFA3A9BC8EFD47EEB2BD629D /* BroadcastOrientationPolicy.swift */, - 46179BF6DAB34804A72D8DDB /* BroadcastVideoOrientation.swift */, - 5E22842CB3AF4514965D3791 /* LiveBroadcastCoordinator.swift */, - 2671666828B04BF7A91B1539 /* LiveBroadcastEngine.swift */, - A1B52CD9228B48FA85CC2D44 /* CompactScoreboardElement.swift */, - FBADDB48408844F39BFD1DC2 /* OverlayCanvasRenderer.swift */, - 18B8BC4646CE4707B112E02E /* OverlayLogoCache.swift */, - 2CC3BD7FC07E4BB29B022564 /* OverlayMappings.swift */, - 677CE6F23F0445D9A30A52A9 /* OverlayRenderer.swift */, - 3AA971C263254BDC95AC2423 /* OverlayState.swift */, - 9A8F9E1CBDE54A15BAFCE1AD /* ScoreboardElement.swift */, - B5A0F1558C174BD584AE0377 /* SponsorElement.swift */, - 073D0DFED0B3415DA15C8B28 /* WatermarkElement.swift */, - 81F07B021AC24DCAA217238C /* LivePreviewView.swift */, - 810AA10E867B4CC08328EC0D /* BroadcastControlsOverlay.swift */, - 5FB7EC31451F4C07BB2DD674 /* BroadcastScreen.swift */, - 2E98F8C22FB6416EB90F19BB /* LiveScoreActions.swift */, - 5AD24618CFB64DCB846C25A2 /* MatchLiveWordmark.swift */, - FE0C26984E50402281861375 /* MatchPrimaryButton.swift */, - CD9CC837B7E847F4B294522D /* MatchScreenScaffold.swift */, - 8D0D3DB5F3834E1587D1F187 /* MatchSecondaryButton.swift */, - 951726866CB945DD917376C7 /* MatchStatusBadge.swift */, - 136E90D700FD44D89C9D5659 /* LoginScreen.swift */, - 7E28D48159B4487C9AE867D2 /* MatchesScreen.swift */, - 1F2E617EAB1E4F65A7A6B5B0 /* AppNavHost.swift */, - 2EDC8F2206484D8C9916E260 /* ModalRoutes.swift */, - D5F27D4CBFFA47DF9A9AB9A9 /* Routes.swift */, - A19DBD17AD504442A518E471 /* BroadcastPermissions.swift */, - 17256285CF354F0D8E4B33A3 /* SplashScreen.swift */, - 3FBA01162B004E85821F206B /* KeepScreenOn.swift */, - 8E44D4F87459404B805ACEC8 /* ScreenOrientation.swift */, - 2C8D6C06908D433AA4E4DF03 /* ShareSheet.swift */, - DFC3A6C1489646CA8DB996D0 /* MatchColors.swift */, - 09528E80CD2840E0B9DEBAD2 /* StepMatchScreen.swift */, - 7BF5EDE52B0A4E75BBA200AC /* StepNetworkTestScreen.swift */, - E3AA2F7662C04600BB71F47C /* StepTransmissionScreen.swift */, - 2C9E84FF89324A4E929A68EA /* TeamBrandingEditor.swift */, - 573991C190AD43BBBDDD186C /* TeamColorPicker.swift */, - FC184551A43F44E09E536D29 /* WizardComponents.swift */, - F6BA4AD8A2004074977D9F6A /* WizardShellScreen.swift */, - A6A99927A66246AF84CF8FC5 /* MatchLiveTv/Resources/Assets.xcassets */, - AB5EAF0FD4BE4B14B5B029B8 /* MatchLiveTv/Resources/Info.plist */, - ); - name = MatchLiveTv; - sourceTree = ""; - }; - 8658B6D49A814C9981463B85 /* MatchLiveTvTests */ = { - isa = PBXGroup; - children = ( - F9E9DB7BBCBA4E35A0583979 /* ApiInstantTests.swift */, - 177C409B72684FE7A3A977B8 /* BroadcastOrientationPolicyTests.swift */, - CF2A0A2676F8406FAACB786B /* LiveBroadcastCoordinatorTests.swift */, - EEC6D82784F44CF2885999DD /* MatchScoringRulesTests.swift */, - A70D09D7B58C4E67B59A7770 /* ScoreActionDecodeTests.swift */, - 79438470374D4CB6B2969CCA /* ScoreControllerTests.swift */, + 9C0FE41B109A41519495E952 /* ApiInstantTests.swift */, + B43DEDBA98F24BE996528018 /* BroadcastOrientationPolicyTests.swift */, + EB11018606164DAFBDC4E7A1 /* LiveBroadcastCoordinatorTests.swift */, + F42DAF0103FD4213BE778C7C /* LiveScoreDialogHostTests.swift */, + 049297E3B0D44FF8840B8E76 /* MatchScoringRulesTests.swift */, + 96BA0FAD47DC40D48F063FC8 /* ScoreActionDecodeTests.swift */, + 1C58DA984475413DB55C3E1B /* ScoreControllerTests.swift */, ); name = MatchLiveTvTests; sourceTree = ""; }; + EB01519A0F5446FABA7B5012 /* MatchLiveTv */ = { + isa = PBXGroup; + children = ( + C3458504736B4137A749812C /* MatchLiveTvApp.swift */, + 691EB1B5F9EA4DFB902E0D37 /* ApiInstant.swift */, + 07588FE10B4143D8971F8A1F /* AppConfig.swift */, + E4770AC3C14D451F89B35533 /* ColorHex.swift */, + BC5C7905A24E4AE1A0600511 /* DeviceTelemetry.swift */, + 0487DB6D2DEB4508B5EF5FCC /* MediaUrl.swift */, + C8D2302B51D94A8984EC6A56 /* TokenStore.swift */, + 3C5ECE7DA4A94297899495FF /* UserFacingError.swift */, + F3DF95A27A584535A1511035 /* ApiDtos.swift */, + 9BCA039B9842405DBCB38BA5 /* MatchLiveAPI.swift */, + A62D39BF1BD343E2B314A150 /* AppContainer.swift */, + D36C4F09E5D04392B0B82EF8 /* ActionCableClient.swift */, + C8AA247685DD45FD980465B0 /* SessionCableService.swift */, + E0B5292C4B7344E98043FA55 /* AuthRepository.swift */, + 76B77E9A6C51421D9AEDFF51 /* MatchRepository.swift */, + D9316C1429F9448ABC7BA7B6 /* MatchSessionLauncher.swift */, + BA8EB774A34C4E259AFB1C88 /* ScoreRepository.swift */, + 1C3663CA3AD648B48EA4405D /* SessionRepository.swift */, + 88C71579DA2945D5B0FA780C /* ScoreController.swift */, + FF24FBB15BA4493EAEA78436 /* WizardSessionHolder.swift */, + 4570572C5D4745A990B291D6 /* MatchHubFilter.swift */, + 4974F7EF092B4FC697A30E00 /* MatchScoringRules.swift */, + D17AB6B00BBC4568A6D0457E /* Models.swift */, + 134FD1D616EF4F82A0175E28 /* ScoreState.swift */, + BC65D1EBC15F4ECB921A94F5 /* BroadcastModels.swift */, + EBD03F804A944D6D84464875 /* BroadcastOrientationPolicy.swift */, + CBA94A102E6C4E1BAF934D53 /* BroadcastVideoOrientation.swift */, + E8E0CCB4B0554F96B04BDB07 /* LiveBroadcastCoordinator.swift */, + CD491B8176A0430A9C3AB7B9 /* LiveBroadcastEngine.swift */, + 7B9968E881924270973373DD /* CompactScoreboardElement.swift */, + C561AB7965264974822DBD60 /* OverlayCanvasRenderer.swift */, + 224057D043A541C287071B37 /* OverlayLogoCache.swift */, + FC8DDF8DE68C4281B9062AD0 /* OverlayMappings.swift */, + C397B3162F38497C9AD0C9CF /* OverlayRenderer.swift */, + DE44F992D17E408D8713CC95 /* OverlayState.swift */, + 6EA61FF84F91473DA84438A8 /* ScoreboardElement.swift */, + 8799BE797C4B4A409E32E753 /* SponsorElement.swift */, + 8DBA84B5B0CA459E89779309 /* WatermarkElement.swift */, + B1123FED73ED4983BFBE9BB6 /* LivePreviewView.swift */, + 6E0E8585555C42A6A220FF29 /* BroadcastControlsOverlay.swift */, + E94110FC43754C50AC862D5C /* BroadcastScreen.swift */, + C7D1C27A80A842A1B531051C /* LiveScoreActions.swift */, + BE69B3EE8D0E4D8EAA8B853B /* MatchLiveWordmark.swift */, + 36263581FBC9465FB59A54A3 /* MatchPrimaryButton.swift */, + A8FE87562E85488A946F8C86 /* MatchScreenScaffold.swift */, + 1144C664590842258CBE9998 /* MatchSecondaryButton.swift */, + BA7FA4E0FD3142D9957B764F /* MatchStatusBadge.swift */, + EAEE3C8BBB684FEBA230480A /* LoginScreen.swift */, + 40924F02DDFA4CCDA9488D64 /* MatchesScreen.swift */, + A3B41DFCE8AF4993A93F756A /* AppNavHost.swift */, + 2C3A3F3250284150B0A0BCD4 /* ModalRoutes.swift */, + 290C51105D0B4ABE997FA155 /* Routes.swift */, + 44FFA851A3BC44A784DF353A /* BroadcastPermissions.swift */, + 74D65108DA4C4A5BB95C0E51 /* SplashScreen.swift */, + A0DC8A3443404B0CAD323B11 /* KeepScreenOn.swift */, + E31852C7972040328E39C991 /* ScreenOrientation.swift */, + D603A791C926456D9B565F78 /* ShareSheet.swift */, + 7B2349A6BFDD4708B821C659 /* MatchColors.swift */, + 4B469A9557164A2682CEA145 /* StepMatchScreen.swift */, + F0D156DFC16945A3A8467EF0 /* StepNetworkTestScreen.swift */, + 74D13551050B4A51A21B0A67 /* StepTransmissionScreen.swift */, + 9AC1BB5EDAEE43359749B95A /* TeamBrandingEditor.swift */, + 6F6D45B70859402BA3ABD014 /* TeamColorPicker.swift */, + F3490DEC22A543F890FEA661 /* WizardComponents.swift */, + 96E61E730231499C9F119309 /* WizardShellScreen.swift */, + FE0CBD099ED14E62B752AB7F /* MatchLiveTv/Resources/Assets.xcassets */, + D4CD1243AC3D4BB8815BBE83 /* MatchLiveTv/Resources/Info.plist */, + ); + name = MatchLiveTv; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 553940DB807C4DBFB63E9FFE /* MatchLiveTv */ = { + 64F84AC8A424490D945D5B65 /* MatchLiveTvTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 4332218393F64E3CA1F31139 /* Build configuration list for PBXNativeTarget "MatchLiveTv" */; + buildConfigurationList = E3DA5397819945D09DC337F6 /* Build configuration list for PBXNativeTarget "MatchLiveTvTests" */; buildPhases = ( - 12E25B1D521C492F8F41CECF /* Sources */, - 085E7F6CFD2B4475AC00D329 /* Frameworks */, - 3944EAB1EB4B4139BBA13CBB /* Resources */, + 3245C286B7A54008850C0923 /* Sources */, + C180AAFADE0640639A940144 /* Frameworks */, + ); + 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 = ( ); @@ -313,40 +333,23 @@ ); name = MatchLiveTv; packageProductDependencies = ( - 3242173ACEDC4B288ACD56E4 /* HaishinKit */, - F3539A3AB0894C54992DB7D5 /* RTMPHaishinKit */, + DFA0D0CEB1F1428D9E3FB3DB /* HaishinKit */, + AA756D8C68BC4B3D8EC96D5E /* RTMPHaishinKit */, ); productName = MatchLiveTv; - productReference = B165DBC9A0DA4C62824D41C3 /* MatchLiveTv.app */; + productReference = AAB84103176746DB89E76F33 /* MatchLiveTv.app */; productType = "com.apple.product-type.application"; }; - 79FDBB021E5045C5A353AEE8 /* MatchLiveTvTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6F0E68806C0E4C1FBAC0863B /* Build configuration list for PBXNativeTarget "MatchLiveTvTests" */; - buildPhases = ( - 83261799604545698E663330 /* Sources */, - 521337FFC4E94E5880B1F174 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 89AF4750097043F984332B2B /* PBXTargetDependency */, - ); - name = MatchLiveTvTests; - productName = MatchLiveTvTests; - productReference = 5C49570E1FB3460BBEB502FC /* MatchLiveTvTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 72A102A7C8964137A464FF32 /* Project object */ = { + 76FC637A5DFB4F018A0D1441 /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 0; LastSwiftUpdateCheck = 1600; }; - buildConfigurationList = E2AD215689B3443E85A02B4C /* Build configuration list for PBXProject "MatchLiveTv" */; + buildConfigurationList = 27F2A4CC59994B3CA41841F5 /* Build configuration list for PBXProject "MatchLiveTv" */; compatibilityVersion = "Xcode 15.0"; developmentRegion = it; hasScannedForEncodings = 0; @@ -355,155 +358,156 @@ en, Base, ); - mainGroup = 631A87449B654E888E88BF77; + mainGroup = 14EA3A4718794D36964484DB; packageReferences = ( - 66E17694875F4BB2ADF2E1D6 /* XCRemoteSwiftPackageReference "HaishinKit" */, + 2DAE333E666A41BE8A5F1148 /* XCRemoteSwiftPackageReference "HaishinKit" */, ); - productRefGroup = 033861C6E3D248C6A4CEFAF6 /* Products */; + productRefGroup = 6668FF0B6F2E4C60861A918C /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 553940DB807C4DBFB63E9FFE /* MatchLiveTv */, - 79FDBB021E5045C5A353AEE8 /* MatchLiveTvTests */, + AE6E9D532CE6492D8B82687F /* MatchLiveTv */, + 64F84AC8A424490D945D5B65 /* MatchLiveTvTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 3944EAB1EB4B4139BBA13CBB /* Resources */ = { + 1C0CE5A5B45A41CBA8B910D1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - F05733319E284083A5AA2784 /* MatchLiveTv/Resources/Assets.xcassets in Resources */, + FE21BE8932864B5D96D1BA41 /* MatchLiveTv/Resources/Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 12E25B1D521C492F8F41CECF /* Sources */ = { + 3245C286B7A54008850C0923 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - CCB2F270DD464E608046A60C /* MatchLiveTvApp.swift in Sources */, - B5937876D40F4E21A63DB92A /* ApiInstant.swift in Sources */, - 674D6A9F61D742DF95F93C5B /* AppConfig.swift in Sources */, - 57B21B3B008A4345AEDFD7D2 /* ColorHex.swift in Sources */, - 5C80FF3E9F574F4EA2FDFEFF /* DeviceTelemetry.swift in Sources */, - 639783D4083F4049B5424C52 /* MediaUrl.swift in Sources */, - D6F532927A6345339AD2149D /* TokenStore.swift in Sources */, - E93FDA6122664F67A5448E2D /* UserFacingError.swift in Sources */, - 8DE2FE7CF4A34222B2D3066A /* ApiDtos.swift in Sources */, - E5B931C144DA46819918A5EC /* MatchLiveAPI.swift in Sources */, - D3C0878AD7354D41B540AD5B /* AppContainer.swift in Sources */, - D1334C2CFEC145328396B7EC /* ActionCableClient.swift in Sources */, - A3D8F65EBA8B479485321837 /* SessionCableService.swift in Sources */, - D67C481FC7DE46C6B7AD09C4 /* AuthRepository.swift in Sources */, - 4B1080F3C1354A89A859ACC6 /* MatchRepository.swift in Sources */, - BB73AB6E535F473EA6C1D232 /* MatchSessionLauncher.swift in Sources */, - 95848029AD4D4683B80DEA8C /* ScoreRepository.swift in Sources */, - EF984C15882E4E328BFCDA74 /* SessionRepository.swift in Sources */, - CEACB53FE13049B9959896F1 /* ScoreController.swift in Sources */, - 01BBD9C8228A4654BE791A09 /* WizardSessionHolder.swift in Sources */, - CBEE59E2E2DE4C058FF42022 /* MatchHubFilter.swift in Sources */, - E054E5E1703A4876B4E13F64 /* MatchScoringRules.swift in Sources */, - 9102501263E1477BAA6DEDD1 /* Models.swift in Sources */, - 4958D62D7A8944EAB3E54F18 /* ScoreState.swift in Sources */, - E75B414604CB429A9CCE797C /* BroadcastModels.swift in Sources */, - 9EAD5508F44243409C697F41 /* BroadcastOrientationPolicy.swift in Sources */, - 3C4DD1CE0BFA4CD9928234CD /* BroadcastVideoOrientation.swift in Sources */, - C9B2434416364C4BB263BB3F /* LiveBroadcastCoordinator.swift in Sources */, - B86EA543F6114B198D334FAF /* LiveBroadcastEngine.swift in Sources */, - 0712F271074B47B992C54B02 /* CompactScoreboardElement.swift in Sources */, - 266CD29FA3C048CC9413460A /* OverlayCanvasRenderer.swift in Sources */, - EA206B930BD448D3AC1E2578 /* OverlayLogoCache.swift in Sources */, - 44519A77D19C46218318593E /* OverlayMappings.swift in Sources */, - 3628957732604F1597784B04 /* OverlayRenderer.swift in Sources */, - 38938AED35E94A99A4921FF3 /* OverlayState.swift in Sources */, - 0747277C94AD48939CBAE80B /* ScoreboardElement.swift in Sources */, - 306216CA292D4974B612AC06 /* SponsorElement.swift in Sources */, - 830325BE85674DD6A31CE672 /* WatermarkElement.swift in Sources */, - 89F47A469F6044B9A92D647A /* LivePreviewView.swift in Sources */, - 8CDFA36E735A4A94A5A60DBF /* BroadcastControlsOverlay.swift in Sources */, - 9770A3D9677F42AC942E98A4 /* BroadcastScreen.swift in Sources */, - 832E24DBB2844E9895717F6F /* LiveScoreActions.swift in Sources */, - F5B6F5CD2D9245BDB8E81055 /* MatchLiveWordmark.swift in Sources */, - ABE74DCBA6804EDEB5398F8F /* MatchPrimaryButton.swift in Sources */, - 2757AF56199F46A49036C307 /* MatchScreenScaffold.swift in Sources */, - 83E38DFBBFFF4412BF2ABEE9 /* MatchSecondaryButton.swift in Sources */, - AB3DF660C79648CFAECB03CF /* MatchStatusBadge.swift in Sources */, - C0CA6EBDA3E84641AFEC3A12 /* LoginScreen.swift in Sources */, - 4236C0FB1B10435EB03C39DF /* MatchesScreen.swift in Sources */, - 49586D0F50AA4BE692FDCF3F /* AppNavHost.swift in Sources */, - EB3C108379594E7EBCBCE016 /* ModalRoutes.swift in Sources */, - 8DB866F0F33A4F3BAA074660 /* Routes.swift in Sources */, - BD2628C89CAD450ABF613183 /* BroadcastPermissions.swift in Sources */, - 815C82E2C5C54746ABF73BEE /* SplashScreen.swift in Sources */, - EED290CEF4A141608F7BE515 /* KeepScreenOn.swift in Sources */, - 7F7C79F0C4EA4B06A5A2E4BA /* ScreenOrientation.swift in Sources */, - BAE5062DD4B749E6BC569CCA /* ShareSheet.swift in Sources */, - B578A98681A8413DBFEF58CA /* MatchColors.swift in Sources */, - 1DE6EABFB67F4046957C9B88 /* StepMatchScreen.swift in Sources */, - 9EF4BA3F81C341B4ACAB643F /* StepNetworkTestScreen.swift in Sources */, - F212F8F1DA0C42619D13D30E /* StepTransmissionScreen.swift in Sources */, - 1C71C5745AF541A793FBD415 /* TeamBrandingEditor.swift in Sources */, - 7DC17CB11FC246378F6624C0 /* TeamColorPicker.swift in Sources */, - 3477E99DCB6843BB8037EB21 /* WizardComponents.swift in Sources */, - 9A208AE54E434798BD5DF06F /* WizardShellScreen.swift in Sources */, + EBB063DFDBE443F3BC12A67A /* ApiInstantTests.swift in Sources */, + 3AA28F966201426380DEE174 /* BroadcastOrientationPolicyTests.swift in Sources */, + 644B22C2C7E54983A6BE393D /* LiveBroadcastCoordinatorTests.swift in Sources */, + 4CD8A3EB76C14F878BF1026C /* LiveScoreDialogHostTests.swift in Sources */, + 35FE18027B054D5BBC20DC9C /* MatchScoringRulesTests.swift in Sources */, + 2498A1488A034D058E6997B0 /* ScoreActionDecodeTests.swift in Sources */, + 6C52A9292D694A728A372551 /* ScoreControllerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 83261799604545698E663330 /* Sources */ = { + AC8B6077C49C4F0086F06F1B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DFC67AC6380B41BC8A8CE866 /* ApiInstantTests.swift in Sources */, - F36DADA0DA9245A48E3DDB29 /* BroadcastOrientationPolicyTests.swift in Sources */, - C1D94B81E44C4BFD8351B165 /* LiveBroadcastCoordinatorTests.swift in Sources */, - 82D6D70F2E554414961F27C3 /* MatchScoringRulesTests.swift in Sources */, - 9EDC5C176D2E40F29455CCEF /* ScoreActionDecodeTests.swift in Sources */, - 07C244E32A4D48A185963C6C /* ScoreControllerTests.swift in Sources */, + 5D4E00AC5D4E44A09E3743DE /* MatchLiveTvApp.swift in Sources */, + 82ADD6499C394031B87D7A96 /* ApiInstant.swift in Sources */, + D916D4368A9A4298BDB3430F /* AppConfig.swift in Sources */, + 994148BB9CCE4E6F800CD89A /* ColorHex.swift in Sources */, + 22A2A4F3BBD845C5B4E1DD6E /* DeviceTelemetry.swift in Sources */, + 6CA1DE649AEE455C994D0E94 /* MediaUrl.swift in Sources */, + 284F82D0FB65448BAB38C6BE /* TokenStore.swift in Sources */, + CAABC65179F6467996D85730 /* UserFacingError.swift in Sources */, + 2D3FAEEE0372415381467FC7 /* ApiDtos.swift in Sources */, + EB8D708E665A46B398EB0C4F /* MatchLiveAPI.swift in Sources */, + 52DCD38F408B4BAE8A0A673D /* AppContainer.swift in Sources */, + 39E01672805E4B8A88DA0FA9 /* ActionCableClient.swift in Sources */, + 48719B5718B2419E96AE6AF2 /* SessionCableService.swift in Sources */, + 9E770D39394E41838877BC62 /* AuthRepository.swift in Sources */, + D77980669AE84165AAF94AF2 /* MatchRepository.swift in Sources */, + 3027E88493BA43B09B150BA1 /* MatchSessionLauncher.swift in Sources */, + 0E03BE40DAF14E98A35051CE /* ScoreRepository.swift in Sources */, + 045086A670F24B1192E0DF8F /* SessionRepository.swift in Sources */, + 53A492E3510D4C8A9A5C94B7 /* ScoreController.swift in Sources */, + 5A8E598237CF41BFB62B83D8 /* WizardSessionHolder.swift in Sources */, + B3DD2F8E837649B2B007CEAF /* MatchHubFilter.swift in Sources */, + 6CC11041AFC64969BC9195D0 /* MatchScoringRules.swift in Sources */, + 8BAE2CEB56064BA3A3A16B53 /* Models.swift in Sources */, + EA533D28A4EF4171B410B56E /* ScoreState.swift in Sources */, + 96E2427E81E744289D1C9B9B /* BroadcastModels.swift in Sources */, + 9D241B051BD54105A9D764DD /* BroadcastOrientationPolicy.swift in Sources */, + 4BD05489BDAB4E309311B1C7 /* BroadcastVideoOrientation.swift in Sources */, + 991371D458954C06A798AC0E /* LiveBroadcastCoordinator.swift in Sources */, + 59BB3212FCBA4F68B23337F3 /* LiveBroadcastEngine.swift in Sources */, + D0BAD147978244529A46C040 /* CompactScoreboardElement.swift in Sources */, + EE689B65571A474CA19A792C /* OverlayCanvasRenderer.swift in Sources */, + 6E09F9E1FBB3459B94343BDD /* OverlayLogoCache.swift in Sources */, + 91C697AC57284A26A9893DFD /* OverlayMappings.swift in Sources */, + 4A6973ACDCA743B29ACC1E2E /* OverlayRenderer.swift in Sources */, + 7862CEBEB345430F908DE135 /* OverlayState.swift in Sources */, + 15EBD3E3D95D4AE5BABB6776 /* ScoreboardElement.swift in Sources */, + 7DCAA615F27C4853B8A0F889 /* SponsorElement.swift in Sources */, + 28A607B3D84448308B130ECF /* WatermarkElement.swift in Sources */, + AEE1728EFF3F491A81B1156B /* LivePreviewView.swift in Sources */, + 921A1A2729B244C08A9BD3FD /* BroadcastControlsOverlay.swift in Sources */, + C5EEE95F92D44046994659FC /* BroadcastScreen.swift in Sources */, + 191F31088FCE4A82932B6FBB /* LiveScoreActions.swift in Sources */, + 6DAD6078CC8D46FCB1AE0A75 /* MatchLiveWordmark.swift in Sources */, + D015D7ACCFE54071B1831C74 /* MatchPrimaryButton.swift in Sources */, + 91F1D3111F2C4BDFAB7435BF /* MatchScreenScaffold.swift in Sources */, + 464C286CAE724604AF9CC1FD /* MatchSecondaryButton.swift in Sources */, + F13DF021E1084F6C844CB7AB /* MatchStatusBadge.swift in Sources */, + 0CE091822CAA4D88B1BE3AF4 /* LoginScreen.swift in Sources */, + C6B059D6435243208A8FC338 /* MatchesScreen.swift in Sources */, + D501A7EE3BAD467A9A63E63C /* AppNavHost.swift in Sources */, + 138294291C614F218D71B1CD /* ModalRoutes.swift in Sources */, + D3C28481960E4E14A0909DCB /* Routes.swift in Sources */, + 30F21F19C7234BBF8B2B77D4 /* BroadcastPermissions.swift in Sources */, + 51B03D8318114D3AB94A41CA /* SplashScreen.swift in Sources */, + 08F123F9692D48EA94EBD94D /* KeepScreenOn.swift in Sources */, + 5E33700F7C694E9D8EC997D7 /* ScreenOrientation.swift in Sources */, + 3A08990CB238458CA25C07C9 /* ShareSheet.swift in Sources */, + 4598E75CCCF5492CB2F0B006 /* MatchColors.swift in Sources */, + 66539A1D77EA4B368F5BDE2E /* StepMatchScreen.swift in Sources */, + EF83C38F78144E0996C33807 /* StepNetworkTestScreen.swift in Sources */, + B7D592901EC34D4B97DCE549 /* StepTransmissionScreen.swift in Sources */, + F13AA7F009F1421FB996956B /* TeamBrandingEditor.swift in Sources */, + 00BDF215CB7942A799F06774 /* TeamColorPicker.swift in Sources */, + 7B4182E19F93484B8B0D07DF /* WizardComponents.swift in Sources */, + 4A67DD768F074E7885DFDF43 /* WizardShellScreen.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 89AF4750097043F984332B2B /* PBXTargetDependency */ = { + 4264391B98534ED485BCB343 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 553940DB807C4DBFB63E9FFE /* MatchLiveTv */; - targetProxy = E0F627D71C6349F1857AFED5 /* PBXContainerItemProxy */; + target = AE6E9D532CE6492D8B82687F /* MatchLiveTv */; + targetProxy = ACB2FE70CE4841CCB7A0ACC7 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 07CBA422677E4E909A377797 /* Release */ = { + 10AA1592F59B4796984A3DF8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; + API_BASE_URL = "https://www.matchlivetv.it"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 21; - GENERATE_INFOPLIST_FILE = YES; + DEVELOPMENT_TEAM = S8Q9TWBRG5; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = MatchLiveTv/Resources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); MARKETING_VERSION = 2.0.0; - PRODUCT_BUNDLE_IDENTIFIER = "com.matchlivetv.match-live-tv.tests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.matchlivetv.match-live-tv"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SWIFT_ENABLE_EXPLICIT_MODULES = NO; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MatchLiveTv.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/MatchLiveTv"; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; - 38453F3C33434DFD8F94862C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 5C7F305207F64DC79FEA28D2 /* Debug */ = { + 13D89B468B1A4BC7A4C411CC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { IPHONEOS_DEPLOYMENT_TARGET = 16.0; @@ -511,7 +515,7 @@ }; name = Debug; }; - A1EF7CCA2C8D46938E2764C4 /* Debug */ = { + 3D4B16FD3007411E80F55942 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { API_BASE_URL = "https://www.matchlivetv.it"; @@ -538,33 +542,15 @@ }; name = Debug; }; - BE33A670C527464E85B1F231 /* Release */ = { + 4112889F91F94934ADAC5A6E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - API_BASE_URL = "https://www.matchlivetv.it"; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 21; - DEVELOPMENT_TEAM = S8Q9TWBRG5; - GENERATE_INFOPLIST_FILE = NO; - INFOPLIST_FILE = MatchLiveTv/Resources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 2.0.0; - PRODUCT_BUNDLE_IDENTIFIER = "com.matchlivetv.match-live-tv"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SWIFT_ENABLE_EXPLICIT_MODULES = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; - F6DDD32ED386440687F72916 /* Debug */ = { + 8EEBF4BEA19A487B9CA09A7E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; @@ -582,32 +568,50 @@ }; name = Debug; }; + E449653FF06F4DCDB2AFC77A /* Release */ = { + 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 = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 4332218393F64E3CA1F31139 /* Build configuration list for PBXNativeTarget "MatchLiveTv" */ = { + 002C5EF177A5409AAE23DB38 /* Build configuration list for PBXNativeTarget "MatchLiveTv" */ = { isa = XCConfigurationList; buildConfigurations = ( - A1EF7CCA2C8D46938E2764C4 /* Debug */, - BE33A670C527464E85B1F231 /* Release */, + 3D4B16FD3007411E80F55942 /* Debug */, + 10AA1592F59B4796984A3DF8 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6F0E68806C0E4C1FBAC0863B /* Build configuration list for PBXNativeTarget "MatchLiveTvTests" */ = { + 27F2A4CC59994B3CA41841F5 /* Build configuration list for PBXProject "MatchLiveTv" */ = { isa = XCConfigurationList; buildConfigurations = ( - F6DDD32ED386440687F72916 /* Debug */, - 07CBA422677E4E909A377797 /* Release */, + 13D89B468B1A4BC7A4C411CC /* Debug */, + 4112889F91F94934ADAC5A6E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - E2AD215689B3443E85A02B4C /* Build configuration list for PBXProject "MatchLiveTv" */ = { + E3DA5397819945D09DC337F6 /* Build configuration list for PBXNativeTarget "MatchLiveTvTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - 5C7F305207F64DC79FEA28D2 /* Debug */, - 38453F3C33434DFD8F94862C /* Release */, + 8EEBF4BEA19A487B9CA09A7E /* Debug */, + E449653FF06F4DCDB2AFC77A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -615,7 +619,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 66E17694875F4BB2ADF2E1D6 /* XCRemoteSwiftPackageReference "HaishinKit" */ = { + 2DAE333E666A41BE8A5F1148 /* XCRemoteSwiftPackageReference "HaishinKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/shogo4405/HaishinKit.swift"; requirement = { @@ -626,17 +630,17 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 3242173ACEDC4B288ACD56E4 /* HaishinKit */ = { + AA756D8C68BC4B3D8EC96D5E /* RTMPHaishinKit */ = { isa = XCSwiftPackageProductDependency; - package = 66E17694875F4BB2ADF2E1D6 /* XCRemoteSwiftPackageReference "HaishinKit" */; - productName = HaishinKit; - }; - F3539A3AB0894C54992DB7D5 /* RTMPHaishinKit */ = { - isa = XCSwiftPackageProductDependency; - package = 66E17694875F4BB2ADF2E1D6 /* XCRemoteSwiftPackageReference "HaishinKit" */; + package = 2DAE333E666A41BE8A5F1148 /* XCRemoteSwiftPackageReference "HaishinKit" */; productName = RTMPHaishinKit; }; + DFA0D0CEB1F1428D9E3FB3DB /* HaishinKit */ = { + isa = XCSwiftPackageProductDependency; + package = 2DAE333E666A41BE8A5F1148 /* XCRemoteSwiftPackageReference "HaishinKit" */; + productName = HaishinKit; + }; /* End XCSwiftPackageProductDependency section */ }; - rootObject = 72A102A7C8964137A464FF32 /* Project object */; + rootObject = 76FC637A5DFB4F018A0D1441 /* Project object */; } diff --git a/native/ios/MatchLiveTv.xcodeproj/xcshareddata/xcschemes/MatchLiveTv.xcscheme b/native/ios/MatchLiveTv.xcodeproj/xcshareddata/xcschemes/MatchLiveTv.xcscheme index 114461b..c6774f0 100644 --- a/native/ios/MatchLiveTv.xcodeproj/xcshareddata/xcschemes/MatchLiveTv.xcscheme +++ b/native/ios/MatchLiveTv.xcodeproj/xcshareddata/xcschemes/MatchLiveTv.xcscheme @@ -3,28 +3,28 @@ - + - + - + - + - + diff --git a/native/ios/MatchLiveTv/Data/Scoring/ScoreController.swift b/native/ios/MatchLiveTv/Data/Scoring/ScoreController.swift index 3560e33..7152b47 100644 --- a/native/ios/MatchLiveTv/Data/Scoring/ScoreController.swift +++ b/native/ios/MatchLiveTv/Data/Scoring/ScoreController.swift @@ -101,6 +101,7 @@ final class ScoreController: ObservableObject { syncGeneration += 1 guard let sessionId else { return false } + let previous = score let optimistic = closedSetState(from: score) score = optimistic sessionCable.sendScoreUpdate(optimistic) @@ -112,9 +113,11 @@ final class ScoreController: ObservableObject { sessionCable.sendScoreUpdate(updated) return true } - suppressRemoteUntil = Date().addingTimeInterval(3) - return true + score = previous + lastActionError = "Chiusura set non confermata dal server" + return false } catch { + score = previous lastActionError = UserFacingError.message(for: error) return false } @@ -161,10 +164,22 @@ final class ScoreController: ObservableObject { case "away_point_3": state.awayPoints += 3 case "home_undo": state.homePoints = max(0, state.homePoints - 1) case "away_undo": state.awayPoints = max(0, state.awayPoints - 1) + case "advance_period": applyOptimisticAdvancePeriod(to: &state) default: break } } + private func applyOptimisticAdvancePeriod(to state: inout ScoreState) { + guard ScoreState.periodBoards.contains(state.boardType) else { return } + state.period += 1 + state.clockRunning = false + if state.boardType == "basket" { + state.periodLabel = "Q\(state.period)" + } else if state.boardType == "timed" { + state.periodLabel = "\(state.period)° tempo" + } + } + private func scheduleAction(_ action: String) { syncTask?.cancel() syncGeneration += 1 @@ -174,9 +189,12 @@ final class ScoreController: ObservableObject { do { if let updated = try await scoreRepository.applyScoreAction(sessionId: sessionId, action: action) { guard generation == syncGeneration else { return } - suppressRemoteUntil = Date().addingTimeInterval(0.5) + suppressRemoteUntil = Date().addingTimeInterval(0.8) score = updated sessionCable.sendScoreUpdate(updated) + } else { + guard generation == syncGeneration else { return } + lastActionError = "Risposta punteggio non valida" } } catch { guard generation == syncGeneration else { return } diff --git a/native/ios/MatchLiveTv/Domain/ScoreState.swift b/native/ios/MatchLiveTv/Domain/ScoreState.swift index 2a1eb5a..87037c9 100644 --- a/native/ios/MatchLiveTv/Domain/ScoreState.swift +++ b/native/ios/MatchLiveTv/Domain/ScoreState.swift @@ -57,6 +57,8 @@ struct ScoreState: Equatable, Sendable { key &+= Int64(homePoints) * 10 key &+= Int64(awayPoints) key &+= Int64(clockSecs) + key &+= Int64(period) * 100_000_000 + key &+= overtime ? 50_000_000 : 0 key &+= Int64(setPartials.count) * 1_000_000 for partial in setPartials { key &+= Int64(partial.set) * 10_000 diff --git a/native/ios/MatchLiveTv/Streaming/BroadcastOrientationPolicy.swift b/native/ios/MatchLiveTv/Streaming/BroadcastOrientationPolicy.swift index 3634bb9..582702c 100644 --- a/native/ios/MatchLiveTv/Streaming/BroadcastOrientationPolicy.swift +++ b/native/ios/MatchLiveTv/Streaming/BroadcastOrientationPolicy.swift @@ -1,11 +1,14 @@ import AVFoundation +import UIKit /// Regole orientamento in diretta (allineate al debounce Android). enum BroadcastOrientationPolicy { /// Attesa prima di applicare rotazione al mixer (evita burst da giro iPad). static let debounceNanoseconds: UInt64 = 350_000_000 /// Finestra in cui ignorare `closed` RTMP dopo rotazione encoder. - static let suppressDisconnectSeconds: TimeInterval = 1.0 + static var suppressDisconnectSeconds: TimeInterval { + UIDevice.current.userInterfaceIdiom == .pad ? 2.5 : 1.0 + } static func shouldApplyMixerOrientation( new: AVCaptureVideoOrientation, diff --git a/native/ios/MatchLiveTv/Streaming/LiveBroadcastEngine.swift b/native/ios/MatchLiveTv/Streaming/LiveBroadcastEngine.swift index 91dd04b..89b9b6e 100644 --- a/native/ios/MatchLiveTv/Streaming/LiveBroadcastEngine.swift +++ b/native/ios/MatchLiveTv/Streaming/LiveBroadcastEngine.swift @@ -42,6 +42,8 @@ final class LiveBroadcastEngine: ObservableObject { private var broadcastGeneration = 0 private var suppressDisconnectError = false private var orientationTransitionUntil: Date = .distantPast + private var reconnectAttempts = 0 + private var reconnectTask: Task? private var lastAppliedCaptureOrientation: AVCaptureVideoOrientation? private var orientationDebounceTask: Task? private var rtmpSession: (any Session)? @@ -121,6 +123,9 @@ final class LiveBroadcastEngine: ObservableObject { self.suppressDisconnectError = suppressDisconnectError defer { self.suppressDisconnectError = false } broadcastGeneration += 1 + reconnectTask?.cancel() + reconnectTask = nil + reconnectAttempts = 0 publishPending = false publishTask?.cancel() publishTask = nil @@ -130,6 +135,9 @@ final class LiveBroadcastEngine: ObservableObject { func resumeBroadcast(config: BroadcastConfig) async throws { self.config = config + reconnectAttempts = 0 + reconnectTask?.cancel() + reconnectTask = nil publishPending = true if !pipelineConfigured { try await configurePipeline(config) @@ -144,6 +152,9 @@ final class LiveBroadcastEngine: ObservableObject { self.suppressDisconnectError = suppressDisconnectError defer { self.suppressDisconnectError = false } broadcastGeneration += 1 + reconnectTask?.cancel() + reconnectTask = nil + reconnectAttempts = 0 publishTask?.cancel() publishTask = nil publishPending = false @@ -254,10 +265,15 @@ final class LiveBroadcastEngine: ObservableObject { try await publish(config: config, generation: generation) if generation == broadcastGeneration { publishPending = false + reconnectAttempts = 0 } } catch { guard generation == broadcastGeneration else { return } publishPending = false + if phase == .reconnecting || reconnectAttempts > 0 { + scheduleReconnect() + return + } let message = UserFacingError.message(for: error) ?? "Connessione RTMP fallita" setPhase(.error, error: message) } @@ -300,16 +316,16 @@ final class LiveBroadcastEngine: ObservableObject { try await session.connect { [weak self] in Task { @MainActor in guard let self, - !self.shouldSuppressDisconnectError, self.broadcastGeneration == generation, - self.phase == .live else { return } - self.setPhase(.error, error: "Connessione RTMP interrotta") + self.phase == .live || self.phase == .reconnecting else { return } + self.scheduleReconnect() } } guard generation == broadcastGeneration else { await teardownRTMP(keepPreview: true) return } + reconnectAttempts = 0 setPhase(.live) } @@ -341,9 +357,8 @@ final class LiveBroadcastEngine: ObservableObject { switch state { case .open: setPhase(.live) - case .closed where phase == .live: - guard !shouldSuppressDisconnectError else { return } - setPhase(.error, error: "Connessione RTMP interrotta") + case .closed where phase == .live || phase == .reconnecting: + scheduleReconnect() default: break } @@ -369,6 +384,33 @@ final class LiveBroadcastEngine: ObservableObject { suppressDisconnectError || Date() < orientationTransitionUntil } + /// Riconnessione automatica RTMP (come Android): evita falsi errori su iPad. + private func scheduleReconnect() { + guard !shouldSuppressDisconnectError else { return } + guard phase == .live || phase == .reconnecting else { return } + guard let config else { return } + + reconnectAttempts += 1 + if reconnectAttempts > config.maxReconnectAttempts { + reconnectTask = nil + setPhase(.error, error: "Connessione RTMP interrotta") + return + } + + setPhase(.reconnecting) + reconnectTask?.cancel() + let generation = broadcastGeneration + let delayMs = config.reconnectDelayMs + reconnectTask = Task { + try? await Task.sleep(nanoseconds: UInt64(delayMs) * 1_000_000) + guard !Task.isCancelled, generation == broadcastGeneration else { return } + guard phase == .reconnecting else { return } + publishPending = true + publishInFlight = false + await startPendingPublish() + } + } + private func applyVideoOrientationIfNeeded(force: Bool = false) async { let orientation = BroadcastVideoOrientation.captureOrientation() let landscapeLocked = AppOrientation.mode == .landscape diff --git a/native/ios/MatchLiveTv/UI/Broadcast/BroadcastScreen.swift b/native/ios/MatchLiveTv/UI/Broadcast/BroadcastScreen.swift index 1b51047..dce241b 100644 --- a/native/ios/MatchLiveTv/UI/Broadcast/BroadcastScreen.swift +++ b/native/ios/MatchLiveTv/UI/Broadcast/BroadcastScreen.swift @@ -117,7 +117,10 @@ struct BroadcastScreen: View { } } .alert("Errore", isPresented: Binding(get: { error != nil }, set: { if !$0 { error = nil } })) { - Button("OK") { onFinished() } + Button("Riprova") { + Task { await retryBroadcast() } + } + Button("Esci", role: .destructive) { onFinished() } } message: { Text(error ?? "") } @@ -240,7 +243,12 @@ struct BroadcastScreen: View { onCloseSet: usesSetScoring ? { Task { await liveScoreActions(for: match).requestCloseSet() } } : nil, - onAdvancePeriod: usesActionScoring ? { scoreController.applyAction("advance_period") } : nil, + onAdvancePeriod: usesActionScoring ? { + Task { + guard await scoreController.applyBoardAction("advance_period") else { return } + updateOverlay() + } + } : nil, onPauseOrResume: { if isPaused { Task { await resumeStream() } @@ -285,6 +293,7 @@ struct BroadcastScreen: View { if isPaused { return MatchColors.accentYellow } switch metrics.phase { case .live: return MatchColors.successGreen + case .reconnecting: return MatchColors.accentYellow case .error: return MatchColors.primaryRed default: return MatchColors.accentYellow } @@ -500,6 +509,18 @@ struct BroadcastScreen: View { ) } + private func retryBroadcast() async { + error = nil + guard let session, let url = session.rtmpIngestUrl, !url.isEmpty else { return } + let config = broadcastConfig(for: session, rtmpUrl: url) + do { + try await container.broadcastCoordinator.resumeBroadcast(config: config) + snackbarMessage = "Riconnessione avviata" + } catch { + self.error = UserFacingError.message(for: error) ?? "Riconnessione non riuscita" + } + } + private func stopStream() async { _ = try? await container.sessionRepository.stopSession(id: sessionId) await teardown() diff --git a/native/ios/MatchLiveTv/UI/Broadcast/LiveScoreActions.swift b/native/ios/MatchLiveTv/UI/Broadcast/LiveScoreActions.swift index 6ee266f..7c29ecc 100644 --- a/native/ios/MatchLiveTv/UI/Broadcast/LiveScoreActions.swift +++ b/native/ios/MatchLiveTv/UI/Broadcast/LiveScoreActions.swift @@ -31,9 +31,10 @@ final class LiveScoreDialogHost: ObservableObject { } func resolve(_ value: Bool) { + guard let continuation = waiter else { return } pending = nil - waiter?.resume(returning: value) waiter = nil + continuation.resume(returning: value) } } @@ -131,10 +132,9 @@ struct ScoreDialogRouter: View { private var dialogBinding: Binding { Binding( get: { host.pending }, - set: { newValue in - if newValue == nil, host.pending != nil { - host.resolve(false) - } + set: { _ in + // Non risolvere qui: su iPad la dismiss dell'alert può azzerare l'item + // dopo il tap su «Chiudi set» e sovrascrivere resolve(true) con false. } ) } diff --git a/native/ios/MatchLiveTvTests/LiveScoreDialogHostTests.swift b/native/ios/MatchLiveTvTests/LiveScoreDialogHostTests.swift new file mode 100644 index 0000000..b68ed5c --- /dev/null +++ b/native/ios/MatchLiveTvTests/LiveScoreDialogHostTests.swift @@ -0,0 +1,25 @@ +import XCTest +@testable import MatchLiveTv + +@MainActor +final class LiveScoreDialogHostTests: XCTestCase { + func testResolveTrueCompletesShow() async { + let host = LiveScoreDialogHost() + let task = Task { await host.show(ScoreDialogState(kind: .setWon)) } + try? await Task.sleep(nanoseconds: 50_000_000) + host.resolve(true) + let result = await task.value + XCTAssertTrue(result) + XCTAssertNil(host.pending) + } + + func testSecondResolveIsIgnored() async { + let host = LiveScoreDialogHost() + let task = Task { await host.show(ScoreDialogState(kind: .setWon)) } + try? await Task.sleep(nanoseconds: 50_000_000) + host.resolve(true) + host.resolve(false) + let result = await task.value + XCTAssertTrue(result) + } +} diff --git a/native/ios/MatchLiveTvTests/ScoreActionDecodeTests.swift b/native/ios/MatchLiveTvTests/ScoreActionDecodeTests.swift index 6ddf00d..1eab5c8 100644 --- a/native/ios/MatchLiveTvTests/ScoreActionDecodeTests.swift +++ b/native/ios/MatchLiveTvTests/ScoreActionDecodeTests.swift @@ -65,4 +65,38 @@ final class ScoreActionDecodeTests: XCTestCase { XCTAssertEqual(score.setPartials[0].home, 25) XCTAssertEqual(score.setPartials[0].away, 18) } + + func testDecodesBasketAdvancePeriodResponse() throws { + let json = """ + { + "id": "821ddb81-9dc2-466a-9ad5-2555e78f4653", + "match_id": "e887ce1d-10ee-4680-8323-79bb8f11e0aa", + "status": "live", + "platform": "matchlivetv", + "score": { + "type": "score_update", + "board_type": "basket", + "home_points": 12, + "away_points": 10, + "current_set": 1, + "set_partials": [], + "timeout_home": false, + "timeout_away": false, + "period": "Q2", + "clock_secs": 600, + "clock_running": false, + "data": { "home_score": 12, "away_score": 10, "period": 2, "clock_secs": 600, "clock_running": false, "overtime": false } + }, + "set_won": false, + "match_won": false, + "winner": null + } + """.data(using: .utf8)! + let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json) + let score = try XCTUnwrap(dto.score?.toDomain()) + XCTAssertEqual(score.periodLabel, "Q2") + XCTAssertEqual(score.period, 2) + XCTAssertEqual(score.clockSecs, 600) + XCTAssertFalse(score.clockRunning) + } } diff --git a/native/ios/MatchLiveTvTests/ScoreControllerTests.swift b/native/ios/MatchLiveTvTests/ScoreControllerTests.swift index b34473d..4357363 100644 --- a/native/ios/MatchLiveTvTests/ScoreControllerTests.swift +++ b/native/ios/MatchLiveTvTests/ScoreControllerTests.swift @@ -55,4 +55,30 @@ final class ScoreControllerTests: XCTestCase { controller.applyAction("home_point") XCTAssertEqual(controller.score.homePoints, 1) } + + func testAdvancePeriodOptimisticUpdatesQuarter() { + let controller = ScoreController( + scoreRepository: ScoreRepository(api: MatchLiveAPI()), + sessionCable: SessionCableService() + ) + var initial = ScoreState() + initial.boardType = "basket" + initial.period = 1 + initial.periodLabel = "Q1" + controller.bind(sessionId: "session-1", initial: initial) + controller.applyAction("advance_period") + XCTAssertEqual(controller.score.period, 2) + XCTAssertEqual(controller.score.periodLabel, "Q2") + XCTAssertFalse(controller.score.clockRunning) + } + + func testProgressKeyChangesWhenPeriodAdvances() { + var q1 = ScoreState(boardType: "basket", period: 1, periodLabel: "Q1", clockSecs: 600) + var q2 = ScoreState(boardType: "basket", period: 2, periodLabel: "Q2", clockSecs: 600) + q1.homePoints = 10 + q1.awayPoints = 8 + q2.homePoints = 10 + q2.awayPoints = 8 + XCTAssertGreaterThan(q2.progressKey(), q1.progressKey()) + } }