Skip to content

Commit 9d6165d

Browse files
authored
Merge pull request #112 from patANZx/fix/vexillographer-nested-flags
2 parents 6b8a039 + 3990c06 commit 9d6165d

File tree

9 files changed

+150
-109
lines changed

9 files changed

+150
-109
lines changed

.github/workflows/ios-tests.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ jobs:
7575
- name: Checkout
7676
uses: actions/checkout@v2
7777
- name: Build and Test
78-
run: swift package generate-xcodeproj && xcrun xcodebuild test -scheme "Vexil-Package" -destination "platform=iOS Simulator,name=iPhone 8"
78+
run: |
79+
DEVICE_ID=`xcrun simctl list --json devices available iPhone | jq -r '.devices | to_entries | map(select(.value | add)) | sort_by(.key) | last.value | first.udid'`
80+
swift package generate-xcodeproj
81+
xcrun xcodebuild test -scheme "Vexil-Package" -destination "platform=iOS Simulator,id=$DEVICE_ID"
7982
8083
build-ios-macos-12:
8184
runs-on: ubuntu-latest

Sources/Vexil/Sources/UserDefaults+FlagValueSource.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ extension UserDefaults: FlagValueSource {
4646
return
4747
}
4848

49-
set(value.boxedFlagValue.object, forKey: key)
49+
if value.boxedFlagValue.object == NSNull() {
50+
set(Data(), forKey: key)
51+
} else {
52+
set(value.boxedFlagValue.object, forKey: key)
53+
}
5054

5155
}
5256

Sources/Vexillographer/Flag Value Controls/CaseIterableFlagControl.swift

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ struct CaseIterableFlagControl<Value>: View where Value: FlagValue, Value: CaseI
3434
@Binding
3535
var showDetail: Bool
3636

37-
@Binding
38-
var showPicker: Bool
39-
4037
// MARK: - View Body
4138

