You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
import SwiftUI
structMultipleChoiceView:View{structExercise{structQuestion{structChoice{vartitle:Stringvarhint:String?varexplanation:String?varisOn:Boolvaritem:Hint?}vartitle:StringvarlongQuestion:String?varhint:String?varchoices:[Choice]varitem:Hint?}vartitle:Stringvarquestions:[Question]}structHint:Identifiable{varmessage:Stringvarid:String{
message
}}structMultipleChoiceToggleStyle:ToggleStyle{func makeBody(configuration:Configuration)->someView{HStack{
configuration.label
Button{
configuration.isOn.toggle()} label:{
if configuration.isOn {Image(systemName:"checkmark.square.fill")}else{Image(systemName:"square")}}.foregroundStyle(.foreground)}.padding().background(.secondary.opacity(0.2), in:.rect(cornerRadius:5))}}@Environment(\.isEnabled)varisEnabled@Statevarexercise=Exercise(
title:"A Quiz Exercise",
questions:[.init(
title:"Multiple-choice question",
longQuestion:"A very very very very very very very very very very very very very very very very very long question?",
hint:"Something",
choices:[.init(
title:"Enter a correct answer option here",
hint:"This is correct",
explanation:"Add an explanation here (only visible in feedback after quiz has ended)",
isOn: false),.init(title:"Maybe this is correct, too", isOn: false),.init(title:"Enter a wrong answer option here", isOn: false)]),.init(
title:"What does every program say first?",
hint:"Nothing",
choices:[.init(title:"Hello, world!", isOn: false)])])varbody:someView{ScrollView{VStack{ForEach($exercise.questions, id: \.title, content:self.question)}.padding(.horizontal)}.navigationTitle(exercise.title).navigationBarTitleDisplayMode(.inline).toolbar{ToolbarItem{Button("Submit"){
//
}}}}}privateextensionMultipleChoiceView{func question(_ question:Binding<Exercise.Question>)->someView{VStack(alignment:.leading){HStack{Text(question.wrappedValue.title).font(.title2)Spacer()
question.wrappedValue.hint.map{ hint inButton{
question.wrappedValue.item =Hint(message: hint)} label:{Image(systemName:"questionmark.circle.fill")}.popover(item: question.item){ item inText(item.message).padding(.horizontal).presentationCompactAdaptation(.popover)}}Text("1 P").font(.body.bold())}
question.wrappedValue.longQuestion.map(Text.init)ForEach(question.choices, id: \.title, content:self.choice)Text("Please check all correct answer options").font(.footnote)}.padding().background(.secondary.opacity(0.1), in:.rect(cornerRadius:5))}func choice(_ choice:Binding<Exercise.Question.Choice>)->someView{VStack{Toggle(isOn: choice.isOn){HStack{Text(choice.wrappedValue.title)Spacer()
if isEnabled {
choice.wrappedValue.hint.map{ hint inButton{
choice.wrappedValue.item =Hint(message: hint)} label:{Image(systemName:"questionmark.circle.fill")}.popover(item: choice.item){ item inText(item.message).padding(.horizontal).presentationCompactAdaptation(.popover)}}}}}.toggleStyle(MultipleChoiceToggleStyle())
if !isEnabled {
if let hint = choice.wrappedValue.hint {HStack{Image(systemName:"questionmark.circle.fill")Text(hint)Spacer()}}
if let explanation = choice.wrappedValue.explanation {HStack(alignment:.top){Image(systemName:"exclamationmark.circle.fill")Text(explanation)Spacer()}}}}}}
#Preview {NavigationStack{MultipleChoiceView().disabled(false)}}
#Preview {NavigationStack{MultipleChoiceView().disabled(true)}.preferredColorScheme(.dark)}
import SwiftUI
structShortAnswerView:View{staticfunc makeNodes(_ string:String)->[Exercise.Question.Node_]{letpattern=#/\[-spot \d+\]/#letsplit= string
.split(separator: pattern).map{ substring inExercise.Question.Node_.init(id:.init(), text:String(substring), isSpot: false)}letmatches= string.matches(of: pattern)letmatch=matches[0].output
print(match)assert(split.count == matches.count +1)
// https://stackoverflow.com/questions/34951824/how-can-i-interleave-two-arrays
func mergeFunction<T>(_ one:[T], _ two:[T])->[T]{letcommonLength=min(one.count, two.count)returnzip(one, two).flatMap{[$0, $1]}+ one.suffix(from: commonLength)+ two.suffix(from: commonLength)}returnmergeFunction(split,
matches.map{ x inExercise.Question.Node_.init(id:.init(), text:"", isSpot: true)})}structExercise{structQuestion{structNode_:Identifiable{letid:UUIDvartext:StringvarisSpot:Bool}vartitle:StringvarlongQuestion:String?varhint:String?varnodes:[Node_]varitem:Hint?}vartitle:Stringvarquestions:[Question]}structHint:Identifiable{varmessage:Stringvarid:String{
message
}}@Statevarexercise=Exercise(
title:"A Quiz Exercise",
questions:[.init(
title:"Short-answer question",
longQuestion:nil,
hint:"Something",
nodes:makeNodes("Enter your long question if needed\n\nSelect a part of the text and click on Add Spot to automatically create an input field and the corresponding mapping\n\nYou can define a input field like this: This [-spot 1] an [-spot 2] field.\n\nTo define the solution for the input fields you need to create a mapping (multiple mapping also possible):")),
// .init(
// title: "What does every program say first?",
// hint: "Nothing",
// choices: [
// .init(title: "Hello, world!", isOn: false)
// ])
])varbody:someView{NavigationStack{ScrollView{VStack{ForEach($exercise.questions, id: \.title, content:self.question)}.padding(.horizontal)}.navigationTitle(exercise.title).navigationBarTitleDisplayMode(.inline).toolbar{ToolbarItem{Button("Submit"){
//
}}}}}}privateextensionShortAnswerView{func question(_ question:Binding<Exercise.Question>)->someView{VStack(alignment:.leading){HStack/*(alignment: .firstTextBaseline)*/ {Text(question.wrappedValue.title).font(.title2)Spacer()
question.wrappedValue.hint.map{ hint inButton{
question.wrappedValue.item =Hint(message: hint)} label:{Image(systemName:"questionmark.circle.fill")}.popover(item: question.item){ item inText(item.message).padding(.horizontal).presentationCompactAdaptation(.popover)}}Text("1 P").font(.body.bold())}VStack(alignment:.leading){ForEach(question.nodes){ node in
if node.wrappedValue.isSpot {TextField("", text: node.text).textFieldStyle(.roundedBorder)}else{Text(node.wrappedValue.text)}}}.padding().background(.background, in:.rect(cornerRadius:5))}.padding().background(.secondary.opacity(0.1), in:.rect(cornerRadius:5))}}
#Preview {ShortAnswerView()}
Prototype
See #65
Multiple-choice question
Screen.Recording.2023-12-20.at.20.11.07.mov
Details
Short-answer question
Screen.Recording.2023-12-24.at.00.56.47.mov
Details
Drag-and-drop question
Simulator.Screen.Recording.-.iPhone.15.Pro.-.2023-12-22.at.00.15.59.mp4
Details
Android
The text was updated successfully, but these errors were encountered: