@@ -11,11 +11,7 @@ struct QuestOptions: View {
1111
1212 let options : [ QuestAnswerChoice ]
1313
14- @Binding var selectedAnswerId : UUID ?
15-
16- var onChoiceSelected : ( QuestAnswerChoice ) -> ( )
17-
18- @Binding var currentAnswer : String ?
14+ @Binding var selectedChoice : QuestAnswerChoice ?
1915
2016 var questType : QuestType
2117
@@ -26,22 +22,18 @@ struct QuestOptions: View {
2622 case . exclusiveChoice:
2723 ExclusiveChoiceView (
2824 options: options,
29- selectedAnswerId: $selectedAnswerId,
30- currentAnswer: $currentAnswer,
31- onChoiceSelected: onChoiceSelected,
25+ selectedChoice: $selectedChoice,
3226 uploadPhoto: uploadPhoto
3327 )
3428 case . multipleChoice:
3529 MultipleChoiceView (
3630 options: options,
37- currentAnswer: $currentAnswer,
38- onChoiceSelected: onChoiceSelected
31+ selectedChoice: $selectedChoice
3932 )
4033
4134 case . numeric:
4235 NumericInputView (
43- currentAnswer: $currentAnswer,
44- onChoiceSelected: onChoiceSelected
36+ selectedChoice: $selectedChoice
4537 )
4638 }
4739 }
@@ -52,9 +44,7 @@ private extension QuestOptions {
5244
5345 struct ExclusiveChoiceView : View {
5446 let options : [ QuestAnswerChoice ]
55- @Binding var selectedAnswerId : UUID ?
56- @Binding var currentAnswer : String ?
57- var onChoiceSelected : ( QuestAnswerChoice ) -> ( )
47+ @Binding var selectedChoice : QuestAnswerChoice ?
5848 var uploadPhoto : ( Bool ) -> ( )
5949
6050 @State private var selectedImageURL : String ? = nil
@@ -87,9 +77,7 @@ private extension QuestOptions {
8777 ForEach ( options, id: \. id) { option in
8878 OptionButton (
8979 option: option,
90- selectedAnswerId: $selectedAnswerId,
91- currentAnswer: $currentAnswer,
92- onChoiceSelected: onChoiceSelected,
80+ selectedChoice: $selectedChoice,
9381 onLongPress: {
9482 if let imageUrl = option. imageURL, !imageUrl. isEmpty {
9583 selectedImageURL = imageUrl
@@ -102,7 +90,7 @@ private extension QuestOptions {
10290
10391 FollowUpButton (
10492 options: options,
105- selectedAnswerId : selectedAnswerId ,
93+ selectedChoice : $selectedChoice ,
10694 uploadPhoto: uploadPhoto
10795 )
10896 }
@@ -114,8 +102,7 @@ private extension QuestOptions {
114102
115103 struct MultipleChoiceView : View {
116104 let options : [ QuestAnswerChoice ]
117- @Binding var currentAnswer : String ?
118- let onChoiceSelected : ( QuestAnswerChoice ) -> Void
105+ @Binding var selectedChoice : QuestAnswerChoice ?
119106
120107 @State private var selectedValues : Set < String > = [ ]
121108 @State private var selectedImageURL : String ? = nil
@@ -167,16 +154,18 @@ private extension QuestOptions {
167154 }
168155 . onAppear ( perform: initializeSelectedValues)
169156 . onChange ( of: selectedValues) { _ in
170- updateCurrentAnswerAndNotify ( )
157+ updateSelectedChoice ( )
158+ }
159+ . onChange ( of: selectedChoice) { _ in
160+ initializeSelectedValues ( )
171161 }
172162 }
173163
174164 private func initializeSelectedValues( ) {
175- guard let answer = currentAnswer , !answer . isEmpty else {
176- selectedValues = [ ]
177- return
165+ let currentSelectedValues = Set ( ( selectedChoice ? . value ?? " " ) . components ( separatedBy : " , " ) . filter { !$0 . isEmpty } )
166+ if selectedValues != currentSelectedValues {
167+ selectedValues = currentSelectedValues
178168 }
179- selectedValues = Set ( answer. components ( separatedBy: " , " ) . filter { !$0. isEmpty } )
180169 }
181170
182171 private func toggleSelection( for option: QuestAnswerChoice ) {
@@ -187,27 +176,38 @@ private extension QuestOptions {
187176 }
188177 }
189178
190- private func updateCurrentAnswerAndNotify ( ) {
179+ private func updateSelectedChoice ( ) {
191180 let combinedValue = selectedValues. sorted ( ) . joined ( separator: " , " )
192- currentAnswer = combinedValue. isEmpty ? nil : combinedValue
193-
194- let fakeAnswer = QuestAnswerChoice ( value: combinedValue, choiceText: combinedValue, imageURL: nil , choiceFollowUp: nil )
195- onChoiceSelected ( fakeAnswer)
181+
182+ if combinedValue. isEmpty {
183+ if selectedChoice != nil {
184+ selectedChoice = nil
185+ }
186+ } else {
187+ if selectedChoice? . value != combinedValue {
188+ let fakeAnswer = QuestAnswerChoice ( value: combinedValue, choiceText: combinedValue, imageURL: nil , choiceFollowUp: nil )
189+ selectedChoice = fakeAnswer
190+ }
191+ }
196192 }
197193 }
198194
199195 struct NumericInputView : View {
200- @Binding var currentAnswer : String ?
201- var onChoiceSelected : ( QuestAnswerChoice ) -> ( )
196+ @Binding var selectedChoice : QuestAnswerChoice ?
202197
203198 var body : some View {
204199 HStack {
205200 TextField ( " Enter value " , text: Binding (
206- get: { currentAnswer ?? " " } ,
201+ get: { selectedChoice ? . value ?? " " } ,
207202 set: { newValue in
208- currentAnswer = newValue
209- let answer = QuestAnswerChoice ( value: newValue, choiceText: newValue, imageURL: " " , choiceFollowUp: " " )
210- onChoiceSelected ( answer)
203+ if newValue. isEmpty {
204+ selectedChoice = nil
205+ } else {
206+ if selectedChoice? . value != newValue {
207+ let answer = QuestAnswerChoice ( value: newValue, choiceText: newValue, imageURL: nil , choiceFollowUp: nil )
208+ selectedChoice = answer
209+ }
210+ }
211211 }
212212 ) )
213213 . frame ( width: 100 )
@@ -249,23 +249,17 @@ private extension QuestOptions {
249249
250250 struct OptionButton : View {
251251 let option : QuestAnswerChoice
252- @Binding var selectedAnswerId : UUID ?
253- @Binding var currentAnswer : String ?
254- let onChoiceSelected : ( QuestAnswerChoice ) -> Void
252+ @Binding var selectedChoice : QuestAnswerChoice ?
255253 let onLongPress : ( ) -> Void
256254
257255 var body : some View {
258256 Button ( action: {
259- if selectedAnswerId == option. id {
257+ if selectedChoice == option {
260258 // Deselect
261- selectedAnswerId = nil
262- currentAnswer = nil
263- // Don't call onChoiceSelected if you want to ignore blank assignment
259+ selectedChoice = nil
264260 } else {
265261 // Select
266- selectedAnswerId = option. id
267- currentAnswer = option. value
268- onChoiceSelected ( option)
262+ selectedChoice = option
269263 }
270264 } ) {
271265 VStack ( spacing: 8 ) {
@@ -283,7 +277,7 @@ private extension QuestOptions {
283277 }
284278 . overlay (
285279 RoundedRectangle ( cornerRadius: 8 )
286- . stroke ( currentAnswer == option. value ? Asset . Colors. accentPink. swiftUIColor : Color . clear, lineWidth: 3 )
280+ . stroke ( selectedChoice == option ? Asset . Colors. accentPink. swiftUIColor : Color . clear, lineWidth: 3 )
287281 )
288282 . onLongPressGesture ( perform: onLongPress)
289283 }
@@ -343,13 +337,11 @@ private extension QuestOptions {
343337
344338 struct FollowUpButton : View {
345339 let options : [ QuestAnswerChoice ]
346- let selectedAnswerId : UUID ?
340+ @ Binding var selectedChoice : QuestAnswerChoice ?
347341 let uploadPhoto : ( Bool ) -> Void
348342
349343 var body : some View {
350- if let selected = selectedAnswerId. flatMap ( { id in
351- options. first ( where: { $0. id == id && $0. choiceFollowUp != nil } )
352- } ) {
344+ if let selected = selectedChoice, selected. choiceFollowUp != nil {
353345 Button ( action: {
354346 uploadPhoto ( true )
355347 } ) {
@@ -406,9 +398,9 @@ private extension QuestOptions {
406398
407399#Preview {
408400 QuestOptions ( options: [ QuestAnswerChoice ( value: " asphalt " , choiceText: " Asphalt " , imageURL: " https://raw.githubusercontent.com/TaskarCenterAtUW/tdei-tools/refs/heads/main/images/sidewalk/surface/asphalt_landscape.png " , choiceFollowUp: nil ) ,
409- QuestAnswerChoice ( value: " no " , choiceText: " No, this roadway is too wide to cross safely. " , imageURL: nil , choiceFollowUp: nil ) ] , selectedAnswerId : . constant ( UUID ( ) ) , onChoiceSelected : { qa in
410-
411- } , currentAnswer : . constant ( " Binding<String?> " ) , questType: GoInfoGame . QuestType. exclusiveChoice) { s in
401+ QuestAnswerChoice ( value: " no " , choiceText: " No, this roadway is too wide to cross safely. " , imageURL: nil , choiceFollowUp: nil ) ] ,
402+ selectedChoice : . constant ( QuestAnswerChoice ( value : " no " , choiceText : " No, this roadway is too wide to cross safely. " , imageURL : nil , choiceFollowUp : nil ) ) ,
403+ questType: GoInfoGame . QuestType. exclusiveChoice) { s in
412404
413405 }
414406}
0 commit comments