Enforce minimum 2 grid columns on tvOS

This commit is contained in:
Arkadiusz Fal
2026-05-08 20:04:29 +02:00
parent 5b9cd8c521
commit f80ba26277
4 changed files with 22 additions and 13 deletions

View File

@@ -55,6 +55,15 @@ enum GridConstants {
/// Maximum allowed columns (to prevent excessive density). /// Maximum allowed columns (to prevent excessive density).
static let maxAllowedColumns = 6 static let maxAllowedColumns = 6
/// Minimum allowed columns. tvOS doesn't make sense with a single column.
static let minAllowedColumns: Int = {
#if os(tvOS)
2
#else
1
#endif
}()
/// Threshold for compact card styling (columns >= this use compact mode). /// Threshold for compact card styling (columns >= this use compact mode).
static let compactThreshold = 3 static let compactThreshold = 3
} }
@@ -74,14 +83,14 @@ func maxGridColumns(
// Formula: availableWidth = (columns * minCardWidth) + ((columns - 1) * spacing) // Formula: availableWidth = (columns * minCardWidth) + ((columns - 1) * spacing)
// Solving for columns: columns = (availableWidth + spacing) / (minCardWidth + spacing) // Solving for columns: columns = (availableWidth + spacing) / (minCardWidth + spacing)
let maxColumns = Int((availableWidth + spacing) / (minCardWidth + spacing)) let maxColumns = Int((availableWidth + spacing) / (minCardWidth + spacing))
return max(1, min(maxColumns, GridConstants.maxAllowedColumns)) return max(GridConstants.minAllowedColumns, min(maxColumns, GridConstants.maxAllowedColumns))
} }
/// Creates grid columns for a LazyVGrid with the specified count. /// Creates grid columns for a LazyVGrid with the specified count.
/// - Parameter count: Number of columns /// - Parameter count: Number of columns
/// - Returns: Array of flexible GridItems with top alignment /// - Returns: Array of flexible GridItems with top alignment
func makeGridColumns(count: Int) -> [GridItem] { func makeGridColumns(count: Int) -> [GridItem] {
Array(repeating: GridItem(.flexible(), spacing: GridConstants.spacing, alignment: .top), count: max(1, count)) Array(repeating: GridItem(.flexible(), spacing: GridConstants.spacing, alignment: .top), count: max(GridConstants.minAllowedColumns, count))
} }
// MARK: - Grid Layout Configuration // MARK: - Grid Layout Configuration
@@ -118,7 +127,7 @@ struct GridLayoutConfiguration {
/// Effective column count, clamped to valid range. /// Effective column count, clamped to valid range.
var effectiveColumns: Int { var effectiveColumns: Int {
min(max(1, gridColumns), max(1, maxColumns)) min(max(GridConstants.minAllowedColumns, gridColumns), max(GridConstants.minAllowedColumns, maxColumns))
} }
/// Whether cards should use compact styling (3+ columns). /// Whether cards should use compact styling (3+ columns).

View File

@@ -28,7 +28,7 @@ struct ViewOptionsSheet: View {
/// Effective columns clamped to valid range. /// Effective columns clamped to valid range.
private var effectiveColumns: Int { private var effectiveColumns: Int {
min(max(1, gridColumns), maxGridColumns) min(max(GridConstants.minAllowedColumns, gridColumns), max(GridConstants.minAllowedColumns, maxGridColumns))
} }
var body: some View { var body: some View {
@@ -64,7 +64,7 @@ struct ViewOptionsSheet: View {
if layout == .grid { if layout == .grid {
Picker("viewOptions.columns.header", selection: $gridColumns) { Picker("viewOptions.columns.header", selection: $gridColumns) {
ForEach(1...maxGridColumns, id: \.self) { count in ForEach(GridConstants.minAllowedColumns...max(GridConstants.minAllowedColumns, maxGridColumns), id: \.self) { count in
Text("\(count)").tag(count) Text("\(count)").tag(count)
} }
} }
@@ -123,7 +123,7 @@ struct ViewOptionsSheet: View {
if layout == .grid { if layout == .grid {
#if os(tvOS) #if os(tvOS)
Picker("viewOptions.columns.header", selection: $gridColumns) { Picker("viewOptions.columns.header", selection: $gridColumns) {
ForEach(1...maxGridColumns, id: \.self) { count in ForEach(GridConstants.minAllowedColumns...max(GridConstants.minAllowedColumns, maxGridColumns), id: \.self) { count in
Text("\(count)").tag(count) Text("\(count)").tag(count)
} }
} }
@@ -131,7 +131,7 @@ struct ViewOptionsSheet: View {
Stepper( Stepper(
"viewOptions.columns \(effectiveColumns)", "viewOptions.columns \(effectiveColumns)",
value: $gridColumns, value: $gridColumns,
in: 1...maxGridColumns in: GridConstants.minAllowedColumns...max(GridConstants.minAllowedColumns, maxGridColumns)
) )
#endif #endif
} }

View File

@@ -142,16 +142,16 @@ struct ManageChannelsView: View {
if layout == .grid { if layout == .grid {
#if os(tvOS) #if os(tvOS)
Picker("viewOptions.columns.header", selection: $gridColumns) { Picker("viewOptions.columns.header", selection: $gridColumns) {
ForEach(1...max(1, gridConfig.maxColumns), id: \.self) { count in ForEach(GridConstants.minAllowedColumns...max(GridConstants.minAllowedColumns, gridConfig.maxColumns), id: \.self) { count in
Text("\(count)").tag(count) Text("\(count)").tag(count)
} }
} }
.pickerStyle(.segmented) .pickerStyle(.segmented)
#else #else
Stepper( Stepper(
"viewOptions.columns \(min(max(1, gridColumns), gridConfig.maxColumns))", "viewOptions.columns \(min(max(GridConstants.minAllowedColumns, gridColumns), gridConfig.maxColumns))",
value: $gridColumns, value: $gridColumns,
in: 1...gridConfig.maxColumns in: GridConstants.minAllowedColumns...max(GridConstants.minAllowedColumns, gridConfig.maxColumns)
) )
#endif #endif
} }

View File

@@ -359,16 +359,16 @@ struct SubscriptionsView: View {
if layout == .grid { if layout == .grid {
#if os(tvOS) #if os(tvOS)
Picker("viewOptions.columns.header", selection: $gridColumns) { Picker("viewOptions.columns.header", selection: $gridColumns) {
ForEach(1...max(1, gridConfig.maxColumns), id: \.self) { count in ForEach(GridConstants.minAllowedColumns...max(GridConstants.minAllowedColumns, gridConfig.maxColumns), id: \.self) { count in
Text("\(count)").tag(count) Text("\(count)").tag(count)
} }
} }
.pickerStyle(.segmented) .pickerStyle(.segmented)
#else #else
Stepper( Stepper(
"viewOptions.columns \(min(max(1, gridColumns), gridConfig.maxColumns))", "viewOptions.columns \(min(max(GridConstants.minAllowedColumns, gridColumns), gridConfig.maxColumns))",
value: $gridColumns, value: $gridColumns,
in: 1...gridConfig.maxColumns in: GridConstants.minAllowedColumns...max(GridConstants.minAllowedColumns, gridConfig.maxColumns)
) )
#endif #endif
} }