Compare commits
7 Commits
09800c5b17
...
480404b21b
| Author | SHA1 | Date | |
|---|---|---|---|
| 480404b21b | |||
| 98a7d157f4 | |||
| 6e80a5986a | |||
| 86b5cabe17 | |||
| b693874f69 | |||
| 69a1c44ded | |||
| 9124a49887 |
@@ -71,7 +71,7 @@ enum QuizGenerator {
|
|||||||
let chars = Array(word)
|
let chars = Array(word)
|
||||||
let letterPositions = chars.indices.filter { chars[$0].isLetter }
|
let letterPositions = chars.indices.filter { chars[$0].isLetter }
|
||||||
guard !letterPositions.isEmpty else { return word }
|
guard !letterPositions.isEmpty else { return word }
|
||||||
let blankCount = min(letterPositions.count - 1, Int(ceil(Double(letterPositions.count) * 0.4)))
|
let blankCount = Int.random(in: 1...letterPositions.count)
|
||||||
let indices = Set(letterPositions.shuffled().prefix(blankCount))
|
let indices = Set(letterPositions.shuffled().prefix(blankCount))
|
||||||
return chars.enumerated().map { indices.contains($0.offset) ? "_" : String($0.element) }.joined()
|
return chars.enumerated().map { indices.contains($0.offset) ? "_" : String($0.element) }.joined()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,14 +36,26 @@ final class QuizViewController: UIViewController {
|
|||||||
target: nil,
|
target: nil,
|
||||||
action: nil
|
action: nil
|
||||||
)
|
)
|
||||||
|
private lazy var caseToggleItem = UIBarButtonItem(
|
||||||
|
title: "a", style: .plain, target: self, action: #selector(toggleCase)
|
||||||
|
)
|
||||||
|
|
||||||
private var current: QuizQuestion? {
|
private var current: QuizQuestion? {
|
||||||
questions.indices.contains(currentIndex) ? questions[currentIndex] : nil
|
questions.indices.contains(currentIndex) ? questions[currentIndex] : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var isUppercase: Bool
|
||||||
|
|
||||||
init(config: QuizConfig) {
|
init(config: QuizConfig) {
|
||||||
self.config = config
|
self.config = config
|
||||||
self.questions = QuizGenerator.makeQuestions(mode: config.mode, words: config.words)
|
let uppercase = UserDefaults.standard.bool(forKey: "spelling_uppercase")
|
||||||
|
self.isUppercase = uppercase
|
||||||
|
let words = config.words.map { word in
|
||||||
|
let text = uppercase ? word.word.uppercased() : word.word.lowercased()
|
||||||
|
return Word(word: text, phonetic: word.phonetic, meaning: word.meaning,
|
||||||
|
example: word.example, exampleMeaning: word.exampleMeaning)
|
||||||
|
}
|
||||||
|
self.questions = QuizGenerator.makeQuestions(mode: config.mode, words: words)
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +199,14 @@ final class QuizViewController: UIViewController {
|
|||||||
resultLabel.isHidden = true
|
resultLabel.isHidden = true
|
||||||
resultPhoneticLabel.isHidden = true
|
resultPhoneticLabel.isHidden = true
|
||||||
|
|
||||||
navigationItem.rightBarButtonItem = config.mode == .zhToEn ? nil : navSpeakerItem
|
if config.mode == .spelling {
|
||||||
|
updateCaseButton()
|
||||||
|
navigationItem.rightBarButtonItems = [navSpeakerItem, caseToggleItem]
|
||||||
|
} else if config.mode == .zhToEn {
|
||||||
|
navigationItem.rightBarButtonItems = nil
|
||||||
|
} else {
|
||||||
|
navigationItem.rightBarButtonItem = navSpeakerItem
|
||||||
|
}
|
||||||
|
|
||||||
let isSpelling = config.mode == .spelling
|
let isSpelling = config.mode == .spelling
|
||||||
let isDictation = config.mode == .dictation
|
let isDictation = config.mode == .dictation
|
||||||
@@ -331,7 +350,7 @@ final class QuizViewController: UIViewController {
|
|||||||
private func submitSpelling(_ typed: String, for question: QuizQuestion) {
|
private func submitSpelling(_ typed: String, for question: QuizQuestion) {
|
||||||
guard selectedOption == nil else { return }
|
guard selectedOption == nil else { return }
|
||||||
selectedOption = typed
|
selectedOption = typed
|
||||||
let correct = typed == question.answer
|
let correct = typed.lowercased() == question.answer.lowercased()
|
||||||
if !correct {
|
if !correct {
|
||||||
wrongWords.append(question.word)
|
wrongWords.append(question.word)
|
||||||
}
|
}
|
||||||
@@ -344,7 +363,7 @@ final class QuizViewController: UIViewController {
|
|||||||
private func submitDictation(_ typed: String, for question: QuizQuestion) {
|
private func submitDictation(_ typed: String, for question: QuizQuestion) {
|
||||||
guard selectedOption == nil else { return }
|
guard selectedOption == nil else { return }
|
||||||
selectedOption = typed
|
selectedOption = typed
|
||||||
let correct = typed == question.answer
|
let correct = typed.lowercased() == question.answer.lowercased()
|
||||||
if !correct {
|
if !correct {
|
||||||
wrongWords.append(question.word)
|
wrongWords.append(question.word)
|
||||||
}
|
}
|
||||||
@@ -390,6 +409,18 @@ final class QuizViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func toggleCase() {
|
||||||
|
isUppercase.toggle()
|
||||||
|
UserDefaults.standard.set(isUppercase, forKey: "spelling_uppercase")
|
||||||
|
updateCaseButton()
|
||||||
|
restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateCaseButton() {
|
||||||
|
caseToggleItem.title = isUppercase ? "A" : "a"
|
||||||
|
caseToggleItem.tintColor = .label
|
||||||
|
}
|
||||||
|
|
||||||
@objc private func speakCurrentWord() {
|
@objc private func speakCurrentWord() {
|
||||||
guard let question = current else { return }
|
guard let question = current else { return }
|
||||||
speech.speak(question.word.word)
|
speech.speak(question.word.word)
|
||||||
@@ -465,7 +496,12 @@ final class QuizViewController: UIViewController {
|
|||||||
countdownTimer?.invalidate()
|
countdownTimer?.invalidate()
|
||||||
countdownLabel.isHidden = true
|
countdownLabel.isHidden = true
|
||||||
view.subviews.compactMap { $0 as? QuizResultView }.forEach { $0.removeFromSuperview() }
|
view.subviews.compactMap { $0 as? QuizResultView }.forEach { $0.removeFromSuperview() }
|
||||||
questions = QuizGenerator.makeQuestions(mode: config.mode, words: config.words)
|
let words = config.words.map { word in
|
||||||
|
let text = isUppercase ? word.word.uppercased() : word.word.lowercased()
|
||||||
|
return Word(word: text, phonetic: word.phonetic, meaning: word.meaning,
|
||||||
|
example: word.example, exampleMeaning: word.exampleMeaning)
|
||||||
|
}
|
||||||
|
questions = QuizGenerator.makeQuestions(mode: config.mode, words: words)
|
||||||
currentIndex = 0
|
currentIndex = 0
|
||||||
wrongWords = []
|
wrongWords = []
|
||||||
startDate = .now
|
startDate = .now
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
|
|||||||
let box = makeBox(fontSize: fontSize)
|
let box = makeBox(fontSize: fontSize)
|
||||||
box.tag = index
|
box.tag = index
|
||||||
if ch != "_", let label = box.viewWithTag(100) as? UILabel {
|
if ch != "_", let label = box.viewWithTag(100) as? UILabel {
|
||||||
label.text = ch.uppercased()
|
label.text = ch
|
||||||
label.isHidden = false
|
label.isHidden = false
|
||||||
}
|
}
|
||||||
box.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(boxTapped(_:))))
|
box.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(boxTapped(_:))))
|
||||||
@@ -199,7 +199,7 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
|
|||||||
}
|
}
|
||||||
let label = box.viewWithTag(100) as? UILabel
|
let label = box.viewWithTag(100) as? UILabel
|
||||||
let filled = filledBlanks[blankIndex]
|
let filled = filledBlanks[blankIndex]
|
||||||
label?.text = filled.uppercased()
|
label?.text = filled
|
||||||
label?.isHidden = filled.isEmpty
|
label?.isHidden = filled.isEmpty
|
||||||
|
|
||||||
let isCurrent = inputEnabled && blankIndex == cursorIndex
|
let isCurrent = inputEnabled && blankIndex == cursorIndex
|
||||||
|
|||||||
Reference in New Issue
Block a user