Skip to content

Commit

Permalink
🔀️ Merge branch 'ladislas/feature/gek-action-observe-sfsymbol' into d…
Browse files Browse the repository at this point in the history
…evelop
  • Loading branch information
ladislas committed Sep 16, 2024
2 parents e0a7173 + b20f081 commit b56895e
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ uuid: 70A14CC4CD394CDBB4886A8DFE4C5CCC
name: touch_to_select_action_observe

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

status: template

Expand Down Expand Up @@ -72,7 +72,7 @@ exercises_payload:
- group:
- instructions:
- locale: fr_FR
value: Touche les fruits similaires à celui présenter
value: Touche les fruits similaires à celui présenté
- locale: en_US
value: Tap the same fruits as the one shown
interface: observeThenTouchToSelect
Expand All @@ -95,3 +95,27 @@ exercises_payload:
- value: pictograms-foods-fruits-banana_yellow-00FB
type: image
is_right_answer: true

- instructions:
- locale: fr_FR
value: Touche les animaux similaires à celui présenté
- locale: en_US
value: Tap the same animals as the one shown
interface: observeThenTouchToSelect
gameplay: findTheRightAnswers
action:
type: ipad
value:
type: sfsymbol
value: fish
payload:
choices:
- value: fish
type: sfsymbol
is_right_answer: true
- value: cat
type: sfsymbol
- value: dog
type: sfsymbol
- value: bird
type: sfsymbol
4 changes: 4 additions & 0 deletions Modules/ContentKit/Sources/Exercise/Exercise+Action.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public extension Exercise {
case .image:
let image = try valueContainer.decode(String.self, forKey: .value)
self = .ipad(type: .image(image))
case .sfsymbol:
let symbol = try valueContainer.decode(String.self, forKey: .value)
self = .ipad(type: .sfsymbol(symbol))
case .audio:
let audio = try valueContainer.decode(String.self, forKey: .value)
self = .ipad(type: .audio(audio))
Expand Down Expand Up @@ -84,6 +87,7 @@ public extension Exercise {
public enum ValueType: String, Codable {
case color
case image
case sfsymbol
case audio
case speech
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,23 @@ struct ActionButtonObserve: View {
// MARK: Lifecycle

init(image: String, imageWasTapped: Binding<Bool>) {
guard let image = Bundle.path(forImage: image) else {
fatalError("Image not found")
if let imagePath = Bundle.path(forImage: image) {
self.image = imagePath
self.isSFSymbol = false
} else if UIImage(systemName: image) != nil {
self.image = image
self.isSFSymbol = true
} else {
fatalError("Image not found: \(image)")
}
self.image = image

self._imageWasTapped = imageWasTapped
}

// MARK: Internal

let image: String
let isSFSymbol: Bool

@Binding var imageWasTapped: Bool

Expand All @@ -76,28 +83,44 @@ struct ActionButtonObserve: View {
}
.disabled(self.imageWasTapped)
.background {
if !FileManager.default.fileExists(atPath: self.image) {
self.imageNotFound()
}

if self.image.isRasterImageFile {
Image(uiImage: UIImage(named: self.image)!)
if self.isSFSymbol {
Image(systemName: self.image)
.resizable()
.clipShape(RoundedRectangle(cornerRadius: 10))
.scaledToFit()
.padding(60)
.frame(width: 460, height: 460)
.clipShape(RoundedRectangle(cornerRadius: 10))
.modifier(AnimatableBlur(blurRadius: self.imageWasTapped ? 0 : 20))
.modifier(AnimatableSaturation(saturation: self.imageWasTapped ? 1 : 0))
}

if self.image.isVectorImageFile {
SVGView(contentsOf: URL(fileURLWithPath: self.image))
.frame(width: 460, height: 460)
.foregroundStyle(.black)
.background(self.choiceBackgroundColor)
.clipShape(RoundedRectangle(cornerRadius: 10))
.modifier(AnimatableBlur(blurRadius: self.imageWasTapped ? 0 : 20))
.modifier(AnimatableSaturation(saturation: self.imageWasTapped ? 1 : 0))
} else {
if !FileManager.default.fileExists(atPath: self.image) {
self.imageNotFound()
}

if self.image.isRasterImageFile {
Image(uiImage: UIImage(named: self.image)!)
.resizable()
.clipShape(RoundedRectangle(cornerRadius: 10))
.scaledToFit()
.frame(width: 460, height: 460)
.background(self.choiceBackgroundColor)
.clipShape(RoundedRectangle(cornerRadius: 10))
.modifier(AnimatableBlur(blurRadius: self.imageWasTapped ? 0 : 20))
.modifier(AnimatableSaturation(saturation: self.imageWasTapped ? 1 : 0))
}

if self.image.isVectorImageFile {
SVGView(contentsOf: URL(fileURLWithPath: self.image))
.clipShape(RoundedRectangle(cornerRadius: 10))
.frame(width: 460, height: 460)
.background(self.choiceBackgroundColor)
.clipShape(RoundedRectangle(cornerRadius: 10))
.modifier(AnimatableBlur(blurRadius: self.imageWasTapped ? 0 : 20))
.modifier(AnimatableSaturation(saturation: self.imageWasTapped ? 1 : 0))
}
}
}
}
Expand Down Expand Up @@ -144,14 +167,24 @@ extension l10n {
}

#Preview {
struct ActionObserveButtonContainer: View {
@State var imageWasTapped = false
var body: some View {
ActionButtonObserve(
image: "placeholder-observe_then_touch_to_select", imageWasTapped: $imageWasTapped
)
ScrollView {
VStack {
HStack {
ActionButtonObserve(
image: "4.circle", imageWasTapped: .constant(false)
)
ActionButtonObserve(
image: "4.circle", imageWasTapped: .constant(true)
)
}
HStack {
ActionButtonObserve(
image: "pictograms-foods-fruits-banana_yellow-00FB", imageWasTapped: .constant(false)
)
ActionButtonObserve(
image: "pictograms-foods-fruits-banana_yellow-00FB", imageWasTapped: .constant(true)
)
}
}
}

return ActionObserveButtonContainer()
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,23 @@ public struct ObserveThenTouchToSelectView: View {
}

public init(exercise: Exercise, data: ExerciseSharedData? = nil) {
guard let payload = exercise.payload as? TouchToSelect.Payload,
case let .ipad(type: .image(name)) = exercise.action
else {
log.error("Exercise payload is not .selection and/or Exercise does not contain iPad image action")
fatalError("đź’Ą Exercise payload is not .selection and/or Exercise does not contain iPad image action")
guard let payload = exercise.payload as? TouchToSelect.Payload else {
log.error("Invalid payload type: expected TouchToSelect.Payload, got \(type(of: exercise.payload))")
fatalError("đź’Ą Invalid payload type: expected TouchToSelect.Payload, got \(type(of: exercise.payload))")
}

switch exercise.action {
case let .ipad(type: .image(name)):
self.image = name
case let .ipad(type: .sfsymbol(name)):
self.image = name
default:
log.error("Invalid action type: expected iPad image or sfsymbol, got \(String(describing: exercise.action))")
fatalError("đź’Ą Invalid action type: expected iPad image or sfsymbol, got \(String(describing: exercise.action))")
}

_viewModel = StateObject(
wrappedValue: TouchToSelectViewViewModel(choices: payload.choices, shuffle: payload.shuffleChoices, shared: data))

self.image = name
}

// MARK: Public
Expand Down

0 comments on commit b56895e

Please sign in to comment.