Skip to content

Commit b56895e

Browse files
committed
🔀️ Merge branch 'ladislas/feature/gek-action-observe-sfsymbol' into develop
2 parents e0a7173 + b20f081 commit b56895e

File tree

4 files changed

+101
-34
lines changed

4 files changed

+101
-34
lines changed

‎Modules/ContentKit/Resources/Content/activities/templates/touch_to_select_action_observe-70A14CC4CD394CDBB4886A8DFE4C5CCC.activity.yml

+26-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ uuid: 70A14CC4CD394CDBB4886A8DFE4C5CCC
88
name: touch_to_select_action_observe
99

1010
created_at: "2024-06-17T17:38:12.804177"
11-
last_edited_at: "2024-06-28T13:28:34.670550"
11+
last_edited_at: "2024-09-16T15:27:15.658346"
1212

1313
status: template
1414

@@ -72,7 +72,7 @@ exercises_payload:
7272
- group:
7373
- instructions:
7474
- locale: fr_FR
75-
value: Touche les fruits similaires à celui présenter
75+
value: Touche les fruits similaires à celui présenté
7676
- locale: en_US
7777
value: Tap the same fruits as the one shown
7878
interface: observeThenTouchToSelect
@@ -95,3 +95,27 @@ exercises_payload:
9595
- value: pictograms-foods-fruits-banana_yellow-00FB
9696
type: image
9797
is_right_answer: true
98+
99+
- instructions:
100+
- locale: fr_FR
101+
value: Touche les animaux similaires à celui présenté
102+
- locale: en_US
103+
value: Tap the same animals as the one shown
104+
interface: observeThenTouchToSelect
105+
gameplay: findTheRightAnswers
106+
action:
107+
type: ipad
108+
value:
109+
type: sfsymbol
110+
value: fish
111+
payload:
112+
choices:
113+
- value: fish
114+
type: sfsymbol
115+
is_right_answer: true
116+
- value: cat
117+
type: sfsymbol
118+
- value: dog
119+
type: sfsymbol
120+
- value: bird
121+
type: sfsymbol

