Compare commits
2 Commits
5b2f51d140
...
75b967893b
| Author | SHA1 | Date | |
|---|---|---|---|
| 75b967893b | |||
| cb37b809f0 |
@@ -0,0 +1,115 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum NumberWords {
|
||||||
|
static let range = 1...999
|
||||||
|
|
||||||
|
private static let atomNumbers: [String: Int] = [
|
||||||
|
"one": 1, "two": 2, "three": 3, "four": 4, "five": 5,
|
||||||
|
"six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10,
|
||||||
|
"eleven": 11, "twelve": 12, "thirteen": 13, "fourteen": 14, "fifteen": 15,
|
||||||
|
"sixteen": 16, "seventeen": 17, "eighteen": 18, "nineteen": 19, "twenty": 20,
|
||||||
|
"thirty": 30, "forty": 40, "fifty": 50, "sixty": 60,
|
||||||
|
"seventy": 70, "eighty": 80, "ninety": 90, "hundred": 100
|
||||||
|
]
|
||||||
|
|
||||||
|
private static let ones = [
|
||||||
|
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
|
||||||
|
"eleven", "twelve", "thirteen", "fourteen", "fifteen",
|
||||||
|
"sixteen", "seventeen", "eighteen", "nineteen"
|
||||||
|
]
|
||||||
|
|
||||||
|
private static let onesPhonetics = [
|
||||||
|
"wʌn", "tuː", "θriː", "fɔːr", "faɪv", "sɪks", "ˈsevn", "eɪt", "naɪn", "ten",
|
||||||
|
"ɪˈlevn", "twelv", "ˌθɜːrˈtiːn", "ˌfɔːrˈtiːn", "ˌfɪfˈtiːn",
|
||||||
|
"ˌsɪksˈtiːn", "ˌsevnˈtiːn", "ˌeɪˈtiːn", "ˌnaɪnˈtiːn"
|
||||||
|
]
|
||||||
|
|
||||||
|
private static let tens: [Int: String] = [
|
||||||
|
20: "twenty", 30: "thirty", 40: "forty", 50: "fifty",
|
||||||
|
60: "sixty", 70: "seventy", 80: "eighty", 90: "ninety"
|
||||||
|
]
|
||||||
|
|
||||||
|
private static let tensPhonetics: [Int: String] = [
|
||||||
|
20: "ˈtwenti", 30: "ˈθɜːrti", 40: "ˈfɔːrti", 50: "ˈfɪfti",
|
||||||
|
60: "ˈsɪksti", 70: "ˈsevnti", 80: "ˈeɪti", 90: "ˈnaɪnti"
|
||||||
|
]
|
||||||
|
|
||||||
|
static func makeWords(atoms: [Word]) -> [Word] {
|
||||||
|
var byNumber: [Int: Word] = [:]
|
||||||
|
for atom in atoms {
|
||||||
|
if let number = atomNumbers[atom.word] {
|
||||||
|
byNumber[number] = atom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return range.map { byNumber[$0] ?? makeWord($0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static func english(_ n: Int) -> String {
|
||||||
|
switch n {
|
||||||
|
case 1...19:
|
||||||
|
return ones[n - 1]
|
||||||
|
case 20...99:
|
||||||
|
let ten = n / 10 * 10
|
||||||
|
let one = n % 10
|
||||||
|
return one == 0 ? tens[ten]! : "\(tens[ten]!)-\(ones[one - 1])"
|
||||||
|
case 100...999:
|
||||||
|
let head = "\(ones[n / 100 - 1]) hundred"
|
||||||
|
let rest = n % 100
|
||||||
|
return rest == 0 ? head : "\(head) \(english(rest))"
|
||||||
|
default:
|
||||||
|
return "\(n)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func phonetic(_ n: Int) -> String {
|
||||||
|
switch n {
|
||||||
|
case 1...19:
|
||||||
|
return onesPhonetics[n - 1]
|
||||||
|
case 20...99:
|
||||||
|
let ten = n / 10 * 10
|
||||||
|
let one = n % 10
|
||||||
|
return one == 0 ? tensPhonetics[ten]! : "\(tensPhonetics[ten]!) \(onesPhonetics[one - 1])"
|
||||||
|
case 100...999:
|
||||||
|
let head = "\(onesPhonetics[n / 100 - 1]) ˈhʌndrəd"
|
||||||
|
let rest = n % 100
|
||||||
|
return rest == 0 ? head : "\(head) \(phonetic(rest))"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func chinese(_ n: Int) -> String {
|
||||||
|
let digits = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
|
||||||
|
switch n {
|
||||||
|
case 0...9:
|
||||||
|
return digits[n]
|
||||||
|
case 10...19:
|
||||||
|
return "十" + (n % 10 == 0 ? "" : digits[n % 10])
|
||||||
|
case 20...99:
|
||||||
|
return digits[n / 10] + "十" + (n % 10 == 0 ? "" : digits[n % 10])
|
||||||
|
case 100...999:
|
||||||
|
let head = digits[n / 100] + "百"
|
||||||
|
let rest = n % 100
|
||||||
|
switch rest {
|
||||||
|
case 0:
|
||||||
|
return head
|
||||||
|
case 1...9:
|
||||||
|
return head + "零" + digits[rest]
|
||||||
|
case 10...19:
|
||||||
|
return head + "一十" + (rest % 10 == 0 ? "" : digits[rest % 10])
|
||||||
|
default:
|
||||||
|
return head + digits[rest / 10] + "十" + (rest % 10 == 0 ? "" : digits[rest % 10])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "\(n)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func makeWord(_ n: Int) -> Word {
|
||||||
|
Word(word: english(n),
|
||||||
|
phonetic: "/\(phonetic(n))/",
|
||||||
|
meaning: chinese(n),
|
||||||
|
example: "I can count to \(english(n)).",
|
||||||
|
exampleMeaning: "我能数到\(chinese(n))。")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,10 +62,10 @@ enum QuizGenerator {
|
|||||||
|
|
||||||
private static func blankWord(_ word: String) -> String {
|
private static func blankWord(_ word: String) -> String {
|
||||||
let chars = Array(word)
|
let chars = Array(word)
|
||||||
let count = chars.count
|
let letterPositions = chars.indices.filter { chars[$0].isLetter }
|
||||||
guard count > 2 else { return String(repeating: "_", count: count) }
|
guard letterPositions.count > 2 else { return String(repeating: "_", count: chars.count) }
|
||||||
let blanks = max(1, Int(Double(count) * 0.4))
|
let blanks = max(1, Int(Double(letterPositions.count) * 0.4))
|
||||||
let indices = Set(Array(0..<count).shuffled().prefix(blanks))
|
let indices = Set(letterPositions.shuffled().prefix(blanks))
|
||||||
return chars.enumerated().map { indices.contains($0.offset) ? "_" : String($0.element) }.joined()
|
return chars.enumerated().map { indices.contains($0.offset) ? "_" : String($0.element) }.joined()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,27 @@
|
|||||||
{ "word": "mouse", "phonetic": "/maʊs/", "meaning": "老鼠", "example": "The mouse likes cheese.", "exampleMeaning": "老鼠喜欢奶酪。" },
|
{ "word": "mouse", "phonetic": "/maʊs/", "meaning": "老鼠", "example": "The mouse likes cheese.", "exampleMeaning": "老鼠喜欢奶酪。" },
|
||||||
{ "word": "snake", "phonetic": "/sneɪk/", "meaning": "蛇", "example": "The snake has no legs.", "exampleMeaning": "蛇没有腿。" },
|
{ "word": "snake", "phonetic": "/sneɪk/", "meaning": "蛇", "example": "The snake has no legs.", "exampleMeaning": "蛇没有腿。" },
|
||||||
{ "word": "frog", "phonetic": "/frɔːɡ/", "meaning": "青蛙", "example": "The frog can jump high.", "exampleMeaning": "青蛙能跳得很高。" },
|
{ "word": "frog", "phonetic": "/frɔːɡ/", "meaning": "青蛙", "example": "The frog can jump high.", "exampleMeaning": "青蛙能跳得很高。" },
|
||||||
{ "word": "bear", "phonetic": "/ber/", "meaning": "熊", "example": "The bear sleeps in winter.", "exampleMeaning": "熊在冬天睡觉。" }
|
{ "word": "bear", "phonetic": "/ber/", "meaning": "熊", "example": "The bear sleeps in winter.", "exampleMeaning": "熊在冬天睡觉。" },
|
||||||
|
{ "word": "giraffe", "phonetic": "/dʒəˈræf/", "meaning": "长颈鹿", "example": "The giraffe is tall.", "exampleMeaning": "长颈鹿很高。" },
|
||||||
|
{ "word": "zebra", "phonetic": "/ˈziːbrə/", "meaning": "斑马", "example": "The zebra has stripes.", "exampleMeaning": "斑马身上有条纹。" },
|
||||||
|
{ "word": "wolf", "phonetic": "/wʊlf/", "meaning": "狼", "example": "The wolf howls at night.", "exampleMeaning": "狼在夜里嚎叫。" },
|
||||||
|
{ "word": "fox", "phonetic": "/fɑːks/", "meaning": "狐狸", "example": "The fox is clever.", "exampleMeaning": "狐狸很聪明。" },
|
||||||
|
{ "word": "deer", "phonetic": "/dɪr/", "meaning": "鹿", "example": "The deer runs fast.", "exampleMeaning": "鹿跑得很快。" },
|
||||||
|
{ "word": "squirrel", "phonetic": "/ˈskwɜːrəl/", "meaning": "松鼠", "example": "The squirrel likes nuts.", "exampleMeaning": "松鼠喜欢坚果。" },
|
||||||
|
{ "word": "penguin", "phonetic": "/ˈpeŋɡwɪn/", "meaning": "企鹅", "example": "The penguin cannot fly.", "exampleMeaning": "企鹅不会飞。" },
|
||||||
|
{ "word": "dolphin", "phonetic": "/ˈdɑːlfɪn/", "meaning": "海豚", "example": "The dolphin swims fast.", "exampleMeaning": "海豚游得很快。" },
|
||||||
|
{ "word": "whale", "phonetic": "/weɪl/", "meaning": "鲸鱼", "example": "The whale is very big.", "exampleMeaning": "鲸鱼非常大。" },
|
||||||
|
{ "word": "shark", "phonetic": "/ʃɑːrk/", "meaning": "鲨鱼", "example": "The shark has sharp teeth.", "exampleMeaning": "鲨鱼有锋利的牙齿。" },
|
||||||
|
{ "word": "turtle", "phonetic": "/ˈtɜːrtl/", "meaning": "乌龟", "example": "The turtle walks slowly.", "exampleMeaning": "乌龟走得很慢。" },
|
||||||
|
{ "word": "owl", "phonetic": "/aʊl/", "meaning": "猫头鹰", "example": "The owl sleeps in the day.", "exampleMeaning": "猫头鹰白天睡觉。" },
|
||||||
|
{ "word": "bee", "phonetic": "/biː/", "meaning": "蜜蜂", "example": "The bee makes honey.", "exampleMeaning": "蜜蜂酿蜜。" },
|
||||||
|
{ "word": "butterfly", "phonetic": "/ˈbʌtərflaɪ/", "meaning": "蝴蝶", "example": "The butterfly is beautiful.", "exampleMeaning": "蝴蝶很漂亮。" },
|
||||||
|
{ "word": "ant", "phonetic": "/ænt/", "meaning": "蚂蚁", "example": "The ant carries food.", "exampleMeaning": "蚂蚁搬运食物。" },
|
||||||
|
{ "word": "spider", "phonetic": "/ˈspaɪdər/", "meaning": "蜘蛛", "example": "The spider makes a web.", "exampleMeaning": "蜘蛛织网。" },
|
||||||
|
{ "word": "kangaroo", "phonetic": "/ˌkæŋɡəˈruː/", "meaning": "袋鼠", "example": "The kangaroo jumps high.", "exampleMeaning": "袋鼠跳得很高。" },
|
||||||
|
{ "word": "koala", "phonetic": "/koʊˈɑːlə/", "meaning": "考拉", "example": "The koala sleeps a lot.", "exampleMeaning": "考拉睡很多觉。" },
|
||||||
|
{ "word": "crocodile", "phonetic": "/ˈkrɑːkədaɪl/", "meaning": "鳄鱼", "example": "The crocodile has a big mouth.", "exampleMeaning": "鳄鱼有一张大嘴。" },
|
||||||
|
{ "word": "camel", "phonetic": "/ˈkæml/", "meaning": "骆驼", "example": "The camel lives in the desert.", "exampleMeaning": "骆驼生活在沙漠里。" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -99,7 +119,27 @@
|
|||||||
{ "word": "fig", "phonetic": "/fɪɡ/", "meaning": "无花果", "example": "Figs are sweet.", "exampleMeaning": "无花果很甜。" },
|
{ "word": "fig", "phonetic": "/fɪɡ/", "meaning": "无花果", "example": "Figs are sweet.", "exampleMeaning": "无花果很甜。" },
|
||||||
{ "word": "blueberry", "phonetic": "/ˈbluːberi/", "meaning": "蓝莓", "example": "Blueberries are good for eyes.", "exampleMeaning": "蓝莓对眼睛有好处。" },
|
{ "word": "blueberry", "phonetic": "/ˈbluːberi/", "meaning": "蓝莓", "example": "Blueberries are good for eyes.", "exampleMeaning": "蓝莓对眼睛有好处。" },
|
||||||
{ "word": "pomegranate", "phonetic": "/ˈpɑːmɪɡrænɪt/", "meaning": "石榴", "example": "The pomegranate has many seeds.", "exampleMeaning": "石榴有很多籽。" },
|
{ "word": "pomegranate", "phonetic": "/ˈpɑːmɪɡrænɪt/", "meaning": "石榴", "example": "The pomegranate has many seeds.", "exampleMeaning": "石榴有很多籽。" },
|
||||||
{ "word": "papaya", "phonetic": "/pəˈpaɪə/", "meaning": "木瓜", "example": "The papaya is orange inside.", "exampleMeaning": "木瓜里面是橙色的。" }
|
{ "word": "papaya", "phonetic": "/pəˈpaɪə/", "meaning": "木瓜", "example": "The papaya is orange inside.", "exampleMeaning": "木瓜里面是橙色的。" },
|
||||||
|
{ "word": "dragon fruit", "phonetic": "/ˈdræɡən fruːt/", "meaning": "火龙果", "example": "The dragon fruit is pink.", "exampleMeaning": "火龙果是粉色的。" },
|
||||||
|
{ "word": "durian", "phonetic": "/ˈdʊriən/", "meaning": "榴莲", "example": "The durian smells strong.", "exampleMeaning": "榴莲气味很浓。" },
|
||||||
|
{ "word": "lychee", "phonetic": "/ˈliːtʃiː/", "meaning": "荔枝", "example": "The lychee is sweet.", "exampleMeaning": "荔枝很甜。" },
|
||||||
|
{ "word": "longan", "phonetic": "/ˈlɔːŋɡən/", "meaning": "龙眼", "example": "The longan is small and sweet.", "exampleMeaning": "龙眼又小又甜。" },
|
||||||
|
{ "word": "mangosteen", "phonetic": "/ˈmæŋɡəstiːn/", "meaning": "山竹", "example": "The mangosteen is white inside.", "exampleMeaning": "山竹里面是白色的。" },
|
||||||
|
{ "word": "passion fruit", "phonetic": "/ˈpæʃn fruːt/", "meaning": "百香果", "example": "The passion fruit is sour.", "exampleMeaning": "百香果是酸的。" },
|
||||||
|
{ "word": "starfruit", "phonetic": "/ˈstɑːrfruːt/", "meaning": "杨桃", "example": "The starfruit looks like a star.", "exampleMeaning": "杨桃看起来像星星。" },
|
||||||
|
{ "word": "grapefruit", "phonetic": "/ˈɡreɪpfruːt/", "meaning": "西柚", "example": "The grapefruit is sour.", "exampleMeaning": "西柚是酸的。" },
|
||||||
|
{ "word": "cantaloupe", "phonetic": "/ˈkæntəloʊp/", "meaning": "哈密瓜", "example": "The cantaloupe is sweet.", "exampleMeaning": "哈密瓜很甜。" },
|
||||||
|
{ "word": "honeydew", "phonetic": "/ˈhʌniduː/", "meaning": "蜜瓜", "example": "The honeydew is green.", "exampleMeaning": "蜜瓜是绿色的。" },
|
||||||
|
{ "word": "raspberry", "phonetic": "/ˈræzberi/", "meaning": "树莓", "example": "The raspberry is red.", "exampleMeaning": "树莓是红色的。" },
|
||||||
|
{ "word": "blackberry", "phonetic": "/ˈblækberi/", "meaning": "黑莓", "example": "The blackberry is dark.", "exampleMeaning": "黑莓是深色的。" },
|
||||||
|
{ "word": "cranberry", "phonetic": "/ˈkrænberi/", "meaning": "蔓越莓", "example": "The cranberry is sour.", "exampleMeaning": "蔓越莓是酸的。" },
|
||||||
|
{ "word": "persimmon", "phonetic": "/pərˈsɪmən/", "meaning": "柿子", "example": "The persimmon is orange.", "exampleMeaning": "柿子是橙色的。" },
|
||||||
|
{ "word": "loquat", "phonetic": "/ˈloʊkwɑːt/", "meaning": "枇杷", "example": "The loquat is yellow.", "exampleMeaning": "枇杷是黄色的。" },
|
||||||
|
{ "word": "guava", "phonetic": "/ˈɡwɑːvə/", "meaning": "番石榴", "example": "The guava is green.", "exampleMeaning": "番石榴是绿色的。" },
|
||||||
|
{ "word": "jackfruit", "phonetic": "/ˈdʒækfruːt/", "meaning": "菠萝蜜", "example": "The jackfruit is very big.", "exampleMeaning": "菠萝蜜非常大。" },
|
||||||
|
{ "word": "avocado", "phonetic": "/ˌævəˈkɑːdoʊ/", "meaning": "牛油果", "example": "The avocado is green.", "exampleMeaning": "牛油果是绿色的。" },
|
||||||
|
{ "word": "tangerine", "phonetic": "/ˌtændʒəˈriːn/", "meaning": "橘子", "example": "The tangerine is easy to peel.", "exampleMeaning": "橘子很好剥皮。" },
|
||||||
|
{ "word": "bayberry", "phonetic": "/ˈbeɪberi/", "meaning": "杨梅", "example": "The bayberry is red and sour.", "exampleMeaning": "杨梅又红又酸。" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -126,7 +166,15 @@
|
|||||||
{ "word": "seventeen", "phonetic": "/ˌsevnˈtiːn/", "meaning": "十七", "example": "He got seventeen points.", "exampleMeaning": "他得了十七分。" },
|
{ "word": "seventeen", "phonetic": "/ˌsevnˈtiːn/", "meaning": "十七", "example": "He got seventeen points.", "exampleMeaning": "他得了十七分。" },
|
||||||
{ "word": "eighteen", "phonetic": "/ˌeɪˈtiːn/", "meaning": "十八", "example": "She is eighteen years old.", "exampleMeaning": "她十八岁。" },
|
{ "word": "eighteen", "phonetic": "/ˌeɪˈtiːn/", "meaning": "十八", "example": "She is eighteen years old.", "exampleMeaning": "她十八岁。" },
|
||||||
{ "word": "nineteen", "phonetic": "/ˌnaɪnˈtiːn/", "meaning": "十九", "example": "Nineteen people came to the party.", "exampleMeaning": "十九个人来参加了聚会。" },
|
{ "word": "nineteen", "phonetic": "/ˌnaɪnˈtiːn/", "meaning": "十九", "example": "Nineteen people came to the party.", "exampleMeaning": "十九个人来参加了聚会。" },
|
||||||
{ "word": "twenty", "phonetic": "/ˈtwenti/", "meaning": "二十", "example": "I have twenty yuan.", "exampleMeaning": "我有二十元。" }
|
{ "word": "twenty", "phonetic": "/ˈtwenti/", "meaning": "二十", "example": "I have twenty yuan.", "exampleMeaning": "我有二十元。" },
|
||||||
|
{ "word": "thirty", "phonetic": "/ˈθɜːrti/", "meaning": "三十", "example": "She has thirty stamps.", "exampleMeaning": "她有三十张邮票。" },
|
||||||
|
{ "word": "forty", "phonetic": "/ˈfɔːrti/", "meaning": "四十", "example": "There are forty students.", "exampleMeaning": "有四十个学生。" },
|
||||||
|
{ "word": "fifty", "phonetic": "/ˈfɪfti/", "meaning": "五十", "example": "My grandfather is fifty.", "exampleMeaning": "我爷爷五十岁。" },
|
||||||
|
{ "word": "sixty", "phonetic": "/ˈsɪksti/", "meaning": "六十", "example": "An hour has sixty minutes.", "exampleMeaning": "一小时有六十分钟。" },
|
||||||
|
{ "word": "seventy", "phonetic": "/ˈsevnti/", "meaning": "七十", "example": "My grandmother is seventy.", "exampleMeaning": "我奶奶七十岁。" },
|
||||||
|
{ "word": "eighty", "phonetic": "/ˈeɪti/", "meaning": "八十", "example": "He can count to eighty.", "exampleMeaning": "他能数到八十。" },
|
||||||
|
{ "word": "ninety", "phonetic": "/ˈnaɪnti/", "meaning": "九十", "example": "The book has ninety pages.", "exampleMeaning": "这本书有九十页。" },
|
||||||
|
{ "word": "hundred", "phonetic": "/ˈhʌndrəd/", "meaning": "百", "example": "One hundred people came.", "exampleMeaning": "来了一百个人。" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,13 @@ final class WordStore {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
let data = try Data(contentsOf: url)
|
let data = try Data(contentsOf: url)
|
||||||
bank = try JSONDecoder().decode(WordBank.self, from: data)
|
let decoded = try JSONDecoder().decode(WordBank.self, from: data)
|
||||||
|
let categories = decoded.categories.map { category -> WordCategory in
|
||||||
|
guard category.id == "numbers" else { return category }
|
||||||
|
return WordCategory(id: category.id, name: category.name, icon: category.icon,
|
||||||
|
words: NumberWords.makeWords(atoms: category.words))
|
||||||
|
}
|
||||||
|
bank = WordBank(version: decoded.version, categories: categories)
|
||||||
} catch {
|
} catch {
|
||||||
loadError = WordStoreError.decodingFailed(error).localizedDescription
|
loadError = WordStoreError.decodingFailed(error).localizedDescription
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,9 +162,14 @@ final class QuizSetupViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func setupCountControl() {
|
private func setupCountControl() {
|
||||||
countControl.insertSegment(withTitle: "全部 \(request.words.count) 题", at: 0, animated: false)
|
if request.words.count > 50 {
|
||||||
if request.words.count > 10 {
|
countControl.insertSegment(withTitle: "随机 10 题", at: 0, animated: false)
|
||||||
countControl.insertSegment(withTitle: "随机 10 题", at: 1, animated: false)
|
countControl.insertSegment(withTitle: "随机 20 题", at: 1, animated: false)
|
||||||
|
} else {
|
||||||
|
countControl.insertSegment(withTitle: "全部 \(request.words.count) 题", at: 0, animated: false)
|
||||||
|
if request.words.count > 10 {
|
||||||
|
countControl.insertSegment(withTitle: "随机 10 题", at: 1, animated: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
countControl.selectedSegmentIndex = 0
|
countControl.selectedSegmentIndex = 0
|
||||||
}
|
}
|
||||||
@@ -198,9 +203,15 @@ final class QuizSetupViewController: UIViewController {
|
|||||||
private func startQuiz() {
|
private func startQuiz() {
|
||||||
guard let selectedIndex else { return }
|
guard let selectedIndex else { return }
|
||||||
Haptics.selection()
|
Haptics.selection()
|
||||||
let words = countControl.selectedSegmentIndex == 0
|
let words: [Word]
|
||||||
? request.words
|
if request.words.count > 50 {
|
||||||
: Array(request.words.shuffled().prefix(10))
|
let count = countControl.selectedSegmentIndex == 0 ? 10 : 20
|
||||||
|
words = Array(request.words.shuffled().prefix(count))
|
||||||
|
} else if countControl.selectedSegmentIndex == 0 {
|
||||||
|
words = request.words
|
||||||
|
} else {
|
||||||
|
words = Array(request.words.shuffled().prefix(10))
|
||||||
|
}
|
||||||
let config = QuizConfig(mode: items[selectedIndex].mode, words: words)
|
let config = QuizConfig(mode: items[selectedIndex].mode, words: words)
|
||||||
navigationController?.pushViewController(QuizViewController(config: config), animated: true)
|
navigationController?.pushViewController(QuizViewController(config: config), animated: true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,8 +126,19 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
|
|||||||
|
|
||||||
private func rebuildBoxes() {
|
private func rebuildBoxes() {
|
||||||
stack.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
stack.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||||
|
let count = CGFloat(max(chars.count, 1))
|
||||||
|
let available = (window?.screen.bounds.width ?? 390) - 32
|
||||||
|
var spacing: CGFloat = 6
|
||||||
|
var boxWidth = (available - spacing * (count - 1)) / count
|
||||||
|
if boxWidth < 16 {
|
||||||
|
spacing = 3
|
||||||
|
boxWidth = (available - spacing * (count - 1)) / count
|
||||||
|
}
|
||||||
|
boxWidth = min(36, boxWidth)
|
||||||
|
stack.spacing = spacing
|
||||||
|
let fontSize = min(22, max(12, boxWidth * 0.62))
|
||||||
boxViews = chars.enumerated().map { index, ch in
|
boxViews = chars.enumerated().map { index, ch in
|
||||||
let box = makeBox()
|
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.uppercased()
|
||||||
@@ -136,7 +147,7 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
|
|||||||
box.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(boxTapped(_:))))
|
box.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(boxTapped(_:))))
|
||||||
stack.addArrangedSubview(box)
|
stack.addArrangedSubview(box)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
box.widthAnchor.constraint(equalToConstant: 36),
|
box.widthAnchor.constraint(equalToConstant: boxWidth),
|
||||||
box.heightAnchor.constraint(equalToConstant: 44)
|
box.heightAnchor.constraint(equalToConstant: 44)
|
||||||
])
|
])
|
||||||
return box
|
return box
|
||||||
@@ -158,7 +169,7 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
|
|||||||
activate()
|
activate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeBox() -> UIView {
|
private func makeBox(fontSize: CGFloat) -> UIView {
|
||||||
let box = UIView()
|
let box = UIView()
|
||||||
box.backgroundColor = .quaternarySystemFill.withAlphaComponent(0.15)
|
box.backgroundColor = .quaternarySystemFill.withAlphaComponent(0.15)
|
||||||
box.layer.cornerRadius = 8
|
box.layer.cornerRadius = 8
|
||||||
@@ -166,8 +177,7 @@ final class SpellingInputView: UIView, UITextFieldDelegate {
|
|||||||
box.layer.borderColor = UIColor.separator.cgColor
|
box.layer.borderColor = UIColor.separator.cgColor
|
||||||
|
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .preferredFont(forTextStyle: .title2)
|
label.font = .systemFont(ofSize: fontSize, weight: .bold)
|
||||||
label.font = .systemFont(ofSize: label.font.pointSize, weight: .bold)
|
|
||||||
label.isHidden = true
|
label.isHidden = true
|
||||||
label.tag = 100
|
label.tag = 100
|
||||||
box.addSubview(label)
|
box.addSubview(label)
|
||||||
|
|||||||
Reference in New Issue
Block a user