Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
7913cb2d45
commit
2b7b770d3a
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Bucket
|
||||||
|
uuid = "88E73C19-3668-4217-9B1F-56B52ACBA7E0"
|
||||||
|
type = "1"
|
||||||
|
version = "2.0">
|
||||||
|
<Breakpoints>
|
||||||
|
<BreakpointProxy
|
||||||
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
|
<BreakpointContent
|
||||||
|
uuid = "B46496BF-3442-4357-9248-38B07C7AB65D"
|
||||||
|
shouldBeEnabled = "No"
|
||||||
|
ignoreCount = "0"
|
||||||
|
continueAfterRunningActions = "No"
|
||||||
|
filePath = "Baccarat/Views/GameTableView.swift"
|
||||||
|
startingColumnNumber = "9223372036854775807"
|
||||||
|
endingColumnNumber = "9223372036854775807"
|
||||||
|
startingLineNumber = "68"
|
||||||
|
endingLineNumber = "68"
|
||||||
|
landmarkName = "body"
|
||||||
|
landmarkType = "24">
|
||||||
|
</BreakpointContent>
|
||||||
|
</BreakpointProxy>
|
||||||
|
</Breakpoints>
|
||||||
|
</Bucket>
|
||||||
@ -143,6 +143,7 @@
|
|||||||
},
|
},
|
||||||
"BALANCE" : {
|
"BALANCE" : {
|
||||||
"comment" : "The label for the user's balance in the top bar.",
|
"comment" : "The label for the user's balance in the top bar.",
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"es" : {
|
"es" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
|
|||||||
@ -290,9 +290,10 @@ struct CardsDisplayArea: View {
|
|||||||
let bankerIsWinner: Bool
|
let bankerIsWinner: Bool
|
||||||
let isTie: Bool
|
let isTie: Bool
|
||||||
|
|
||||||
// MARK: - Scaled Font Sizes (Dynamic Type)
|
// MARK: - Fixed font sizes for card area
|
||||||
|
// Fixed because the card display has strict layout constraints
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .headline) private var labelFontSize: CGFloat = 14
|
private let labelFontSize: CGFloat = 14
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: Design.Spacing.xxxLarge) {
|
HStack(spacing: Design.Spacing.xxxLarge) {
|
||||||
@ -482,36 +483,42 @@ struct TopBarView: View {
|
|||||||
let onReset: () -> Void
|
let onReset: () -> Void
|
||||||
let onSettings: () -> Void
|
let onSettings: () -> Void
|
||||||
|
|
||||||
// MARK: - Scaled Font Sizes (Dynamic Type)
|
// MARK: - Environment
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .caption2) private var labelFontSize: CGFloat = 9
|
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
|
||||||
@ScaledMetric(relativeTo: .body) private var currencyFontSize: CGFloat = 14
|
|
||||||
@ScaledMetric(relativeTo: .title3) private var balanceFontSize: CGFloat = 20
|
/// Whether the current text size is an accessibility size (very large)
|
||||||
@ScaledMetric(relativeTo: .caption) private var smallFontSize: CGFloat = 12
|
private var isAccessibilitySize: Bool {
|
||||||
@ScaledMetric(relativeTo: .body) private var buttonFontSize: CGFloat = 16
|
dynamicTypeSize.isAccessibilitySize
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Fixed font sizes for constrained top bar
|
||||||
|
// These use fixed sizes because the top bar has strict space constraints
|
||||||
|
// and must remain readable at all accessibility settings
|
||||||
|
|
||||||
|
private let labelFontSize: CGFloat = 9
|
||||||
|
private let currencyFontSize: CGFloat = 14
|
||||||
|
private let balanceFontSize: CGFloat = 20
|
||||||
|
private let smallFontSize: CGFloat = 12
|
||||||
|
private let buttonFontSize: CGFloat = 16
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
// Balance display
|
// Balance display - simplified at accessibility sizes
|
||||||
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
|
HStack(spacing: Design.Spacing.xSmall) {
|
||||||
Text("BALANCE")
|
Text("$")
|
||||||
.font(.system(size: labelFontSize, weight: .medium, design: .rounded))
|
.font(.system(size: currencyFontSize, weight: .bold))
|
||||||
.foregroundStyle(.white.opacity(0.6))
|
.foregroundStyle(.yellow.opacity(0.8))
|
||||||
.tracking(1)
|
|
||||||
|
|
||||||
HStack(spacing: Design.Spacing.xSmall) {
|
Text(balance, format: .number)
|
||||||
Text("$")
|
.font(.system(size: balanceFontSize, weight: .black, design: .rounded))
|
||||||
.font(.system(size: currencyFontSize, weight: .bold))
|
.foregroundStyle(.white)
|
||||||
.foregroundStyle(.yellow.opacity(0.8))
|
.contentTransition(.numericText())
|
||||||
|
.animation(.spring(duration: Design.Animation.quick), value: balance)
|
||||||
Text(balance, format: .number)
|
.lineLimit(1)
|
||||||
.font(.system(size: balanceFontSize, weight: .black, design: .rounded))
|
.minimumScaleFactor(0.5)
|
||||||
.foregroundStyle(.white)
|
|
||||||
.contentTransition(.numericText())
|
|
||||||
.animation(.spring(duration: Design.Animation.quick), value: balance)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.padding(.horizontal, Design.Spacing.xLarge)
|
.padding(.horizontal, Design.Spacing.medium)
|
||||||
.padding(.vertical, Design.Spacing.xSmall)
|
.padding(.vertical, Design.Spacing.xSmall)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
@ -520,8 +527,8 @@ struct TopBarView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
// Cards remaining indicator (if enabled)
|
// Cards remaining indicator - hidden at accessibility sizes to save space
|
||||||
if showCardsRemaining {
|
if showCardsRemaining && !isAccessibilitySize {
|
||||||
HStack(spacing: Design.Spacing.xSmall) {
|
HStack(spacing: Design.Spacing.xSmall) {
|
||||||
Image(systemName: "rectangle.portrait.on.rectangle.portrait.fill")
|
Image(systemName: "rectangle.portrait.on.rectangle.portrait.fill")
|
||||||
.font(.system(size: smallFontSize))
|
.font(.system(size: smallFontSize))
|
||||||
@ -533,7 +540,7 @@ struct TopBarView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings button
|
// Settings button (icon only)
|
||||||
Button("Settings", systemImage: "gearshape.fill", action: onSettings)
|
Button("Settings", systemImage: "gearshape.fill", action: onSettings)
|
||||||
.labelStyle(.iconOnly)
|
.labelStyle(.iconOnly)
|
||||||
.font(.system(size: buttonFontSize))
|
.font(.system(size: buttonFontSize))
|
||||||
@ -544,14 +551,14 @@ struct TopBarView: View {
|
|||||||
.fill(Color.black.opacity(Design.Opacity.overlay))
|
.fill(Color.black.opacity(Design.Opacity.overlay))
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reset button
|
// Reset button (icon only to save space)
|
||||||
Button("Reset", systemImage: "arrow.counterclockwise", action: onReset)
|
Button("Reset", systemImage: "arrow.counterclockwise", action: onReset)
|
||||||
.font(.system(size: smallFontSize, weight: .medium))
|
.labelStyle(.iconOnly)
|
||||||
|
.font(.system(size: buttonFontSize))
|
||||||
.foregroundStyle(.white.opacity(0.6))
|
.foregroundStyle(.white.opacity(0.6))
|
||||||
.padding(.horizontal, Design.Spacing.small)
|
.padding(Design.Spacing.small)
|
||||||
.padding(.vertical, Design.Spacing.xSmall)
|
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Circle()
|
||||||
.fill(Color.black.opacity(Design.Opacity.overlay))
|
.fill(Color.black.opacity(Design.Opacity.overlay))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -567,65 +574,33 @@ struct ActionButtonsView: View {
|
|||||||
let onClear: () -> Void
|
let onClear: () -> Void
|
||||||
let onNewRound: () -> Void
|
let onNewRound: () -> Void
|
||||||
|
|
||||||
// MARK: - Scaled Font Sizes (Dynamic Type)
|
// MARK: - Environment
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .body) private var clearButtonFontSize: CGFloat = 14
|
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
|
||||||
@ScaledMetric(relativeTo: .headline) private var primaryButtonFontSize: CGFloat = 16
|
|
||||||
@ScaledMetric(relativeTo: .body) private var statusFontSize: CGFloat = 14
|
/// Whether the current text size is an accessibility size (very large)
|
||||||
|
private var isAccessibilitySize: Bool {
|
||||||
|
dynamicTypeSize.isAccessibilitySize
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Fixed font sizes for action buttons
|
||||||
|
// Fixed because buttons have constrained space and must remain usable
|
||||||
|
|
||||||
|
private let buttonFontSize: CGFloat = 16
|
||||||
|
private let iconSize: CGFloat = 24
|
||||||
|
private let statusFontSize: CGFloat = 14
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: Design.Spacing.medium) {
|
HStack(spacing: Design.Spacing.medium) {
|
||||||
if gameState.currentPhase == .betting {
|
if gameState.currentPhase == .betting {
|
||||||
// Clear bets button
|
// Clear bets button - icon only at accessibility sizes
|
||||||
Button("Clear", systemImage: "xmark.circle", action: onClear)
|
clearButton
|
||||||
.font(.system(size: clearButtonFontSize, weight: .semibold))
|
|
||||||
.foregroundStyle(.white)
|
|
||||||
.padding(.horizontal, Design.Spacing.xLarge)
|
|
||||||
.padding(.vertical, Design.Spacing.medium)
|
|
||||||
.background(
|
|
||||||
Capsule()
|
|
||||||
.fill(Color.Button.destructive)
|
|
||||||
)
|
|
||||||
.opacity(gameState.currentBets.isEmpty ? Design.Opacity.disabled : 1.0)
|
|
||||||
.disabled(gameState.currentBets.isEmpty)
|
|
||||||
|
|
||||||
// Deal button
|
// Deal button - icon only at accessibility sizes
|
||||||
Button("Deal", systemImage: "play.fill", action: onDeal)
|
dealButton
|
||||||
.font(.system(size: primaryButtonFontSize, weight: .bold))
|
|
||||||
.foregroundStyle(.black)
|
|
||||||
.padding(.horizontal, Design.Spacing.xxxLarge)
|
|
||||||
.padding(.vertical, Design.Spacing.medium)
|
|
||||||
.background(
|
|
||||||
Capsule()
|
|
||||||
.fill(
|
|
||||||
LinearGradient(
|
|
||||||
colors: [Color.Button.goldLight, Color.Button.goldDark],
|
|
||||||
startPoint: .top,
|
|
||||||
endPoint: .bottom
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
|
|
||||||
.opacity(gameState.canDeal ? 1.0 : Design.Opacity.disabled)
|
|
||||||
.disabled(!gameState.canDeal)
|
|
||||||
} else if gameState.currentPhase == .roundComplete {
|
} else if gameState.currentPhase == .roundComplete {
|
||||||
// New round button
|
// New round button - icon only at accessibility sizes
|
||||||
Button("New Round", systemImage: "arrow.right.circle", action: onNewRound)
|
newRoundButton
|
||||||
.font(.system(size: primaryButtonFontSize, weight: .bold))
|
|
||||||
.foregroundStyle(.black)
|
|
||||||
.padding(.horizontal, Design.Spacing.xxxLarge)
|
|
||||||
.padding(.vertical, Design.Spacing.medium)
|
|
||||||
.background(
|
|
||||||
Capsule()
|
|
||||||
.fill(
|
|
||||||
LinearGradient(
|
|
||||||
colors: [Color.Button.goldLight, Color.Button.goldDark],
|
|
||||||
startPoint: .top,
|
|
||||||
endPoint: .bottom
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
|
|
||||||
} else {
|
} else {
|
||||||
// Playing indicator
|
// Playing indicator
|
||||||
HStack(spacing: Design.Spacing.xSmall) {
|
HStack(spacing: Design.Spacing.xSmall) {
|
||||||
@ -635,12 +610,128 @@ struct ActionButtonsView: View {
|
|||||||
Text("Dealing...")
|
Text("Dealing...")
|
||||||
.font(.system(size: statusFontSize, weight: .medium))
|
.font(.system(size: statusFontSize, weight: .medium))
|
||||||
.foregroundStyle(.white.opacity(Design.Opacity.heavy))
|
.foregroundStyle(.white.opacity(Design.Opacity.heavy))
|
||||||
|
.lineLimit(1)
|
||||||
|
.minimumScaleFactor(0.7)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, Design.Spacing.xLarge)
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
.padding(.vertical, Design.Spacing.medium)
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var clearButton: some View {
|
||||||
|
if isAccessibilitySize {
|
||||||
|
Button("Clear", systemImage: "xmark.circle", action: onClear)
|
||||||
|
.labelStyle(.iconOnly)
|
||||||
|
.font(.system(size: iconSize, weight: .semibold))
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.padding(Design.Spacing.medium)
|
||||||
|
.background(
|
||||||
|
Circle()
|
||||||
|
.fill(Color.Button.destructive)
|
||||||
|
)
|
||||||
|
.opacity(gameState.currentBets.isEmpty ? Design.Opacity.disabled : 1.0)
|
||||||
|
.disabled(gameState.currentBets.isEmpty)
|
||||||
|
} else {
|
||||||
|
Button("Clear", systemImage: "xmark.circle", action: onClear)
|
||||||
|
.labelStyle(.titleOnly)
|
||||||
|
.font(.system(size: buttonFontSize, weight: .semibold))
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
|
.background(
|
||||||
|
Capsule()
|
||||||
|
.fill(Color.Button.destructive)
|
||||||
|
)
|
||||||
|
.opacity(gameState.currentBets.isEmpty ? Design.Opacity.disabled : 1.0)
|
||||||
|
.disabled(gameState.currentBets.isEmpty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var dealButton: some View {
|
||||||
|
if isAccessibilitySize {
|
||||||
|
Button("Deal", systemImage: "play.fill", action: onDeal)
|
||||||
|
.labelStyle(.iconOnly)
|
||||||
|
.font(.system(size: iconSize, weight: .bold))
|
||||||
|
.foregroundStyle(.black)
|
||||||
|
.padding(Design.Spacing.medium)
|
||||||
|
.background(
|
||||||
|
Circle()
|
||||||
|
.fill(
|
||||||
|
LinearGradient(
|
||||||
|
colors: [Color.Button.goldLight, Color.Button.goldDark],
|
||||||
|
startPoint: .top,
|
||||||
|
endPoint: .bottom
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
|
||||||
|
.opacity(gameState.canDeal ? 1.0 : Design.Opacity.disabled)
|
||||||
|
.disabled(!gameState.canDeal)
|
||||||
|
} else {
|
||||||
|
Button("Deal", systemImage: "play.fill", action: onDeal)
|
||||||
|
.labelStyle(.titleOnly)
|
||||||
|
.font(.system(size: buttonFontSize, weight: .bold))
|
||||||
|
.foregroundStyle(.black)
|
||||||
|
.padding(.horizontal, Design.Spacing.xxxLarge)
|
||||||
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
|
.background(
|
||||||
|
Capsule()
|
||||||
|
.fill(
|
||||||
|
LinearGradient(
|
||||||
|
colors: [Color.Button.goldLight, Color.Button.goldDark],
|
||||||
|
startPoint: .top,
|
||||||
|
endPoint: .bottom
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
|
||||||
|
.opacity(gameState.canDeal ? 1.0 : Design.Opacity.disabled)
|
||||||
|
.disabled(!gameState.canDeal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var newRoundButton: some View {
|
||||||
|
if isAccessibilitySize {
|
||||||
|
Button("New Round", systemImage: "arrow.right.circle", action: onNewRound)
|
||||||
|
.labelStyle(.iconOnly)
|
||||||
|
.font(.system(size: iconSize, weight: .bold))
|
||||||
|
.foregroundStyle(.black)
|
||||||
|
.padding(Design.Spacing.medium)
|
||||||
|
.background(
|
||||||
|
Circle()
|
||||||
|
.fill(
|
||||||
|
LinearGradient(
|
||||||
|
colors: [Color.Button.goldLight, Color.Button.goldDark],
|
||||||
|
startPoint: .top,
|
||||||
|
endPoint: .bottom
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
|
||||||
|
} else {
|
||||||
|
Button("New Round", systemImage: "arrow.right.circle", action: onNewRound)
|
||||||
|
.labelStyle(.titleOnly)
|
||||||
|
.font(.system(size: buttonFontSize, weight: .bold))
|
||||||
|
.foregroundStyle(.black)
|
||||||
|
.padding(.horizontal, Design.Spacing.xxxLarge)
|
||||||
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
|
.background(
|
||||||
|
Capsule()
|
||||||
|
.fill(
|
||||||
|
LinearGradient(
|
||||||
|
colors: [Color.Button.goldLight, Color.Button.goldDark],
|
||||||
|
startPoint: .top,
|
||||||
|
endPoint: .bottom
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
|||||||
@ -12,9 +12,10 @@ struct MiniBaccaratTableView: View {
|
|||||||
@Bindable var gameState: GameState
|
@Bindable var gameState: GameState
|
||||||
let selectedChip: ChipDenomination
|
let selectedChip: ChipDenomination
|
||||||
|
|
||||||
// MARK: - Scaled Font Sizes (Dynamic Type)
|
// MARK: - Fixed Font Sizes
|
||||||
|
// Fixed because the table area has strict layout constraints
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .caption) private var tableLimitsFontSize: CGFloat = Design.BaseFontSize.small
|
private let tableLimitsFontSize: CGFloat = Design.BaseFontSize.small
|
||||||
|
|
||||||
// MARK: - Layout Constants
|
// MARK: - Layout Constants
|
||||||
|
|
||||||
@ -68,6 +69,8 @@ struct MiniBaccaratTableView: View {
|
|||||||
.font(.system(size: tableLimitsFontSize, weight: .bold, design: .rounded))
|
.font(.system(size: tableLimitsFontSize, weight: .bold, design: .rounded))
|
||||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||||
.tracking(1)
|
.tracking(1)
|
||||||
|
.lineLimit(1)
|
||||||
|
.minimumScaleFactor(0.6)
|
||||||
|
|
||||||
ZStack {
|
ZStack {
|
||||||
// Table felt background with arc shape
|
// Table felt background with arc shape
|
||||||
@ -201,10 +204,11 @@ struct TieBettingZone: View {
|
|||||||
var isAtMax: Bool = false
|
var isAtMax: Bool = false
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
|
||||||
// MARK: - Scaled Font Sizes (Dynamic Type)
|
// MARK: - Fixed Font Sizes
|
||||||
|
// Fixed because betting zones have strict space constraints
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .headline) private var titleFontSize: CGFloat = Design.BaseFontSize.medium
|
private let titleFontSize: CGFloat = Design.BaseFontSize.medium
|
||||||
@ScaledMetric(relativeTo: .caption2) private var subtitleFontSize: CGFloat = Design.BaseFontSize.xSmall
|
private let subtitleFontSize: CGFloat = Design.BaseFontSize.xSmall
|
||||||
|
|
||||||
// MARK: - Layout Constants
|
// MARK: - Layout Constants
|
||||||
|
|
||||||
@ -243,10 +247,14 @@ struct TieBettingZone: View {
|
|||||||
Text("TIE")
|
Text("TIE")
|
||||||
.font(.system(size: titleFontSize, weight: .black, design: .rounded))
|
.font(.system(size: titleFontSize, weight: .black, design: .rounded))
|
||||||
.tracking(2)
|
.tracking(2)
|
||||||
|
.lineLimit(1)
|
||||||
|
.minimumScaleFactor(0.5)
|
||||||
|
|
||||||
Text("PAYS 8 TO 1")
|
Text("PAYS 8 TO 1")
|
||||||
.font(.system(size: subtitleFontSize, weight: .medium))
|
.font(.system(size: subtitleFontSize, weight: .medium))
|
||||||
.opacity(Design.Opacity.heavy)
|
.opacity(Design.Opacity.heavy)
|
||||||
|
.lineLimit(1)
|
||||||
|
.minimumScaleFactor(0.5)
|
||||||
}
|
}
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
}
|
}
|
||||||
@ -270,10 +278,11 @@ struct BankerBettingZone: View {
|
|||||||
var isAtMax: Bool = false
|
var isAtMax: Bool = false
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
|
||||||
// MARK: - Scaled Font Sizes (Dynamic Type)
|
// MARK: - Fixed Font Sizes
|
||||||
|
// Fixed because betting zones have strict space constraints
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .headline) private var titleFontSize: CGFloat = Design.BaseFontSize.large
|
private let titleFontSize: CGFloat = Design.BaseFontSize.large
|
||||||
@ScaledMetric(relativeTo: .caption2) private var subtitleFontSize: CGFloat = Design.BaseFontSize.xSmall
|
private let subtitleFontSize: CGFloat = Design.BaseFontSize.xSmall
|
||||||
|
|
||||||
// MARK: - Layout Constants
|
// MARK: - Layout Constants
|
||||||
|
|
||||||
@ -328,10 +337,14 @@ struct BankerBettingZone: View {
|
|||||||
Text("BANKER")
|
Text("BANKER")
|
||||||
.font(.system(size: titleFontSize, weight: .black, design: .rounded))
|
.font(.system(size: titleFontSize, weight: .black, design: .rounded))
|
||||||
.tracking(3)
|
.tracking(3)
|
||||||
|
.lineLimit(1)
|
||||||
|
.minimumScaleFactor(0.5)
|
||||||
|
|
||||||
Text("PAYS 0.95 TO 1")
|
Text("PAYS 0.95 TO 1")
|
||||||
.font(.system(size: subtitleFontSize, weight: .medium))
|
.font(.system(size: subtitleFontSize, weight: .medium))
|
||||||
.opacity(Design.Opacity.heavy)
|
.opacity(Design.Opacity.heavy)
|
||||||
|
.lineLimit(1)
|
||||||
|
.minimumScaleFactor(0.5)
|
||||||
}
|
}
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
}
|
}
|
||||||
@ -355,10 +368,11 @@ struct PlayerBettingZone: View {
|
|||||||
var isAtMax: Bool = false
|
var isAtMax: Bool = false
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
|
||||||
// MARK: - Scaled Font Sizes (Dynamic Type)
|
// MARK: - Fixed Font Sizes
|
||||||
|
// Fixed because betting zones have strict space constraints
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .headline) private var titleFontSize: CGFloat = Design.BaseFontSize.large
|
private let titleFontSize: CGFloat = Design.BaseFontSize.large
|
||||||
@ScaledMetric(relativeTo: .caption2) private var subtitleFontSize: CGFloat = Design.BaseFontSize.xSmall
|
private let subtitleFontSize: CGFloat = Design.BaseFontSize.xSmall
|
||||||
|
|
||||||
// MARK: - Layout Constants
|
// MARK: - Layout Constants
|
||||||
|
|
||||||
@ -413,10 +427,14 @@ struct PlayerBettingZone: View {
|
|||||||
Text("PLAYER")
|
Text("PLAYER")
|
||||||
.font(.system(size: titleFontSize, weight: .black, design: .rounded))
|
.font(.system(size: titleFontSize, weight: .black, design: .rounded))
|
||||||
.tracking(3)
|
.tracking(3)
|
||||||
|
.lineLimit(1)
|
||||||
|
.minimumScaleFactor(0.5)
|
||||||
|
|
||||||
Text("PAYS 1 TO 1")
|
Text("PAYS 1 TO 1")
|
||||||
.font(.system(size: subtitleFontSize, weight: .medium))
|
.font(.system(size: subtitleFontSize, weight: .medium))
|
||||||
.opacity(Design.Opacity.heavy)
|
.opacity(Design.Opacity.heavy)
|
||||||
|
.lineLimit(1)
|
||||||
|
.minimumScaleFactor(0.5)
|
||||||
}
|
}
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user