‎Modules/ContentKit/Sources/Exercise/Exercise+Action.swift

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ public extension Exercise {
3030
case .image:
3131
let image = try valueContainer.decode(String.self, forKey: .value)
3232
self = .ipad(type: .image(image))
33+
case .sfsymbol:
34+
let symbol = try valueContainer.decode(String.self, forKey: .value)
35+
self = .ipad(type: .sfsymbol(symbol))
3336
case .audio:
3437
let audio = try valueContainer.decode(String.self, forKey: .value)
3538
self = .ipad(type: .audio(audio))
@@ -84,6 +87,7 @@ public extension Exercise {
8487
public enum ValueType: String, Codable {
8588
case color
8689
case image
90+
case sfsymbol
8791
case audio
8892
case speech
8993
}

‎Modules/GameEngineKit/Sources/Exercises/ActionButton/ActionButton+Observe.swift

+58-25
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,23 @@ struct ActionButtonObserve: View {
4545
// MARK: Lifecycle
4646

4747
init(image: String, imageWasTapped: Binding<Bool>) {
48-
guard let image = Bundle.path(forImage: image) else {
49-
fatalError("Image not found")
48+
if let imagePath = Bundle.path(forImage: image) {
49+
self.image = imagePath
50+
self.isSFSymbol = false
51+
} else if UIImage(systemName: image) != nil {
52+
self.image = image
53+
self.isSFSymbol = true
54+
} else {
55+
fatalError("Image not found: \(image)")
5056
}
51-
self.image = image
57+
5258
self._imageWasTapped = imageWasTapped
5359
}
5460

5561
// MARK: Internal
5662

5763
let image: String
64+
let isSFSymbol: Bool
5865

5966
@Binding var imageWasTapped: Bool
6067

@@ -76,28 +83,44 @@ struct ActionButtonObserve: View {
7683
}
7784
.disabled(self.imageWasTapped)
7885
.background {
79-
if !FileManager.default.fileExists(atPath: self.image) {
80-
self.imageNotFound()
81-
}
82-
83-
if self.image.isRasterImageFile {
84-
Image(uiImage: UIImage(named: self.image)!)
86+
if self.isSFSymbol {
87+
Image(systemName: self.image)
8588
.resizable()
8689
.clipShape(RoundedRectangle(cornerRadius: 10))
8790
.scaledToFit()
91+
.padding(60)
8892
.frame(width: 460, height: 460)
89-
.clipShape(RoundedRectangle(cornerRadius: 10))
90-
.modifier(AnimatableBlur(blurRadius: self.imageWasTapped ? 0 : 20))
91-
.modifier(AnimatableSaturation(saturation: self.imageWasTapped ? 1 : 0))
92-
}
93-
94-
if self.image.isVectorImageFile {
95-
SVGView(contentsOf: URL(fileURLWithPath: self.image))
96-
.frame(width: 460, height: 460)
93+
.foregroundStyle(.black)
9794
.background(self.choiceBackgroundColor)
9895
.clipShape(RoundedRectangle(cornerRadius: 10))
9996
.modifier(AnimatableBlur(blurRadius: self.imageWasTapped ? 0 : 20))
10097
.modifier(AnimatableSaturation(saturation: self.imageWasTapped ? 1 : 0))
98+
} else {
99+
if !FileManager.default.fileExists(atPath: self.image) {
100+
self.imageNotFound()
101+
}
102+
103+
if self.image.isRasterImageFile {
104+
Image(uiImage: UIImage(named: self.image)!)
105+
.resizable()
106+
.clipShape(RoundedRectangle(cornerRadius: 10))
107+
.scaledToFit()
108+
.frame(width: 460, height: 460)
109+
.background(self.choiceBackgroundColor)
110+
.clipShape(RoundedRectangle(cornerRadius: 10))
111+
.modifier(AnimatableBlur(blurRadius: self.imageWasTapped ? 0 : 20))
112+
.modifier(AnimatableSaturation(saturation: self.imageWasTapped ? 1 : 0))
113+
}
114+
115+
if self.image.isVectorImageFile {
116+
SVGView(contentsOf: URL(fileURLWithPath: self.image))
117+
.clipShape(RoundedRectangle(cornerRadius: 10))
118+
.frame(width: 460, height: 460)
119+
.background(self.choiceBackgroundColor)
120+
.clipShape(RoundedRectangle(cornerRadius: 10))
121+
.modifier(AnimatableBlur(blurRadius: self.imageWasTapped ? 0 : 20))
122+
.modifier(AnimatableSaturation(saturation: self.imageWasTapped ? 1 : 0))
123+
}
101124
}
102125
}
103126
}
@@ -144,14 +167,24 @@ extension l10n {
144167
}
145168

146169
#Preview {
147-
struct ActionObserveButtonContainer: View {
148-
@State var imageWasTapped = false
149-
var body: some View {
150-
ActionButtonObserve(
151-
image: "placeholder-observe_then_touch_to_select", imageWasTapped: $imageWasTapped
152-
)
170+
ScrollView {
171+
VStack {
172+
HStack {
173+
ActionButtonObserve(
174+
image: "4.circle", imageWasTapped: .constant(false)
175+
)
176+
ActionButtonObserve(
177+
image: "4.circle", imageWasTapped: .constant(true)
178+
)
179+
}
180+
HStack {
181+
ActionButtonObserve(
182+
image: "pictograms-foods-fruits-banana_yellow-00FB", imageWasTapped: .constant(false)
183+
)
184+
ActionButtonObserve(
185+
image: "pictograms-foods-fruits-banana_yellow-00FB", imageWasTapped: .constant(true)
186+
)
187+
}
153188
}
154189
}
155-
156-
return ActionObserveButtonContainer()
157190
}

‎Modules/GameEngineKit/Sources/Exercises/Touch/ObserveThenTouchToSelect/ObserveThenTouchToSelect.swift

+13-7
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,23 @@ public struct ObserveThenTouchToSelectView: View {
1515
}
1616

1717
public init(exercise: Exercise, data: ExerciseSharedData? = nil) {
18-
guard let payload = exercise.payload as? TouchToSelect.Payload,
19-
case let .ipad(type: .image(name)) = exercise.action
20-
else {
21-
log.error("Exercise payload is not .selection and/or Exercise does not contain iPad image action")
22-
fatalError("đź’Ą Exercise payload is not .selection and/or Exercise does not contain iPad image action")
18+
guard let payload = exercise.payload as? TouchToSelect.Payload else {
19+
log.error("Invalid payload type: expected TouchToSelect.Payload, got \(type(of: exercise.payload))")
20+
fatalError("đź’Ą Invalid payload type: expected TouchToSelect.Payload, got \(type(of: exercise.payload))")
21+
}
22+
23+
switch exercise.action {
24+
case let .ipad(type: .image(name)):
25+
self.image = name
26+
case let .ipad(type: .sfsymbol(name)):
27+
self.image = name
28+
default:
29+
log.error("Invalid action type: expected iPad image or sfsymbol, got \(String(describing: exercise.action))")
30+
fatalError("đź’Ą Invalid action type: expected iPad image or sfsymbol, got \(String(describing: exercise.action))")
2331
}
2432

2533
_viewModel = StateObject(
2634
wrappedValue: TouchToSelectViewViewModel(choices: payload.choices, shuffle: payload.shuffleChoices, shared: data))
27-
28-
self.image = name
2935
}
3036

3137
// MARK: Public

0 commit comments

Comments
 (0)