@@ -26,18 +26,20 @@ struct BitwardenSegmentedControl<T: Menuable & Identifiable>: View {
26
26
var body : some View {
27
27
HStack ( spacing: 0 ) {
28
28
ForEach ( selections) { selection in
29
+ let isSelected = self . selection. id == selection. id
29
30
Button {
31
+ // Don't update the selection if this segment is already selected.
32
+ guard !isSelected else { return }
30
33
self . selection = selection
31
34
} label: {
32
- segmentView (
33
- title: selection. localizedName,
34
- isDisabled: isSelectionDisabled ( selection) ,
35
- isSelected: selection == self . selection
36
- )
37
- . matchedGeometryEffect ( id: selection, in: segmentedControl)
35
+ Text ( selection. localizedName)
36
+ . styleGuide ( . callout, weight: . semibold)
38
37
}
38
+ . accessibility ( if: isSelected, addTraits: . isSelected)
39
39
. accessibilityIdentifier ( selection. accessibilityId)
40
+ . buttonStyle ( SegmentButtonStyle ( isSelected: isSelected) )
40
41
. disabled ( isSelectionDisabled ( selection) )
42
+ . matchedGeometryEffect ( id: selection, in: segmentedControl)
41
43
}
42
44
}
43
45
. background (
@@ -70,36 +72,38 @@ struct BitwardenSegmentedControl<T: Menuable & Identifiable>: View {
70
72
_selection = selection
71
73
self . selections = selections
72
74
}
75
+ }
73
76
74
- // MARK: Private
77
+ // MARK: - SegmentButtonStyle
75
78
76
- /// Returns the foreground color for a segment.
77
- ///
78
- /// - Parameters:
79
- /// - isDisabled: Whether the segment is disabled.
80
- /// - isSelected: Whether the segment is selected.
81
- ///
82
- private func segmentForegroundColor( isDisabled: Bool , isSelected: Bool ) -> Color {
83
- guard !isDisabled else { return Asset . Colors. buttonFilledDisabledForeground. swiftUIColor }
79
+ /// A `ButtonStyle` for displaying a segment within the `BitwardenSegmentedControl`.
80
+ ///
81
+ private struct SegmentButtonStyle : ButtonStyle {
82
+ // MARK: Properties
83
+
84
+ @Environment ( \. isEnabled) var isEnabled : Bool
85
+
86
+ /// Whether the segment is selected.
87
+ let isSelected : Bool
88
+
89
+ /// The color of the foreground elements in the button.
90
+ var foregroundColor : Color {
91
+ guard isEnabled else { return Asset . Colors. buttonFilledDisabledForeground. swiftUIColor }
84
92
return isSelected ?
85
93
Asset . Colors. textInteraction. swiftUIColor :
86
94
Asset . Colors. textSecondary. swiftUIColor
87
95
}
88
96
89
- /// Returns a view for a single segment within the segmented control.
90
- ///
91
- /// - Parameters:
92
- /// - title: The title of the segment.
93
- /// - isDisabled: Whether the segment is disabled.
94
- /// - isSelected: Whether the segment is selected.
95
- ///
96
- private func segmentView( title: String , isDisabled: Bool , isSelected: Bool ) -> some View {
97
- Text ( title)
98
- . styleGuide ( . callout, weight: . semibold)
97
+ // MARK: ButtonStyle
98
+
99
+ func makeBody( configuration: Configuration ) -> some View {
100
+ configuration. label
99
101
. frame ( maxWidth: . infinity)
100
- . foregroundStyle ( segmentForegroundColor ( isDisabled : isDisabled , isSelected : isSelected ) )
102
+ . foregroundStyle ( foregroundColor )
101
103
. padding ( . vertical, 8 )
102
104
. dynamicTypeSize ( ... DynamicTypeSize . xxxLarge)
105
+ . opacity ( configuration. isPressed && !isSelected ? 0.5 : 1 )
106
+ . contentShape ( Capsule ( ) )
103
107
}
104
108
}
105
109
0 commit comments