From c6f10b852414128351f5eadb26c748b32af1d347 Mon Sep 17 00:00:00 2001 From: Aoife McLaughlin Date: Mon, 7 Oct 2024 12:50:56 +0100 Subject: [PATCH 1/6] create pagination buttons component --- .../Source/Components/PaginationButtons.swift | 40 +++++++++++++++++++ .../Components/PaginationProgressBar.swift | 29 +------------- 2 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 Sources/Source/Components/PaginationButtons.swift diff --git a/Sources/Source/Components/PaginationButtons.swift b/Sources/Source/Components/PaginationButtons.swift new file mode 100644 index 00000000..c342edb3 --- /dev/null +++ b/Sources/Source/Components/PaginationButtons.swift @@ -0,0 +1,40 @@ +import SwiftUI + +struct PaginationButtons: View { + let iconColor: Color + let borderColor: Color + @Binding var selectedIndex: Int + @Binding var canNavigateBack: Bool + @Binding var canNavigateForward: Bool + + var body: some View { + HStack { + IconButton( + icon: Image(.chevronLeft), + size: .small, + iconColor: iconColor, + borderColor: borderColor, + disabled: $canNavigateBack + ) { + withAnimation { + selectedIndex -= 1 + } + } + IconButton( + icon: Image(.chevronRight), + size: .small, + iconColor: iconColor, + borderColor: borderColor, + disabled: $canNavigateForward + ) { + withAnimation { + selectedIndex += 1 + } + } + } + } +} + +#Preview { + PaginationButtons(iconColor: .blue, borderColor: .red, selectedIndex: .constant(0), canNavigateBack: .constant(true), canNavigateForward: .constant(false)) +} diff --git a/Sources/Source/Components/PaginationProgressBar.swift b/Sources/Source/Components/PaginationProgressBar.swift index e5ab17ea..3c8df822 100644 --- a/Sources/Source/Components/PaginationProgressBar.swift +++ b/Sources/Source/Components/PaginationProgressBar.swift @@ -39,7 +39,7 @@ public struct PaginationProgressBar: View { ZStack(alignment: .trailing) { scrollingIndicator .frame(maxWidth: .infinity, alignment: .center) - progressButtons + PaginationButtons(iconColor: primaryColor, borderColor: secondaryColor, selectedIndex: $selectedIndex, canNavigateBack: $canNavigateBack, canNavigateForward: $canNavigateForward) .frame(alignment: .trailing) } } else { @@ -61,33 +61,6 @@ public struct PaginationProgressBar: View { ) } - private var progressButtons: some View { - HStack { - IconButton( - icon: Image(.chevronLeft), - size: .small, - iconColor: primaryColor, - borderColor: secondaryColor, - disabled: $canNavigateBack - ) { - withAnimation { - selectedIndex -= 1 - } - } - IconButton( - icon: Image(.chevronRight), - size: .small, - iconColor: primaryColor, - borderColor: secondaryColor, - disabled: $canNavigateForward - ) { - withAnimation { - selectedIndex += 1 - } - } - } - } - private func updateButtonDisabledState() { canNavigateBack = selectedIndex == 0 canNavigateForward = selectedIndex == pageCount - 1 From 7897a1e6acd0c02b8a8104d6e53dd0b9abdad1a8 Mon Sep 17 00:00:00 2001 From: Aoife McLaughlin Date: Mon, 7 Oct 2024 12:53:09 +0100 Subject: [PATCH 2/6] make public --- .../Source/Components/PaginationButtons.swift | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Sources/Source/Components/PaginationButtons.swift b/Sources/Source/Components/PaginationButtons.swift index c342edb3..b65a222b 100644 --- a/Sources/Source/Components/PaginationButtons.swift +++ b/Sources/Source/Components/PaginationButtons.swift @@ -1,13 +1,27 @@ import SwiftUI -struct PaginationButtons: View { +public struct PaginationButtons: View { let iconColor: Color let borderColor: Color @Binding var selectedIndex: Int @Binding var canNavigateBack: Bool @Binding var canNavigateForward: Bool - var body: some View { + public init( + iconColor: Color, + borderColor: Color, + selectedIndex: Binding, + canNavigateBack: Binding, + canNavigateForward: Binding + ) { + self.iconColor = iconColor + self.borderColor = borderColor + self._selectedIndex = selectedIndex + self._canNavigateBack = canNavigateBack + self._canNavigateForward = canNavigateForward + } + + public var body: some View { HStack { IconButton( icon: Image(.chevronLeft), From 16be37f855850eb957cd22545af3a05cd72a76bb Mon Sep 17 00:00:00 2001 From: Aoife McLaughlin Date: Mon, 7 Oct 2024 17:50:27 +0100 Subject: [PATCH 3/6] make buttons a bit more usable --- .../Source/Components/Buttons/IconButton.swift | 16 ++++++++-------- .../Source/Components/PaginationButtons.swift | 16 +++++++--------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/Sources/Source/Components/Buttons/IconButton.swift b/Sources/Source/Components/Buttons/IconButton.swift index 4787e24c..a50d0512 100644 --- a/Sources/Source/Components/Buttons/IconButton.swift +++ b/Sources/Source/Components/Buttons/IconButton.swift @@ -9,21 +9,21 @@ public struct IconButton: View { private let iconColor: Color private let borderColor: Color private let action: () -> () - @Binding private var disabled: Bool + private var disabled: Bool public init( icon: Image, size: ButtonSize, iconColor: Color, borderColor: Color, - disabled: Binding = .constant(false), + disabled: Bool = false, action: @escaping () -> Void ) { self.icon = icon self.size = size self.iconColor = iconColor self.borderColor = borderColor - self._disabled = disabled + self.disabled = disabled self.action = action } @@ -35,7 +35,7 @@ public struct IconButton: View { icon .resizable() } - .buttonStyle(IconButtonStyle(size: size, isDisabled: $disabled, borderColor: borderColor, iconColor: iconColor)) + .buttonStyle(IconButtonStyle(size: size, isDisabled: disabled, borderColor: borderColor, iconColor: iconColor)) } } @@ -45,16 +45,16 @@ public struct IconButton: View { /// Custom disabled functionality has been used here, rather than the native to ensure the styling of the button in the disabled state is correctly reflected and that no touch events are passed through to the view behind. struct IconButtonStyle: ButtonStyle { let size: ButtonSize - @Binding private var isDisabled: Bool + private var isDisabled: Bool let borderColor: Color let iconColor: Color @Environment(\.colorScheme) private var colorScheme - init(size: ButtonSize, isDisabled: Binding = .constant(false), borderColor: Color, iconColor: Color) { + init(size: ButtonSize, isDisabled: Bool = false, borderColor: Color, iconColor: Color) { self.size = size - self._isDisabled = isDisabled + self.isDisabled = isDisabled self.borderColor = borderColor self.iconColor = iconColor } @@ -82,7 +82,7 @@ struct IconButtonStyle: ButtonStyle { } #Preview { - IconButton(icon: Image(.chevronLeft), size: .small, iconColor: .black, borderColor: .gray, disabled: .constant(false), action: {}) + IconButton(icon: Image(.chevronLeft), size: .small, iconColor: .black, borderColor: .gray, disabled: false, action: {}) } // Maps button size to layout values for icon. diff --git a/Sources/Source/Components/PaginationButtons.swift b/Sources/Source/Components/PaginationButtons.swift index b65a222b..c6380160 100644 --- a/Sources/Source/Components/PaginationButtons.swift +++ b/Sources/Source/Components/PaginationButtons.swift @@ -4,21 +4,19 @@ public struct PaginationButtons: View { let iconColor: Color let borderColor: Color @Binding var selectedIndex: Int - @Binding var canNavigateBack: Bool - @Binding var canNavigateForward: Bool + let pageCount: Int + public init( iconColor: Color, borderColor: Color, selectedIndex: Binding, - canNavigateBack: Binding, - canNavigateForward: Binding + pageCount: Int ) { self.iconColor = iconColor self.borderColor = borderColor self._selectedIndex = selectedIndex - self._canNavigateBack = canNavigateBack - self._canNavigateForward = canNavigateForward + self.pageCount = pageCount } public var body: some View { @@ -28,7 +26,7 @@ public struct PaginationButtons: View { size: .small, iconColor: iconColor, borderColor: borderColor, - disabled: $canNavigateBack + disabled: selectedIndex > 0 ) { withAnimation { selectedIndex -= 1 @@ -39,7 +37,7 @@ public struct PaginationButtons: View { size: .small, iconColor: iconColor, borderColor: borderColor, - disabled: $canNavigateForward + disabled: selectedIndex < pageCount ) { withAnimation { selectedIndex += 1 @@ -50,5 +48,5 @@ public struct PaginationButtons: View { } #Preview { - PaginationButtons(iconColor: .blue, borderColor: .red, selectedIndex: .constant(0), canNavigateBack: .constant(true), canNavigateForward: .constant(false)) + PaginationButtons(iconColor: .blue, borderColor: .red, selectedIndex: .constant(0), pageCount: 10) } From 2dedb0bbe6f9d553883190c0df615e3a535dec78 Mon Sep 17 00:00:00 2001 From: Aoife McLaughlin Date: Mon, 7 Oct 2024 17:57:48 +0100 Subject: [PATCH 4/6] update optionality of selected index --- .../Source/Components/PaginationButtons.swift | 26 ++++++++++++++----- .../Components/PaginationProgressBar.swift | 9 +++---- .../ScrollingPaginationIndicator.swift | 8 +++--- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Sources/Source/Components/PaginationButtons.swift b/Sources/Source/Components/PaginationButtons.swift index c6380160..f8023554 100644 --- a/Sources/Source/Components/PaginationButtons.swift +++ b/Sources/Source/Components/PaginationButtons.swift @@ -3,14 +3,14 @@ import SwiftUI public struct PaginationButtons: View { let iconColor: Color let borderColor: Color - @Binding var selectedIndex: Int + @Binding var selectedIndex: Int? let pageCount: Int public init( iconColor: Color, borderColor: Color, - selectedIndex: Binding, + selectedIndex: Binding, pageCount: Int ) { self.iconColor = iconColor @@ -19,6 +19,16 @@ public struct PaginationButtons: View { self.pageCount = pageCount } + private var backDisabled: Bool { + guard let selectedIndex else { return true } + return selectedIndex > 0 + } + + private var forwardDisabled: Bool { + guard let selectedIndex else { return true } + return selectedIndex < pageCount + } + public var body: some View { HStack { IconButton( @@ -26,10 +36,12 @@ public struct PaginationButtons: View { size: .small, iconColor: iconColor, borderColor: borderColor, - disabled: selectedIndex > 0 + disabled: backDisabled ) { withAnimation { - selectedIndex -= 1 + if let selectedIndex { + self.selectedIndex = selectedIndex - 1 + } } } IconButton( @@ -37,10 +49,12 @@ public struct PaginationButtons: View { size: .small, iconColor: iconColor, borderColor: borderColor, - disabled: selectedIndex < pageCount + disabled: forwardDisabled ) { withAnimation { - selectedIndex += 1 + if let selectedIndex { + self.selectedIndex = selectedIndex + 1 + } } } } diff --git a/Sources/Source/Components/PaginationProgressBar.swift b/Sources/Source/Components/PaginationProgressBar.swift index 3c8df822..941adfb4 100644 --- a/Sources/Source/Components/PaginationProgressBar.swift +++ b/Sources/Source/Components/PaginationProgressBar.swift @@ -1,5 +1,4 @@ import SwiftUI -import Source /// This component used to signpost progression through a paginated view. /// @@ -8,7 +7,7 @@ public struct PaginationProgressBar: View { private let pageCount: Int private let indicatorWidth: CGFloat - @Binding private var selectedIndex: Int + @Binding private var selectedIndex: Int? private let primaryColor: Color private let secondaryColor: Color @@ -22,7 +21,7 @@ public struct PaginationProgressBar: View { public init( pageCount: Int, indicatorWidth: CGFloat, - selectedIndex: Binding, + selectedIndex: Binding, primaryColor: Color, secondaryColor: Color ) { @@ -39,7 +38,7 @@ public struct PaginationProgressBar: View { ZStack(alignment: .trailing) { scrollingIndicator .frame(maxWidth: .infinity, alignment: .center) - PaginationButtons(iconColor: primaryColor, borderColor: secondaryColor, selectedIndex: $selectedIndex, canNavigateBack: $canNavigateBack, canNavigateForward: $canNavigateForward) + PaginationButtons(iconColor: primaryColor, borderColor: secondaryColor, selectedIndex: $selectedIndex, pageCount: pageCount) .frame(alignment: .trailing) } } else { @@ -69,7 +68,7 @@ public struct PaginationProgressBar: View { struct PaginationProgressBar_Previews_Container: PreviewProvider { struct Container: View { - @State var selectedIndex = 0 + @State var selectedIndex: Int? = 0 let elementArray = [0, 1, 2, 3, 4, 5, 6] var body: some View { VStack { diff --git a/Sources/Source/Components/ScrollingPaginationIndicator.swift b/Sources/Source/Components/ScrollingPaginationIndicator.swift index 3fbae0a5..baf60699 100644 --- a/Sources/Source/Components/ScrollingPaginationIndicator.swift +++ b/Sources/Source/Components/ScrollingPaginationIndicator.swift @@ -6,7 +6,7 @@ import SwiftUI public struct ScrollingPaginationIndicator: View { private let pageCount: Int - @Binding private var selectedIndex: Int + @Binding private var selectedIndex: Int? private let numberOfVisibleDots: Int private let spacing: CGFloat private let indicatorWidth: CGFloat @@ -34,7 +34,7 @@ public struct ScrollingPaginationIndicator: View { numberOfVisibleDots: Int = 5, indicatorWidth: CGFloat, spacing: CGFloat = 4, - selectedIndex: Binding, + selectedIndex: Binding, primaryColor: Color, secondaryColor: Color ) { @@ -56,7 +56,7 @@ public struct ScrollingPaginationIndicator: View { /// - Parameter index: The index of the item for which the scale factor is to be calculated. /// - Returns: A `CGFloat` value representing the scale factor for the item at the given index. private func scale(for index: Int) -> CGFloat { - guard pageCount >= numberOfVisibleDots else { return 1.0 } + guard pageCount >= numberOfVisibleDots, let selectedIndex else { return 1.0 } let indexDifference = abs(index - selectedIndex) let scaleSpread = max((CGFloat(numberOfVisibleDots - 1) / 2 + 1), 1) let scaleFactor = CGFloat(indexDifference) / scaleSpread @@ -90,7 +90,7 @@ public struct ScrollingPaginationIndicator: View { struct ScrollingPageIndicator_Previews_Container: PreviewProvider { struct Container: View { - @State var selectedIndex = 0 + @State var selectedIndex: Int? = 0 let elementArray = [0, 1, 2, 3, 4, 5, 6, 7, 8] var body: some View { VStack { From ade58ad8a662ea54819f7e0ab1059ee2e66afef1 Mon Sep 17 00:00:00 2001 From: Aoife McLaughlin Date: Mon, 7 Oct 2024 18:02:54 +0100 Subject: [PATCH 5/6] fix up logic --- Sources/Source/Components/PaginationButtons.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Source/Components/PaginationButtons.swift b/Sources/Source/Components/PaginationButtons.swift index f8023554..8836efe9 100644 --- a/Sources/Source/Components/PaginationButtons.swift +++ b/Sources/Source/Components/PaginationButtons.swift @@ -21,12 +21,12 @@ public struct PaginationButtons: View { private var backDisabled: Bool { guard let selectedIndex else { return true } - return selectedIndex > 0 + return selectedIndex == 0 } private var forwardDisabled: Bool { guard let selectedIndex else { return true } - return selectedIndex < pageCount + return selectedIndex >= pageCount - 1 } public var body: some View { From 6dbe27dfe4bcb7092eb29dd8a60d6f3c987e7ccb Mon Sep 17 00:00:00 2001 From: Aoife McLaughlin Date: Tue, 8 Oct 2024 11:20:04 +0100 Subject: [PATCH 6/6] PR feedback --- Sources/Source/Components/Buttons/IconButton.swift | 9 ++++----- Sources/Source/Components/PaginationButtons.swift | 1 - Sources/Source/Components/PaginationProgressBar.swift | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Sources/Source/Components/Buttons/IconButton.swift b/Sources/Source/Components/Buttons/IconButton.swift index a50d0512..fc985767 100644 --- a/Sources/Source/Components/Buttons/IconButton.swift +++ b/Sources/Source/Components/Buttons/IconButton.swift @@ -36,7 +36,6 @@ public struct IconButton: View { .resizable() } .buttonStyle(IconButtonStyle(size: size, isDisabled: disabled, borderColor: borderColor, iconColor: iconColor)) - } } @@ -44,10 +43,10 @@ public struct IconButton: View { /// /// Custom disabled functionality has been used here, rather than the native to ensure the styling of the button in the disabled state is correctly reflected and that no touch events are passed through to the view behind. struct IconButtonStyle: ButtonStyle { - let size: ButtonSize - private var isDisabled: Bool - let borderColor: Color - let iconColor: Color + private let size: ButtonSize + private let isDisabled: Bool + private let borderColor: Color + private let iconColor: Color @Environment(\.colorScheme) private var colorScheme diff --git a/Sources/Source/Components/PaginationButtons.swift b/Sources/Source/Components/PaginationButtons.swift index 8836efe9..965d6af5 100644 --- a/Sources/Source/Components/PaginationButtons.swift +++ b/Sources/Source/Components/PaginationButtons.swift @@ -6,7 +6,6 @@ public struct PaginationButtons: View { @Binding var selectedIndex: Int? let pageCount: Int - public init( iconColor: Color, borderColor: Color, diff --git a/Sources/Source/Components/PaginationProgressBar.swift b/Sources/Source/Components/PaginationProgressBar.swift index 941adfb4..04287fb9 100644 --- a/Sources/Source/Components/PaginationProgressBar.swift +++ b/Sources/Source/Components/PaginationProgressBar.swift @@ -7,10 +7,10 @@ public struct PaginationProgressBar: View { private let pageCount: Int private let indicatorWidth: CGFloat - @Binding private var selectedIndex: Int? private let primaryColor: Color private let secondaryColor: Color + @Binding private var selectedIndex: Int? @Environment(\.horizontalSizeClass) private var sizeClass