Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ (ContentKit): Refactor Exercise Payload #468

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 3 additions & 57 deletions Modules/ContentKit/Sources/Exercise/Exercise+Payload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,7 @@

import Foundation

// swiftlint:disable nesting
public protocol ExercisePayloadProtocol: Codable {}

extension Exercise {

public enum Payload: Codable {
case selection(TouchToSelect.Payload)
case dragAndDrop(DragAndDropIntoZones.Payload)

// TODO(@ladislas): see if we can decode based on interface in Exercise
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CustomKeys.self)

if container.allKeys.contains(.dropZoneA) {
let dropZoneA = try container.decode(DragAndDropIntoZones.DropZone.Details.self, forKey: .dropZoneA)
let dropZoneB = try container.decodeIfPresent(
DragAndDropIntoZones.DropZone.Details.self, forKey: .dropZoneB)
let choices = try container.decode([DragAndDropIntoZones.Choice].self, forKey: .choices)

self = .dragAndDrop(
DragAndDropIntoZones.Payload(dropZoneA: dropZoneA, dropZoneB: dropZoneB, choices: choices))
return
}

// ? Selection
if container.allKeys.contains(.choices) {
let choices = try container.decode([TouchToSelect.Choice].self, forKey: .choices)
let shuffleChoices = try container.decodeIfPresent(Bool.self, forKey: .shuffleChoices) ?? false

self = .selection(
TouchToSelect.Payload(choices: choices, shuffleChoices: shuffleChoices))
return
}

throw DecodingError.dataCorruptedError(
forKey: CustomKeys.payload, in: container,
debugDescription:
"Cannot decode ExercisePayload. Available keys: \(container.allKeys.map { $0.stringValue })")
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .selection(let payload):
try container.encode(payload)
case .dragAndDrop(let payload):
try container.encode(payload)
}
}

private enum CustomKeys: String, CodingKey {
case choices, dropZoneA, dropZoneB, payload, action
case shuffleChoices = "shuffle_choices"
}
}

}

// swiftlint:enable nesting
extension TouchToSelect.Payload: ExercisePayloadProtocol {}
extension DragAndDropIntoZones.Payload: ExercisePayloadProtocol {}
16 changes: 16 additions & 0 deletions Modules/ContentKit/Sources/Exercise/Exercise+TouchToSelect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
public enum TouchToSelect {

public struct Choice: Codable {

public let value: String
public let type: Exercise.UIElementType
public let isRightAnswer: Bool
Expand All @@ -27,11 +28,26 @@ public enum TouchToSelect {
self.type = type
self.isRightAnswer = isRightAnswer
}

}

public struct Payload: Codable {

public let choices: [Choice]
public let shuffleChoices: Bool

enum CodingKeys: String, CodingKey {
case choices
case shuffleChoices = "shuffle_choices"
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.choices = try container.decode([Choice].self, forKey: .choices)

self.shuffleChoices = try container.decodeIfPresent(Bool.self, forKey: .shuffleChoices) ?? false
}

}

}
Expand Down
33 changes: 32 additions & 1 deletion Modules/ContentKit/Sources/Exercise/Exercise.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,37 @@ public struct Exercise: Codable {
public let interface: Interface
public let gameplay: Gameplay
public let action: Action?
public let payload: Payload
public let payload: ExercisePayloadProtocol

enum CodingKeys: String, CodingKey {
case instructions, interface, gameplay, action, payload
}

public func encode(to encoder: Encoder) throws {
fatalError("💥 Not implemented yet")
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.instructions = try container.decode(String.self, forKey: .instructions)
self.interface = try container.decode(Interface.self, forKey: .interface)
self.gameplay = try container.decode(Gameplay.self, forKey: .gameplay)
self.action = try container.decodeIfPresent(Action.self, forKey: .action)

switch (interface, gameplay) {
case (.touchToSelect, .findTheRightAnswers),
(.listenThenTouchToSelect, .findTheRightAnswers),
(.observeThenTouchToSelect, .findTheRightAnswers),
(.robotThenTouchToSelect, .findTheRightAnswers):
payload = try container.decode(TouchToSelect.Payload.self, forKey: .payload)

case (.dragAndDropIntoZones, .findTheRightAnswers):
payload = try container.decode(DragAndDropIntoZones.Payload.self, forKey: .payload)

default:
throw DecodingError.dataCorruptedError(
forKey: .payload, in: container, debugDescription: "Invalid combination of interface or gameplay")
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@State private var scene: SKScene = SKScene()
let dropZoneA: DragAndDropIntoZones.DropZone.Details
let dropZoneB: DragAndDropIntoZones.DropZone.Details?
// TODO(@HPezz): Add hints variable

Check failure on line 16 in Modules/GameEngineKit/Sources/_NewSystem/Views/DragAndDrop/DragAndDropIntoZonesView.swift

View workflow job for this annotation

GitHub Actions / lint

TODOs should be resolved ((@HPezz): Add hints variable) (todo)
// let hints: Bool

public init(
Expand All @@ -26,7 +26,7 @@
}

public init(exercise: Exercise, data: ExerciseSharedData? = nil) {
guard case .dragAndDrop(let payload) = exercise.payload else {
guard let payload = exercise.payload as? DragAndDropIntoZones.Payload else {
log.error("Exercise payload is not .dragAndDrop")
fatalError("💥 Exercise payload is not .dragAndDrop")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public struct ListenThenTouchToSelectView: View {

public init(exercise: Exercise, data: ExerciseSharedData? = nil) {
guard
case .selection(let payload) = exercise.payload,
let payload = exercise.payload as? TouchToSelect.Payload,
case .ipad(type: .audio(let name)) = exercise.action
else {
log.error("Exercise payload is not .selection and/or Exercise does not contain iPad audio action")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public struct ObserveThenTouchToSelectView: View {

public init(exercise: Exercise, data: ExerciseSharedData? = nil) {
guard
case .selection(let payload) = exercise.payload,
let payload = exercise.payload as? TouchToSelect.Payload,
case .ipad(type: .image(let name)) = exercise.action
else {
log.error("Exercise payload is not .selection and/or Exercise does not contain iPad image action")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public struct RobotThenTouchToSelectView: View {

public init(exercise: Exercise, data: ExerciseSharedData? = nil) {
guard
case .selection(let payload) = exercise.payload,
let payload = exercise.payload as? TouchToSelect.Payload,
case .robot(let actionType) = exercise.action
else {
log.error("Exercise payload is not .selection and/or Exercise does not contain robot action")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public struct TouchToSelectView: View {
}

public init(exercise: Exercise, data: ExerciseSharedData? = nil) {
guard case .selection(let payload) = exercise.payload else {
guard let payload = exercise.payload as? TouchToSelect.Payload else {
fatalError("Exercise payload is not .selection")
}

Expand Down
Loading