Compare commits

..

4 Commits

Author SHA1 Message Date
fish c86e482e68 修复大小写切换后新输入字母不跟随转换,输入时根据当前大小写状态存储
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 22:46:18 +08:00
fish ccf0bc876b 大小写切换改为原地更新字符,不重建页面
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 22:41:04 +08:00
fish d14ae41706 大小写切换改为仅刷新当前字母显示,不再重置整个页面
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 22:35:26 +08:00
fish 2d8caf3550 单词详情页导航栏学习按钮与历史记录按钮位置互换
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 22:33:19 +08:00
4 changed files with 45 additions and 4 deletions
@@ -51,6 +51,27 @@ enum QuizGenerator {
}
}
static func recase(_ questions: [QuizQuestion], toUpper: Bool) -> [QuizQuestion] {
questions.map { q in
let word = q.word
let text = toUpper ? word.word.uppercased() : word.word.lowercased()
let recased = Word(categoryId: word.categoryId, word: text, phonetic: word.phonetic,
meaning: word.meaning, example: word.example, exampleMeaning: word.exampleMeaning)
let blanked = q.blankedWord.map { ch -> String in
ch == "_" ? "_" : ch.uppercased()
}.joined()
let blankedWord = toUpper ? blanked.uppercased() : blanked.lowercased()
return QuizQuestion(
word: recased,
prompt: q.prompt,
options: q.options,
answer: text,
blankedWord: blankedWord,
blankPositions: q.blankPositions
)
}
}
private static func promptText(_ word: Word, _ mode: QuizMode) -> String {
switch mode {
case .enToZh: return word.word
@@ -218,6 +218,7 @@ final class QuizViewController: UIViewController {
if isSpelling {
spellingHintLabel.text = "\(question.word.word.count) 个字母,补全空缺部分"
spellingView.isUppercase = isUppercase
spellingView.configure(blankedWord: question.blankedWord, blankPositions: question.blankPositions)
if config.isStudyMode {
nextButton.isHidden = true
@@ -425,7 +426,9 @@ final class QuizViewController: UIViewController {
isUppercase.toggle()
UserDefaults.standard.set(isUppercase, forKey: "spelling_uppercase")
updateCaseButton()
restart()
spellingView.isUppercase = isUppercase
questions = QuizGenerator.recase(questions, toUpper: isUppercase)
spellingView.updateCase(toUpper: isUppercase)
}
private func updateCaseButton() {
@@ -17,6 +17,8 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
private var cursorView: UIView?
private var inputEnabled = true
var isUppercase = false
var isComplete: Bool {
!filledBlanks.isEmpty && filledBlanks.allSatisfy { !$0.isEmpty }
}
@@ -133,6 +135,20 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
hiddenField.inputAccessoryView = nil
}
func updateCase(toUpper: Bool) {
chars = chars.map {
guard $0 != "_" else { return $0 }
return toUpper ? $0.uppercased() : $0.lowercased()
}
filledBlanks = filledBlanks.map {
$0.isEmpty ? $0 : (toUpper ? $0.uppercased() : $0.lowercased())
}
for (index, box) in boxViews.enumerated() where chars[index] != "_" {
(box.viewWithTag(100) as? UILabel)?.text = chars[index]
}
refreshBoxes()
}
func showResultState(correct: Bool) {
let color = correct ? Theme.Color.correct : Theme.Color.wrong
for position in blankPositions {
@@ -169,7 +185,8 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
onChange?()
}
} else if let char = string.last, char.isLetter, cursorIndex < blankPositions.count {
filledBlanks[cursorIndex] = String(char).lowercased()
let converted = isUppercase ? char.uppercased() : char.lowercased()
filledBlanks[cursorIndex] = converted
cursorIndex += 1
refreshBoxes()
popBox(atBlank: cursorIndex - 1)
@@ -32,8 +32,8 @@ final class WordDetailViewController: UIViewController {
title = categoryName
navigationItem.largeTitleDisplayMode = .never
navigationItem.rightBarButtonItems = [
UIBarButtonItem(image: UIImage(systemName: "clock.arrow.circlepath"), style: .plain, target: self, action: #selector(showHistory)),
UIBarButtonItem(title: "学习", style: .plain, target: self, action: #selector(startSpelling))
UIBarButtonItem(title: "学习", style: .plain, target: self, action: #selector(startSpelling)),
UIBarButtonItem(image: UIImage(systemName: "clock.arrow.circlepath"), style: .plain, target: self, action: #selector(showHistory))
]
buildLayout()
updateSpeakState()