Skip to content

Commit 38be10a

Browse files
committed
Scoreboard refactoring.
1 parent dccd895 commit 38be10a

File tree

1 file changed

+166
-134
lines changed

1 file changed

+166
-134
lines changed

Moblin/VideoEffects/Scoreboard/ScoreboardEffect.swift

Lines changed: 166 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -81,65 +81,64 @@ private func padelScoreboardSettingsToEffect(_ scoreboard: SettingsWidgetPadelSc
8181
return PadelScoreboard(home: home, away: away, score: score)
8282
}
8383

84-
final class ScoreboardEffect: VideoEffect {
85-
private var scoreboardImage: CIImage?
86-
private var sceneWidget: SettingsSceneWidget?
87-
88-
func setSceneWidget(sceneWidget: SettingsSceneWidget) {
89-
processorPipelineQueue.async {
90-
self.sceneWidget = sceneWidget
91-
}
92-
}
93-
94-
@MainActor
95-
func update(scoreboard: SettingsWidgetScoreboard,
96-
config: RemoteControlScoreboardMatchConfig,
97-
players: [SettingsWidgetScoreboardPlayer])
98-
{
99-
switch scoreboard.sport {
100-
case .padel:
101-
updatePadel(textColor: scoreboard.textColorColor,
102-
primaryBackgroundColor: scoreboard.primaryBackgroundColorColor,
103-
secondaryBackgroundColor: scoreboard.secondaryBackgroundColorColor,
104-
padel: scoreboard.padel,
105-
players: players)
106-
case .generic:
107-
updateGeneric(textColor: scoreboard.textColorColor,
108-
primaryBackgroundColor: scoreboard.primaryBackgroundColorColor,
109-
secondaryBackgroundColor: scoreboard.secondaryBackgroundColorColor,
110-
generic: scoreboard.generic)
111-
default:
112-
updateModular(modular: scoreboard.modular, config: config)
113-
}
114-
}
84+
private struct GenericScoreboardView: View {
85+
let textColor: Color
86+
let primaryBackgroundColor: Color
87+
let secondaryBackgroundColor: Color
88+
@ObservedObject var generic: SettingsWidgetGenericScoreboard
11589

116-
override func execute(_ image: CIImage, _: VideoEffectInfo) -> CIImage {
117-
guard let scoreboardImage, let sceneWidget else {
118-
return image
90+
var body: some View {
91+
VStack(alignment: .leading, spacing: 0) {
92+
HStack {
93+
Text(generic.title)
94+
Spacer()
95+
Text(generic.clock.format())
96+
.monospacedDigit()
97+
.font(.system(size: 25))
98+
}
99+
.padding(5)
100+
.background(secondaryBackgroundColor)
101+
HStack(alignment: .center, spacing: 18) {
102+
VStack(alignment: .leading) {
103+
VStack(alignment: .leading) {
104+
Spacer(minLength: 0)
105+
Text(generic.home.uppercased())
106+
Spacer(minLength: 0)
107+
}
108+
VStack(alignment: .leading) {
109+
Spacer(minLength: 0)
110+
Text(generic.away.uppercased())
111+
Spacer(minLength: 0)
112+
}
113+
}
114+
.font(.system(size: 25))
115+
Spacer()
116+
VStack {
117+
TeamScoreView(score: generic.score.home)
118+
TeamScoreView(score: generic.score.away)
119+
}
120+
.frame(width: 28)
121+
.font(.system(size: 45))
122+
}
123+
.padding([.leading, .trailing], 5)
124+
.background(primaryBackgroundColor)
125+
PoweredByMoblinView(backgroundColor: secondaryBackgroundColor)
119126
}
120-
let scale = image.extent.size.maximum() / 1920
121-
return scoreboardImage
122-
.scaled(x: scale, y: scale)
123-
.move(sceneWidget.layout, image.extent.size)
124-
.cropped(to: image.extent)
125-
.composited(over: image)
127+
.clipShape(RoundedRectangle(cornerRadius: 5))
128+
.foregroundStyle(textColor)
126129
}
130+
}
127131

128-
private func setScoreboardImage(image: CIImage?) {
129-
processorPipelineQueue.async {
130-
self.scoreboardImage = image
131-
}
132-
}
132+
private struct PadelScoreboardView: View {
133+
let textColor: Color
134+
let primaryBackgroundColor: Color
135+
let secondaryBackgroundColor: Color
136+
let padel: SettingsWidgetPadelScoreboard
137+
let players: [SettingsWidgetScoreboardPlayer]
133138

134-
@MainActor
135-
private func updatePadel(textColor: Color,
136-
primaryBackgroundColor: Color,
137-
secondaryBackgroundColor: Color,
138-
padel: SettingsWidgetPadelScoreboard,
139-
players: [SettingsWidgetScoreboardPlayer])
140-
{
139+
var body: some View {
141140
let scoreboard = padelScoreboardSettingsToEffect(padel, players)
142-
let scoreBoard = VStack(alignment: .leading, spacing: 0) {
141+
VStack(alignment: .leading, spacing: 0) {
143142
HStack(alignment: .center, spacing: 18) {
144143
VStack(alignment: .leading) {
145144
VStack(alignment: .leading) {
@@ -177,81 +176,12 @@ final class ScoreboardEffect: VideoEffect {
177176
}
178177
.clipShape(RoundedRectangle(cornerRadius: 5))
179178
.foregroundStyle(textColor)
180-
let renderer = ImageRenderer(content: scoreBoard)
181-
guard let image = renderer.uiImage else {
182-
return
183-
}
184-
setScoreboardImage(image: CIImage(image: image))
185-
}
186-
187-
@MainActor
188-
private func updateGeneric(textColor: Color,
189-
primaryBackgroundColor: Color,
190-
secondaryBackgroundColor: Color,
191-
generic: SettingsWidgetGenericScoreboard)
192-
{
193-
let scoreBoard = VStack(alignment: .leading, spacing: 0) {
194-
HStack {
195-
Text(generic.title)
196-
Spacer()
197-
Text(generic.clock.format())
198-
.monospacedDigit()
199-
.font(.system(size: 25))
200-
}
201-
.padding(5)
202-
.background(secondaryBackgroundColor)
203-
HStack(alignment: .center, spacing: 18) {
204-
VStack(alignment: .leading) {
205-
VStack(alignment: .leading) {
206-
Spacer(minLength: 0)
207-
Text(generic.home.uppercased())
208-
Spacer(minLength: 0)
209-
}
210-
VStack(alignment: .leading) {
211-
Spacer(minLength: 0)
212-
Text(generic.away.uppercased())
213-
Spacer(minLength: 0)
214-
}
215-
}
216-
.font(.system(size: 25))
217-
Spacer()
218-
VStack {
219-
TeamScoreView(score: generic.score.home)
220-
TeamScoreView(score: generic.score.away)
221-
}
222-
.frame(width: 28)
223-
.font(.system(size: 45))
224-
}
225-
.padding([.leading, .trailing], 5)
226-
.background(primaryBackgroundColor)
227-
PoweredByMoblinView(backgroundColor: secondaryBackgroundColor)
228-
}
229-
.clipShape(RoundedRectangle(cornerRadius: 5))
230-
.foregroundStyle(textColor)
231-
let renderer = ImageRenderer(content: scoreBoard)
232-
guard let image = renderer.uiImage else {
233-
return
234-
}
235-
setScoreboardImage(image: CIImage(image: image))
236179
}
180+
}
237181

238-
@MainActor
239-
private func updateModular(
240-
modular: SettingsWidgetModularScoreboard,
241-
config: RemoteControlScoreboardMatchConfig
242-
) {
243-
let content = VStack(alignment: .center, spacing: 0) {
244-
switch modular.layout {
245-
case .sideBySide:
246-
renderSideBySide(modular: modular, config: config)
247-
case .stackHistory:
248-
renderStackHistory(modular: modular, config: config)
249-
default:
250-
renderStacked(modular: modular, config: config)
251-
}
252-
}
253-
setScoreboardImage(image: ImageRenderer(content: content).ciImage())
254-
}
182+
private struct ModularScoreboardView: View {
183+
let modular: SettingsWidgetModularScoreboard
184+
let config: RemoteControlScoreboardMatchConfig
255185

256186
private func calculateMaxHistory(config: RemoteControlScoreboardMatchConfig) -> Int {
257187
var maxHistory = 0
@@ -673,7 +603,7 @@ final class ScoreboardEffect: VideoEffect {
673603
.opacity(0.25)
674604
.frame(width: width, height: height)
675605
}
676-
if let label = label, !label.isEmpty {
606+
if let label, !label.isEmpty {
677607
VStack(spacing: -2) {
678608
Text(label)
679609
.font(.system(size: size * 0.35, weight: .bold))
@@ -766,12 +696,114 @@ final class ScoreboardEffect: VideoEffect {
766696
}
767697

768698
private func renderTitleBlock(title: String, modular: SettingsWidgetModularScoreboard) -> some View {
769-
Text(title)
770-
.font(.system(size: modular.fontSize() * 0.7))
771-
.bold(modular.isBold)
772-
.foregroundStyle(.white)
773-
.padding(.vertical, 1)
774-
.frame(maxWidth: .infinity)
775-
.background(.black)
699+
HCenter {
700+
Text(title)
701+
.font(.system(size: modular.fontSize() * 0.7))
702+
.bold(modular.isBold)
703+
.foregroundStyle(.white)
704+
.padding(.vertical, 1)
705+
}
706+
.background(.black)
707+
}
708+
709+
var body: some View {
710+
VStack(spacing: 0) {
711+
switch modular.layout {
712+
case .sideBySide:
713+
renderSideBySide(modular: modular, config: config)
714+
case .stackHistory:
715+
renderStackHistory(modular: modular, config: config)
716+
default:
717+
renderStacked(modular: modular, config: config)
718+
}
719+
}
720+
}
721+
}
722+
723+
final class ScoreboardEffect: VideoEffect {
724+
private var scoreboardImage: CIImage?
725+
private var sceneWidget: SettingsSceneWidget?
726+
727+
func setSceneWidget(sceneWidget: SettingsSceneWidget) {
728+
processorPipelineQueue.async {
729+
self.sceneWidget = sceneWidget
730+
}
731+
}
732+
733+
@MainActor
734+
func update(scoreboard: SettingsWidgetScoreboard,
735+
config: RemoteControlScoreboardMatchConfig,
736+
players: [SettingsWidgetScoreboardPlayer])
737+
{
738+
switch scoreboard.sport {
739+
case .generic:
740+
updateGeneric(textColor: scoreboard.textColorColor,
741+
primaryBackgroundColor: scoreboard.primaryBackgroundColorColor,
742+
secondaryBackgroundColor: scoreboard.secondaryBackgroundColorColor,
743+
generic: scoreboard.generic)
744+
case .padel:
745+
updatePadel(textColor: scoreboard.textColorColor,
746+
primaryBackgroundColor: scoreboard.primaryBackgroundColorColor,
747+
secondaryBackgroundColor: scoreboard.secondaryBackgroundColorColor,
748+
padel: scoreboard.padel,
749+
players: players)
750+
default:
751+
updateModular(modular: scoreboard.modular, config: config)
752+
}
753+
}
754+
755+
override func execute(_ image: CIImage, _: VideoEffectInfo) -> CIImage {
756+
guard let scoreboardImage, let sceneWidget else {
757+
return image
758+
}
759+
let scale = image.extent.size.maximum() / 1920
760+
return scoreboardImage
761+
.scaled(x: scale, y: scale)
762+
.move(sceneWidget.layout, image.extent.size)
763+
.cropped(to: image.extent)
764+
.composited(over: image)
765+
}
766+
767+
private func setScoreboardImage(image: CIImage?) {
768+
processorPipelineQueue.async {
769+
self.scoreboardImage = image
770+
}
771+
}
772+
773+
@MainActor
774+
private func updateGeneric(textColor: Color,
775+
primaryBackgroundColor: Color,
776+
secondaryBackgroundColor: Color,
777+
generic: SettingsWidgetGenericScoreboard)
778+
{
779+
let scoreboard = GenericScoreboardView(textColor: textColor,
780+
primaryBackgroundColor: primaryBackgroundColor,
781+
secondaryBackgroundColor: secondaryBackgroundColor,
782+
generic: generic)
783+
setScoreboardImage(image: ImageRenderer(content: scoreboard).ciImage())
784+
}
785+
786+
@MainActor
787+
private func updatePadel(textColor: Color,
788+
primaryBackgroundColor: Color,
789+
secondaryBackgroundColor: Color,
790+
padel: SettingsWidgetPadelScoreboard,
791+
players: [SettingsWidgetScoreboardPlayer])
792+
{
793+
let scoreboard = PadelScoreboardView(textColor: textColor,
794+
primaryBackgroundColor: primaryBackgroundColor,
795+
secondaryBackgroundColor: secondaryBackgroundColor,
796+
padel: padel,
797+
players: players)
798+
setScoreboardImage(image: ImageRenderer(content: scoreboard).ciImage())
799+
}
800+
801+
@MainActor
802+
private func updateModular(
803+
modular: SettingsWidgetModularScoreboard,
804+
config: RemoteControlScoreboardMatchConfig
805+
) {
806+
let scoreboard = ModularScoreboardView(modular: modular, config: config)
807+
setScoreboardImage(image: ImageRenderer(content: scoreboard).ciImage())
776808
}
777809
}

0 commit comments

Comments
 (0)