mirror of
https://github.com/lichess-org/mobile.git
synced 2026-05-26 13:50:52 +00:00
Extract layout constants
This commit is contained in:
@@ -15,6 +15,7 @@ struct ChessPieceView: View {
|
||||
Image(assetName)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: squareSize * 0.9, height: squareSize * 0.9)
|
||||
.frame(width: squareSize * DailyPuzzleWidgetLayout.pieceSizeFactor,
|
||||
height: squareSize * DailyPuzzleWidgetLayout.pieceSizeFactor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import CoreGraphics
|
||||
|
||||
/// Layout constants shared across daily puzzle widget views.
|
||||
enum DailyPuzzleWidgetLayout {
|
||||
// Typography
|
||||
static let titleFontSize: CGFloat = 17
|
||||
static let metaFontSize: CGFloat = 14
|
||||
|
||||
// Header
|
||||
static let headerSpacing: CGFloat = 8
|
||||
static let headerBottomPadding: CGFloat = 5
|
||||
static let logoSize: CGFloat = 20
|
||||
|
||||
// Side-to-move indicator
|
||||
static let sideIndicatorSize: CGFloat = 14
|
||||
static let sideIndicatorBorderOpacity: CGFloat = 0.4
|
||||
static let sideIndicatorBorderWidth: CGFloat = 0.5
|
||||
|
||||
// Board — small
|
||||
static let smallBoardPadding: CGFloat = 8
|
||||
static let smallBoardCornerRadius: CGFloat = 12
|
||||
static let smallBoardBorderWidth: CGFloat = 1
|
||||
|
||||
// Board — large
|
||||
static let largeBoardCornerRadius: CGFloat = 6
|
||||
static let largeBoardBorderWidth: CGFloat = 1
|
||||
static let largeHorizontalPadding: CGFloat = 16
|
||||
static let largeTopPadding: CGFloat = 11
|
||||
|
||||
// Piece
|
||||
static let pieceSizeFactor: CGFloat = 0.9
|
||||
|
||||
// Error state
|
||||
static let errorIconSize: CGFloat = 20
|
||||
static let errorStackSpacing: CGFloat = 6
|
||||
}
|
||||
@@ -24,8 +24,12 @@ struct DailyPuzzleWidgetView: View {
|
||||
private var smallView: some View {
|
||||
VStack(spacing: 0) {
|
||||
boardView
|
||||
.roundedCornerWithBorder(lineWidth: 1, style: .tertiary, radius: 12)
|
||||
.padding(8)
|
||||
.roundedCornerWithBorder(
|
||||
lineWidth: DailyPuzzleWidgetLayout.smallBoardBorderWidth,
|
||||
style: .tertiary,
|
||||
radius: DailyPuzzleWidgetLayout.smallBoardCornerRadius
|
||||
)
|
||||
.padding(DailyPuzzleWidgetLayout.smallBoardPadding)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +39,15 @@ struct DailyPuzzleWidgetView: View {
|
||||
private var largeView: some View {
|
||||
GeometryReader { geo in
|
||||
VStack(spacing: 0) {
|
||||
HStack(spacing: 8) {
|
||||
HStack(spacing: DailyPuzzleWidgetLayout.headerSpacing) {
|
||||
Image("LichessLogo")
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)
|
||||
.frame(
|
||||
width: DailyPuzzleWidgetLayout.logoSize,
|
||||
height: DailyPuzzleWidgetLayout.logoSize
|
||||
)
|
||||
Text("Daily Puzzle")
|
||||
.font(.system(size: 17, weight: .semibold))
|
||||
.font(.system(size: DailyPuzzleWidgetLayout.titleFontSize, weight: .semibold))
|
||||
.foregroundStyle(.primary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -48,31 +55,43 @@ struct DailyPuzzleWidgetView: View {
|
||||
|
||||
if entry.showRating, let rating = entry.rating {
|
||||
Image(systemName: "chart.line.uptrend.xyaxis")
|
||||
.font(.system(size: 14))
|
||||
.font(.system(size: DailyPuzzleWidgetLayout.metaFontSize))
|
||||
.foregroundStyle(.secondary)
|
||||
Text("\(rating)")
|
||||
.font(.system(size: 14))
|
||||
.font(.system(size: DailyPuzzleWidgetLayout.metaFontSize))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Circle()
|
||||
.fill(entry.isWhiteToMove ? Color.white : Color.black)
|
||||
.overlay(Circle().stroke(Color.primary.opacity(0.4), lineWidth: 0.5))
|
||||
.frame(width: 14, height: 14)
|
||||
.overlay(
|
||||
Circle().stroke(
|
||||
Color.primary.opacity(DailyPuzzleWidgetLayout.sideIndicatorBorderOpacity),
|
||||
lineWidth: DailyPuzzleWidgetLayout.sideIndicatorBorderWidth
|
||||
)
|
||||
)
|
||||
.frame(
|
||||
width: DailyPuzzleWidgetLayout.sideIndicatorSize,
|
||||
height: DailyPuzzleWidgetLayout.sideIndicatorSize
|
||||
)
|
||||
|
||||
Text(entry.date.shortTime)
|
||||
.font(.system(size: 14))
|
||||
.font(.system(size: DailyPuzzleWidgetLayout.metaFontSize))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
.padding(.bottom, DailyPuzzleWidgetLayout.headerBottomPadding)
|
||||
|
||||
boardView
|
||||
.roundedCornerWithBorder(lineWidth: 1, style: .tertiary, radius: 6)
|
||||
.roundedCornerWithBorder(
|
||||
lineWidth: DailyPuzzleWidgetLayout.largeBoardBorderWidth,
|
||||
style: .tertiary,
|
||||
radius: DailyPuzzleWidgetLayout.largeBoardCornerRadius
|
||||
)
|
||||
.frame(width: geo.size.width, height: geo.size.width)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.top, 11)
|
||||
.padding(.horizontal, DailyPuzzleWidgetLayout.largeHorizontalPadding)
|
||||
.padding(.top, DailyPuzzleWidgetLayout.largeTopPadding)
|
||||
}
|
||||
|
||||
// MARK: - Reusable sub-views
|
||||
@@ -95,9 +114,9 @@ struct DailyPuzzleWidgetView: View {
|
||||
|
||||
@ViewBuilder
|
||||
private func errorView(_ message: String) -> some View {
|
||||
VStack(spacing: 6) {
|
||||
VStack(spacing: DailyPuzzleWidgetLayout.errorStackSpacing) {
|
||||
Image(systemName: "exclamationmark.circle")
|
||||
.font(.system(size: 20))
|
||||
.font(.system(size: DailyPuzzleWidgetLayout.errorIconSize))
|
||||
.foregroundStyle(.secondary)
|
||||
Text(message)
|
||||
.font(.caption)
|
||||
|
||||
Reference in New Issue
Block a user