Skip to content

Commit

Permalink
fix: fixing timing mismatch M2-8255 (#900)
Browse files Browse the repository at this point in the history
* feature/adding unix time

* fix creating boot time to fix the timestamp result

* fix/Fixing timing mismatch between taps

* reverting some files

* fixing identation

* fixing redundant call, and ensuring the button will be disabled before user action

* new formating and fixing index out of range

---------

Co-authored-by: Felipe Imperio <felipeimp@Felipes-MacBook-Pro.local>
  • Loading branch information
2 people authored and ChaconC committed Dec 6, 2024
1 parent a7da1bf commit dd98685
Showing 1 changed file with 85 additions and 52 deletions.
137 changes: 85 additions & 52 deletions ios/FlankerNativeComponents/GameManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@ enum TypeTimeStamps {
}

protocol GameManagerProtocol: AnyObject {
func updateText(text: String, color: UIColor, font: UIFont, isStart: Bool, typeTime: TypeTimeStamps)
func updateText(
text: String, color: UIColor, font: UIFont, isStart: Bool, typeTime: TypeTimeStamps)
func updateFixations(image: URL?, isStart: Bool, typeTime: TypeTimeStamps)
func updateTime(time: String)
func setEnableButton(isEnable: Bool)
func updateTitleButton(left: String?, right: String?, leftImage: URL?, rightImage: URL?, countButton: Int)
func resultTest(avrgTime: Int?, procentCorrect: Int?, data: FlankerModel?, dataArray: [FlankerModel]?, isShowResults: Bool, minAccuracy: Int)
func updateTitleButton(
left: String?, right: String?, leftImage: URL?, rightImage: URL?, countButton: Int)
func resultTest(
avrgTime: Int?, procentCorrect: Int?, data: FlankerModel?, dataArray: [FlankerModel]?,
isShowResults: Bool, minAccuracy: Int)
}

class GameManager {
Expand Down Expand Up @@ -78,11 +82,11 @@ class GameManager {
weak var delegate: GameManagerProtocol?

private let bootTime: Double = {
let uptime = CACurrentMediaTime()
let nowTime = Date().timeIntervalSince1970
return nowTime - uptime
}()
let uptime = CACurrentMediaTime()
let nowTime = Date().timeIntervalSince1970
return nowTime - uptime
}()

func startGame(timeSpeed: Float, isShowAnswers: Bool, countGame: Int) {
countAllGame = countGame
timeSpeedGame = TimeInterval(timeSpeed)
Expand Down Expand Up @@ -115,7 +119,7 @@ class GameManager {
case .fixations:
startFixationsTimestamp = time
case .trial:
break
break
case .feedback:
startFeedbackTimestamp = time
case .response:
Expand All @@ -137,14 +141,15 @@ class GameManager {

func checkedAnswer(button: SelectedButton) {
guard !hasRespondedInCurrentTrial else { return }
guard let startTrialTimestamp = startTrialTimestamp else { return }
hasRespondedInCurrentTrial = true
respondTouchButton = bootTime + CACurrentMediaTime()
invalidateTimers()

delegate?.setEnableButton(isEnable: false)

guard let gameParameters = gameParameters else { return }
guard let startTrialTimestamp = startTrialTimestamp else { return }
guard countTest >= 0 && countTest < gameParameters.trials.count else { return }
var resultTime = (respondTouchButton! - startTrialTimestamp) * 1000

arrayTimes.append(Int(resultTime))
Expand All @@ -155,31 +160,39 @@ class GameManager {
startFeedbackTimestamp = bootTime + CACurrentMediaTime()

let correctChoice = gameParameters.trials[countTest].correctChoice
let isCorrect = (button == .left && correctChoice == 0) || (button == .right && correctChoice == 1)
let isCorrect =
(button == .left && correctChoice == 0) || (button == .right && correctChoice == 1)
if isCorrect {
correctAnswers += 1
}

let buttonPressed = (button == .left) ? "0" : "1"
let model = FlankerModel(rt: resultTime,
stimulus: text,
button_pressed: buttonPressed,
image_time: endTrialTimestamp! * 1000,
correct: isCorrect,
start_timestamp: 0,
tag: Constants.tag,
trial_index: countTest + 1,
start_time: startTrialTimestamp * 1000,
response_touch_timestamp: respondTouchButton! * 1000)
let model = FlankerModel(
rt: resultTime,
stimulus: text,
button_pressed: buttonPressed,
image_time: endTrialTimestamp! * 1000,
correct: isCorrect,
start_timestamp: 0,
tag: Constants.tag,
trial_index: countTest + 1,
start_time: startTrialTimestamp * 1000,
response_touch_timestamp: respondTouchButton! * 1000)

resultManager.addStepData(data: model)
delegate?.resultTest(avrgTime: nil, procentCorrect: nil, data: model, dataArray: nil, isShowResults: false, minAccuracy: gameParameters.minimumAccuracy)
delegate?.resultTest(
avrgTime: nil, procentCorrect: nil, data: model, dataArray: nil, isShowResults: false,
minAccuracy: gameParameters.minimumAccuracy)

if gameParameters.showFeedback {
let feedbackText = isCorrect ? Constants.correctText : Constants.inCorrectText
let feedbackColor = isCorrect ? Constants.greenColor : Constants.redColor
delegate?.updateText(text: feedbackText, color: feedbackColor, font: Constants.smallFont, isStart: false, typeTime: .feedback)
let timer = Timer(timeInterval: Constants.lowTimeInterval, target: self, selector: #selector(setDefaultText), userInfo: nil, repeats: false)
delegate?.updateText(
text: feedbackText, color: feedbackColor, font: Constants.smallFont, isStart: false,
typeTime: .feedback)
let timer = Timer(
timeInterval: Constants.lowTimeInterval, target: self, selector: #selector(setDefaultText),
userInfo: nil, repeats: false)
RunLoop.main.add(timer, forMode: .common)
} else {
setDefaultText(isFirst: false)
Expand All @@ -189,9 +202,10 @@ class GameManager {
@objc func setDefaultText(isFirst: Bool) {
guard let gameParameters = gameParameters else { return }

hasRespondedInCurrentTrial = false
delegate?.setEnableButton(isEnable: false)

hasRespondedInCurrentTrial = false

if !isFirst {
endFeedbackTimestamp = bootTime + CACurrentMediaTime()
countTest += 1
Expand All @@ -208,12 +222,17 @@ class GameManager {

if gameParameters.showFixation {
startFixationsTimestamp = bootTime + CACurrentMediaTime()
if let image = URL(string: gameParameters.fixation), gameParameters.fixation.contains("https") {
if let image = URL(string: gameParameters.fixation), gameParameters.fixation.contains("https")
{
delegate?.updateFixations(image: image, isStart: true, typeTime: .fixations)
} else {
delegate?.updateText(text: gameParameters.fixation, color: .black, font: Constants.bigFont, isStart: true, typeTime: .fixations)
delegate?.updateText(
text: gameParameters.fixation, color: .black, font: Constants.bigFont, isStart: true,
typeTime: .fixations)
}
timerSetText = Timer(timeInterval: gameParameters.fixationDuration / 1000, target: self, selector: #selector(setText), userInfo: nil, repeats: false)
timerSetText = Timer(
timeInterval: gameParameters.fixationDuration / 1000, target: self,
selector: #selector(setText), userInfo: nil, repeats: false)
RunLoop.main.add(timerSetText!, forMode: .common)
} else {
setText()
Expand All @@ -223,27 +242,33 @@ class GameManager {
@objc func setText() {
guard let gameParameters = gameParameters else { return }
guard countTest < gameParameters.trials.count else {
handleEndOfGame()
return
handleEndOfGame()
return
}

endFixationsTimestamp = bootTime + CACurrentMediaTime()

startTrialTimestamp = bootTime + CACurrentMediaTime()

hasRespondedInCurrentTrial = false

text = gameParameters.trials[countTest].stimulus.en

if let image = URL(string: text), text.contains("https") {
delegate?.updateFixations(image: image, isStart: true, typeTime: .trial)
} else {
delegate?.updateText(text: text, color: .black, font: Constants.bigFont, isStart: true, typeTime: .trial)
delegate?.updateText(
text: text, color: .black, font: Constants.bigFont, isStart: true, typeTime: .trial)
}

DispatchQueue.main.asyncAfter(deadline: .now()) {
self.delegate?.setEnableButton(isEnable: true)
self.timeResponse = Timer(timeInterval: gameParameters.trialDuration / 1000, target: self, selector: #selector(self.timeResponseFailed), userInfo: nil, repeats: false)
RunLoop.main.add(self.timeResponse!, forMode: .common)
}
delegate?.setEnableButton(isEnable: true)

timeResponse = Timer(
timeInterval: gameParameters.trialDuration / 1000,
target: self,
selector: #selector(timeResponseFailed),
userInfo: nil,
repeats: false)
RunLoop.main.add(timeResponse!, forMode: .common)
}

@objc func timeResponseFailed() {
Expand All @@ -256,27 +281,34 @@ class GameManager {
startFeedbackTimestamp = bootTime + CACurrentMediaTime()

if gameParameters.showFeedback {
delegate?.updateText(text: Constants.timeRespondText, color: .black, font: Constants.smallFont, isStart: false, typeTime: .feedback)
delegate?.updateText(
text: Constants.timeRespondText, color: .black, font: Constants.smallFont, isStart: false,
typeTime: .feedback)
}

guard let startTrialTimestamp = startTrialTimestamp else { return }

let model = FlankerModel(rt: 0.0,
stimulus: text,
button_pressed: nil,
image_time: endTrialTimestamp! * 1000, // має намалювати
correct: false,
start_timestamp: 0, // вже намальовано
tag: Constants.tag,
trial_index: countTest + 1,
start_time: startTrialTimestamp * 1000,
response_touch_timestamp: 0)
let model = FlankerModel(
rt: 0.0,
stimulus: text,
button_pressed: nil,
image_time: endTrialTimestamp! * 1000, // має намалювати
correct: false,
start_timestamp: 0, // вже намальовано
tag: Constants.tag,
trial_index: countTest + 1,
start_time: startTrialTimestamp * 1000,
response_touch_timestamp: 0)

resultManager.addStepData(data: model)
delegate?.resultTest(avrgTime: nil, procentCorrect: nil, data: model, dataArray: nil,isShowResults: gameParameters.showResults, minAccuracy: gameParameters.minimumAccuracy)
delegate?.resultTest(
avrgTime: nil, procentCorrect: nil, data: model, dataArray: nil,
isShowResults: gameParameters.showResults, minAccuracy: gameParameters.minimumAccuracy)

if gameParameters.showFeedback {
let timer = Timer(timeInterval: Constants.lowTimeInterval, target: self, selector: #selector(setDefaultText), userInfo: nil, repeats: false)
let timer = Timer(
timeInterval: Constants.lowTimeInterval, target: self, selector: #selector(setDefaultText),
userInfo: nil, repeats: false)
RunLoop.main.add(timer, forMode: .common)
} else {
setDefaultText(isFirst: false)
Expand Down Expand Up @@ -314,6 +346,7 @@ class GameManager {
countTest = -1
correctAnswers = 0
arrayTimes = []
hasRespondedInCurrentTrial = false
invalidateTimers()
}

Expand All @@ -323,8 +356,8 @@ class GameManager {
}
}

private extension GameManager {
func updateButtonTitle() {
extension GameManager {
fileprivate func updateButtonTitle() {
guard let gameParameters = gameParameters else { return }
guard countTest < gameParameters.trials.count else { return }

Expand Down

0 comments on commit dd98685

Please sign in to comment.