4239
var content: some View {
@@ -52,7 +49,7 @@ struct CaseIterableFlagControl<Value>: View where Value: FlagValue, Value: CaseI
5249
var body: some View {
5350
HStack {
5451
if self.isEditable {
55-
NavigationLink(destination: self.selector, isActive: self.$showPicker) {
52+
NavigationLink(destination: self.selector) {
5653
self.content
5754
}
5855
} else {
@@ -63,7 +60,7 @@ struct CaseIterableFlagControl<Value>: View where Value: FlagValue, Value: CaseI
6360
}
6461

6562
var selector: some View {
66-
return self.selectorList
63+
SelectorList(value: self.$value)
6764
.navigationBarTitle(Text(self.label), displayMode: .inline)
6865
}
6966

@@ -104,60 +101,66 @@ struct CaseIterableFlagControl<Value>: View where Value: FlagValue, Value: CaseI
104101

105102
#endif
106103

107-
var selectorList: some View {
108-
Form {
109-
ForEach(Value.allCases, id: \.self) { value in
110-
Button(
111-
action: {
112-
self.value = value
113-
self.showPicker = false
114-
},
115-
label: {
116-
HStack {
117-
FlagDisplayValueView(value: value)
118-
.foregroundColor(.primary)
119-
Spacer()
120-
121-
if value == self.value {
122-
self.checkmark
104+
struct SelectorList: View {
105+
@Binding
106+
var value: Value
107+
108+
@Environment(\.presentationMode)
109+
private var presentationMode
110+
111+
var body: some View {
112+
Form {
113+
ForEach(Value.allCases, id: \.self) { value in
114+
Button(
115+
action: {
116+
self.value = value
117+
self.presentationMode.wrappedValue.dismiss()
118+
},
119+
label: {
120+
HStack {
121+
FlagDisplayValueView(value: value)
122+
.foregroundColor(.primary)
123+
Spacer()
124+
125+
if value == self.value {
126+
self.checkmark
127+
}
123128
}
124129
}
125-
}
126-
)
130+
)
131+
}
127132
}
128133
}
129-
}
130134

131135
#if os(macOS)
132136

133-
var checkmark: some View {
134-
return Text("")
135-
}
137+
var checkmark: some View {
138+
return Text("")
139+
}
136140

137141
#else
138142

139-
var checkmark: some View {
140-
return Image(systemName: "checkmark")
141-
}
143+
var checkmark: some View {
144+
return Image(systemName: "checkmark")
145+
}
142146

143147
#endif
144-
148+
}
145149
}
146150

147-
148151
// MARK: - Creating CaseIterableFlagControls
149152

150153
@available(OSX 11.0, iOS 13.0, watchOS 7.0, tvOS 13.0, *)
151154
protocol CaseIterableEditableFlag {
152-
func control<RootGroup>(label: String, manager: FlagValueManager<RootGroup>, showDetail: Binding<Bool>, showPicker: Binding<Bool>) -> AnyView where RootGroup: FlagContainer
155+
func control<RootGroup>(label: String, manager: FlagValueManager<RootGroup>, showDetail: Binding<Bool>) -> AnyView where RootGroup: FlagContainer
153156
}
154157

155158
@available(OSX 11.0, iOS 13.0, watchOS 7.0, tvOS 13.0, *)
156159
extension UnfurledFlag: CaseIterableEditableFlag
157160
where Value: FlagValue, Value: CaseIterable, Value.AllCases: RandomAccessCollection,
158161
Value: RawRepresentable, Value.RawValue: FlagValue, Value: Hashable
159162
{
160-
func control<RootGroup>(label: String, manager: FlagValueManager<RootGroup>, showDetail: Binding<Bool>, showPicker: Binding<Bool>) -> AnyView where RootGroup: FlagContainer {
163+
func control<RootGroup>(label: String, manager: FlagValueManager<RootGroup>, showDetail: Binding<Bool>) -> AnyView where RootGroup: FlagContainer {
161164
return CaseIterableFlagControl<Value>(
162165
label: label,
163166
value: Binding(
@@ -168,8 +171,7 @@ extension UnfurledFlag: CaseIterableEditableFlag
168171
),
169172
hasChanges: manager.hasValueInSource(flag: flag),
170173
isEditable: manager.isEditable,
171-
showDetail: showDetail,
172-
showPicker: showPicker
174+
showDetail: showDetail
173175
)
174176
.eraseToAnyView()
175177
}

Sources/Vexillographer/Flag Value Controls/OptionalCaseIterableFlagControl.swift

Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ struct OptionalCaseIterableFlagControl<Value>: View
3737
@Binding
3838
var showDetail: Bool
3939

40-
@Binding
41-
var showPicker: Bool
42-
4340
// MARK: - View Body
4441

4542
var content: some View {
@@ -53,7 +50,7 @@ struct OptionalCaseIterableFlagControl<Value>: View
5350
var body: some View {
5451
HStack {
5552
if self.isEditable {
56-
NavigationLink(destination: self.selector, isActive: self.$showPicker) {
53+
NavigationLink(destination: self.selector) {
5754
self.content
5855
}
5956
} else {
@@ -66,82 +63,92 @@ struct OptionalCaseIterableFlagControl<Value>: View
6663
#if os(iOS)
6764

6865
var selector: some View {
69-
return self.selectorList
66+
SelectorList(value: self.$value)
7067
.navigationBarTitle(Text(self.label), displayMode: .inline)
7168
}
7269

7370
#else
7471

7572
var selector: some View {
76-
return self.selectorList
73+
SelectorList(value: self.$value)
7774
}
7875

7976
#endif
8077

81-
var selectorList: some View {
82-
Form {
83-
Section {
84-
Button(
85-
action: {
86-
self.valueSelected(nil)
87-
},
88-
label: {
89-
Text("None")
90-
.foregroundColor(.primary)
91-
Spacer()
92-
93-
if self.value.wrapped == nil {
94-
self.checkmark
78+
struct SelectorList: View {
79+
@Binding
80+
var value: Value
81+
82+
@Environment(\.presentationMode)
83+
private var presentationMode
84+
85+
var body: some View {
86+
Form {
87+
Section {
88+
Button(
89+
action: {
90+
self.valueSelected(nil)
91+
},
92+
label: {
93+
HStack {
94+
Text("None")
95+
.foregroundColor(.primary)
96+
Spacer()
97+
98+
if self.value.wrapped == nil {
99+
self.checkmark
100+
}
101+
}
95102
}
96-
}
97-
)
98-
}
103+
)
104+
}
99105

100-
ForEach(Value.WrappedFlagValue.allCases, id: \.self) { value in
101-
Button(
102-
action: {
103-
self.valueSelected(value)
104-
},
105-
label: {
106-
FlagDisplayValueView(value: value)
107-
Spacer()
108-
109-
if value == self.value.wrapped {
110-
self.checkmark
106+
ForEach(Value.WrappedFlagValue.allCases, id: \.self) { value in
107+
Button(
108+
action: {
109+
self.valueSelected(value)
110+
},
111+
label: {
112+
HStack {
113+
FlagDisplayValueView(value: value)
114+
.foregroundColor(.primary)
115+
Spacer()
116+
117+
if value == self.value.wrapped {
118+
self.checkmark
119+
}
120+
}
111121
}
112-
}
113-
)
122+
)
123+
}
114124
}
115125
}
116-
}
117126

118127
#if os(macOS)
119128

120-
var checkmark: some View {
121-
return Text("")
122-
}
129+
var checkmark: some View {
130+
return Text("")
131+
}
123132

124133
#else
125134

126-
var checkmark: some View {
127-
return Image(systemName: "checkmark")
128-
}
135+
var checkmark: some View {
136+
return Image(systemName: "checkmark")
137+
}
129138

130139
#endif
131-
132-
func valueSelected(_ value: Value.WrappedFlagValue?) {
133-
self.value.wrapped = value
134-
showPicker = false
140+
func valueSelected(_ value: Value.WrappedFlagValue?) {
141+
self.value.wrapped = value
142+
presentationMode.wrappedValue.dismiss()
143+
}
135144
}
136-
137145
}
138146

139-
140147
// MARK: - Creating CaseIterableFlagControls
141148

142149
@available(OSX 11.0, iOS 13.0, watchOS 7.0, tvOS 13.0, *)
143150
protocol OptionalCaseIterableEditableFlag {
144-
func control<RootGroup>(label: String, manager: FlagValueManager<RootGroup>, showDetail: Binding<Bool>, showPicker: Binding<Bool>) -> AnyView where RootGroup: FlagContainer
151+
func control<RootGroup>(label: String, manager: FlagValueManager<RootGroup>, showDetail: Binding<Bool>) -> AnyView where RootGroup: FlagContainer
145152
}
146153

147154
@available(OSX 11.0, iOS 13.0, watchOS 7.0, tvOS 13.0, *)
@@ -150,7 +157,7 @@ extension UnfurledFlag: OptionalCaseIterableEditableFlag
150157
Value.WrappedFlagValue.AllCases: RandomAccessCollection, Value.WrappedFlagValue: RawRepresentable,
151158
Value.WrappedFlagValue.RawValue: FlagValue, Value.WrappedFlagValue: Hashable
152159
{
153-
func control<RootGroup>(label: String, manager: FlagValueManager<RootGroup>, showDetail: Binding<Bool>, showPicker: Binding<Bool>) -> AnyView where RootGroup: FlagContainer {
160+
func control<RootGroup>(label: String, manager: FlagValueManager<RootGroup>, showDetail: Binding<Bool>) -> AnyView where RootGroup: FlagContainer {
154161
let key = info.key
155162

156163
return OptionalCaseIterableFlagControl<Value>(
@@ -159,7 +166,7 @@ extension UnfurledFlag: OptionalCaseIterableEditableFlag
159166
get: { Value(manager.flagValue(key: key)) },
160167
set: { newValue in
161168
do {
162-
try manager.setFlagValue(newValue.wrapped, key: key)
169+
try manager.setFlagValue(newValue, key: key)
163170

164171
} catch {
165172
print("[Vexilographer] Could not set flag with key \"\(key)\" to \"\(newValue)\"")
@@ -168,8 +175,7 @@ extension UnfurledFlag: OptionalCaseIterableEditableFlag
168175
),
169176
hasChanges: manager.hasValueInSource(flag: flag),
170177
isEditable: manager.isEditable,
171-
showDetail: showDetail,
172-
showPicker: showPicker
178+
showDetail: showDetail
173179
)
174180
.eraseToAnyView()
175181
}

Sources/Vexillographer/FlagGroupView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ struct UnfurledFlagGroupView<Group, Root>: View where Group: FlagContainer, Root
6363
Section {
6464
// Filter out all links. They won't work on the mac flag group view.
6565
ForEach(self.group.allItems().filter { $0.isLink == false }, id: \.id) { item in
66-
item.unfurledView
66+
UnfurledFlagItemView(item: item)
6767
}
6868
}
6969
}
@@ -98,7 +98,7 @@ struct UnfurledFlagGroupView<Group, Root>: View where Group: FlagContainer, Root
9898

9999
var flags: some View {
100100
ForEach(self.group.allItems(), id: \.id) { item in
101-
item.unfurledView
101+
UnfurledFlagItemView(item: item)
102102
}
103103
}
104104

Sources/Vexillographer/FlagSectionView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ struct UnfurledFlagSectionView<Group, Root>: View where Group: FlagContainer, Ro
6868

6969
private var content: some View {
7070
ForEach(self.group.allItems(), id: \.id) { item in
71-
item.unfurledView
71+
UnfurledFlagItemView(item: item)
7272
}
7373
}
7474

Sources/Vexillographer/FlagView.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ struct UnfurledFlagView<Value, RootGroup>: View where Value: FlagValue, RootGrou
2929
@State
3030
private var showDetail = false
3131

32-
@State
33-
private var showPicker = false
34-
35-
3632
// MARK: - Initialisation
3733

3834
init(flag: UnfurledFlag<Value, RootGroup>, manager: FlagValueManager<RootGroup>) {
@@ -65,10 +61,10 @@ struct UnfurledFlagView<Value, RootGroup>: View where Value: FlagValue, RootGrou
6561
return flag.control(label: self.flag.info.name, manager: self.manager, showDetail: self.$showDetail)
6662

6763
} else if let flag = self.flag as? CaseIterableEditableFlag {
68-
return flag.control(label: self.flag.info.name, manager: self.manager, showDetail: self.$showDetail, showPicker: self.$showPicker)
64+
return flag.control(label: self.flag.info.name, manager: self.manager, showDetail: self.$showDetail)
6965

7066
} else if let flag = self.flag as? OptionalCaseIterableEditableFlag {
71-
return flag.control(label: self.flag.info.name, manager: self.manager, showDetail: self.$showDetail, showPicker: self.$showPicker)
67+
return flag.control(label: self.flag.info.name, manager: self.manager, showDetail: self.$showDetail)
7268

7369
} else if let flag = self.flag as? StringEditableFlag {
7470
return flag.control(label: self.flag.info.name, manager: self.manager, showDetail: self.$showDetail)

0 commit comments

Comments
 (0)