diff --git a/LearnEnglish/LearnEnglish/Models/Word.swift b/LearnEnglish/LearnEnglish/Models/Word.swift index f4cb0f8..16398ce 100644 --- a/LearnEnglish/LearnEnglish/Models/Word.swift +++ b/LearnEnglish/LearnEnglish/Models/Word.swift @@ -9,6 +9,12 @@ struct WordCategory: Codable, Identifiable, Hashable { let id: String let name: String let icon: String + var words: [Word] + var subcategories: [Subcategory]? +} + +struct Subcategory: Codable, Hashable { + let name: String let words: [Word] } diff --git a/LearnEnglish/LearnEnglish/Resources/words.json b/LearnEnglish/LearnEnglish/Resources/words.json index 78292f2..45c527f 100644 --- a/LearnEnglish/LearnEnglish/Resources/words.json +++ b/LearnEnglish/LearnEnglish/Resources/words.json @@ -290,48 +290,89 @@ "id": "food_drink", "name": "饮食", "icon": "fork.knife", - "words": [ - { "word": "rice", "phonetic": "/raɪs/", "meaning": "米饭", "example": "I eat rice every day.", "exampleMeaning": "我每天吃米饭。" }, - { "word": "bread", "phonetic": "/bred/", "meaning": "面包", "example": "I have bread for breakfast.", "exampleMeaning": "我早餐吃面包。" }, - { "word": "noodle", "phonetic": "/ˈnuːdl/", "meaning": "面条", "example": "I like beef noodles.", "exampleMeaning": "我喜欢牛肉面。" }, - { "word": "dumpling", "phonetic": "/ˈdʌmplɪŋ/", "meaning": "饺子", "example": "We make dumplings together.", "exampleMeaning": "我们一起包饺子。" }, - { "word": "egg", "phonetic": "/eɡ/", "meaning": "鸡蛋", "example": "I have an egg for breakfast.", "exampleMeaning": "我早餐吃一个鸡蛋。" }, - { "word": "meat", "phonetic": "/miːt/", "meaning": "肉", "example": "I like to eat meat.", "exampleMeaning": "我喜欢吃肉。" }, - { "word": "beef", "phonetic": "/biːf/", "meaning": "牛肉", "example": "The beef is tender.", "exampleMeaning": "牛肉很嫩。" }, - { "word": "pork", "phonetic": "/pɔːrk/", "meaning": "猪肉", "example": "I don't eat pork.", "exampleMeaning": "我不吃猪肉。" }, - { "word": "chicken", "phonetic": "/ˈtʃɪkɪn/", "meaning": "鸡肉", "example": "Fried chicken is popular.", "exampleMeaning": "炸鸡很受欢迎。" }, - { "word": "vegetable", "phonetic": "/ˈvedʒtəbl/", "meaning": "蔬菜", "example": "Eat more vegetables.", "exampleMeaning": "多吃蔬菜。" }, - { "word": "carrot", "phonetic": "/ˈkærət/", "meaning": "胡萝卜", "example": "Rabbits like carrots.", "exampleMeaning": "兔子喜欢胡萝卜。" }, - { "word": "tomato", "phonetic": "/təˈmeɪtoʊ/", "meaning": "番茄", "example": "The tomato is red.", "exampleMeaning": "番茄是红色的。" }, - { "word": "potato", "phonetic": "/pəˈteɪtoʊ/", "meaning": "土豆", "example": "Potatoes grow underground.", "exampleMeaning": "土豆长在地下。" }, - { "word": "onion", "phonetic": "/ˈʌnjən/", "meaning": "洋葱", "example": "The onion makes me cry.", "exampleMeaning": "洋葱让我流泪。" }, - { "word": "cucumber", "phonetic": "/ˈkjuːkʌmbər/", "meaning": "黄瓜", "example": "The cucumber is fresh.", "exampleMeaning": "黄瓜很新鲜。" }, - { "word": "cabbage", "phonetic": "/ˈkæbɪdʒ/", "meaning": "卷心菜", "example": "Cabbage is good for health.", "exampleMeaning": "卷心菜对健康有好处。" }, - { "word": "water", "phonetic": "/ˈwɔːtər/", "meaning": "水", "example": "I drink water every day.", "exampleMeaning": "我每天喝水。" }, - { "word": "milk", "phonetic": "/mɪlk/", "meaning": "牛奶", "example": "I drink a glass of milk.", "exampleMeaning": "我喝一杯牛奶。" }, - { "word": "juice", "phonetic": "/dʒuːs/", "meaning": "果汁", "example": "Orange juice is sweet.", "exampleMeaning": "橙汁很甜。" }, - { "word": "tea", "phonetic": "/tiː/", "meaning": "茶", "example": "I drink tea in the afternoon.", "exampleMeaning": "我下午喝茶。" }, - { "word": "coffee", "phonetic": "/ˈkɔːfi/", "meaning": "咖啡", "example": "I need a cup of coffee.", "exampleMeaning": "我需要一杯咖啡。" }, - { "word": "beer", "phonetic": "/bɪr/", "meaning": "啤酒", "example": "He drinks beer with friends.", "exampleMeaning": "他和朋友喝啤酒。" }, - { "word": "wine", "phonetic": "/waɪn/", "meaning": "葡萄酒", "example": "Red wine is good for health.", "exampleMeaning": "红酒对健康有好处。" }, - { "word": "salt", "phonetic": "/sɔːlt/", "meaning": "盐", "example": "Don't add too much salt.", "exampleMeaning": "不要加太多盐。" }, - { "word": "sugar", "phonetic": "/ˈʃʊɡər/", "meaning": "糖", "example": "I put sugar in my coffee.", "exampleMeaning": "我在咖啡里加糖。" }, - { "word": "oil", "phonetic": "/ɔɪl/", "meaning": "油", "example": "Add some oil to the pan.", "exampleMeaning": "往锅里加点油。" }, - { "word": "sauce", "phonetic": "/sɔːs/", "meaning": "酱", "example": "The sauce is delicious.", "exampleMeaning": "这个酱很好吃。" }, - { "word": "breakfast", "phonetic": "/ˈbrekfəst/", "meaning": "早餐", "example": "Breakfast is the most important meal.", "exampleMeaning": "早餐是最重要的一餐。" }, - { "word": "lunch", "phonetic": "/lʌntʃ/", "meaning": "午餐", "example": "I have lunch at twelve.", "exampleMeaning": "我十二点吃午餐。" }, - { "word": "dinner", "phonetic": "/ˈdɪnər/", "meaning": "晚餐", "example": "We have dinner at six.", "exampleMeaning": "我们六点吃晚餐。" }, - { "word": "soup", "phonetic": "/suːp/", "meaning": "汤", "example": "The soup is hot.", "exampleMeaning": "汤是热的。" }, - { "word": "cake", "phonetic": "/keɪk/", "meaning": "蛋糕", "example": "I like chocolate cake.", "exampleMeaning": "我喜欢巧克力蛋糕。" }, - { "word": "cookie", "phonetic": "/ˈkʊki/", "meaning": "饼干", "example": "The cookie is crunchy.", "exampleMeaning": "饼干很脆。" }, - { "word": "ice cream", "phonetic": "/ˌaɪs ˈkriːm/", "meaning": "冰淇淋", "example": "Ice cream is cold and sweet.", "exampleMeaning": "冰淇淋又冰又甜。" }, - { "word": "chocolate", "phonetic": "/ˈtʃɔːklət/", "meaning": "巧克力", "example": "I love dark chocolate.", "exampleMeaning": "我爱黑巧克力。" }, - { "word": "candy", "phonetic": "/ˈkændi/", "meaning": "糖果", "example": "The child likes candy.", "exampleMeaning": "小孩喜欢糖果。" }, - { "word": "sandwich", "phonetic": "/ˈsænwɪtʃ/", "meaning": "三明治", "example": "I made a sandwich for lunch.", "exampleMeaning": "我做了三明治当午餐。" }, - { "word": "pizza", "phonetic": "/ˈpiːtsə/", "meaning": "披萨", "example": "Pizza is from Italy.", "exampleMeaning": "披萨来自意大利。" }, - { "word": "hamburger", "phonetic": "/ˈhæmbɜːrɡər/", "meaning": "汉堡", "example": "The hamburger is big.", "exampleMeaning": "这个汉堡很大。" }, - { "word": "cheese", "phonetic": "/tʃiːz/", "meaning": "奶酪", "example": "Cheese is made from milk.", "exampleMeaning": "奶酪是用牛奶做的。" }, - { "word": "butter", "phonetic": "/ˈbʌtər/", "meaning": "黄油", "example": "I spread butter on bread.", "exampleMeaning": "我在面包上涂黄油。" } + "words": [], + "subcategories": [ + { + "name": "主食", + "words": [ + { "word": "rice", "phonetic": "/raɪs/", "meaning": "米饭", "example": "I eat rice every day.", "exampleMeaning": "我每天吃米饭。" }, + { "word": "bread", "phonetic": "/bred/", "meaning": "面包", "example": "I have bread for breakfast.", "exampleMeaning": "我早餐吃面包。" }, + { "word": "noodle", "phonetic": "/ˈnuːdl/", "meaning": "面条", "example": "I like beef noodles.", "exampleMeaning": "我喜欢牛肉面。" }, + { "word": "dumpling", "phonetic": "/ˈdʌmplɪŋ/", "meaning": "饺子", "example": "We make dumplings together.", "exampleMeaning": "我们一起包饺子。" } + ] + }, + { + "name": "肉类", + "words": [ + { "word": "meat", "phonetic": "/miːt/", "meaning": "肉", "example": "I like to eat meat.", "exampleMeaning": "我喜欢吃肉。" }, + { "word": "beef", "phonetic": "/biːf/", "meaning": "牛肉", "example": "The beef is tender.", "exampleMeaning": "牛肉很嫩。" }, + { "word": "pork", "phonetic": "/pɔːrk/", "meaning": "猪肉", "example": "I don't eat pork.", "exampleMeaning": "我不吃猪肉。" }, + { "word": "chicken", "phonetic": "/ˈtʃɪkɪn/", "meaning": "鸡肉", "example": "Fried chicken is popular.", "exampleMeaning": "炸鸡很受欢迎。" }, + { "word": "egg", "phonetic": "/eɡ/", "meaning": "鸡蛋", "example": "I have an egg for breakfast.", "exampleMeaning": "我早餐吃一个鸡蛋。" } + ] + }, + { + "name": "蔬菜", + "words": [ + { "word": "vegetable", "phonetic": "/ˈvedʒtəbl/", "meaning": "蔬菜", "example": "Eat more vegetables.", "exampleMeaning": "多吃蔬菜。" }, + { "word": "carrot", "phonetic": "/ˈkærət/", "meaning": "胡萝卜", "example": "Rabbits like carrots.", "exampleMeaning": "兔子喜欢胡萝卜。" }, + { "word": "tomato", "phonetic": "/təˈmeɪtoʊ/", "meaning": "番茄", "example": "The tomato is red.", "exampleMeaning": "番茄是红色的。" }, + { "word": "potato", "phonetic": "/pəˈteɪtoʊ/", "meaning": "土豆", "example": "Potatoes grow underground.", "exampleMeaning": "土豆长在地下。" }, + { "word": "onion", "phonetic": "/ˈʌnjən/", "meaning": "洋葱", "example": "The onion makes me cry.", "exampleMeaning": "洋葱让我流泪。" }, + { "word": "cucumber", "phonetic": "/ˈkjuːkʌmbər/", "meaning": "黄瓜", "example": "The cucumber is fresh.", "exampleMeaning": "黄瓜很新鲜。" }, + { "word": "cabbage", "phonetic": "/ˈkæbɪdʒ/", "meaning": "卷心菜", "example": "Cabbage is good for health.", "exampleMeaning": "卷心菜对健康有好处。" } + ] + }, + { + "name": "饮品", + "words": [ + { "word": "water", "phonetic": "/ˈwɔːtər/", "meaning": "水", "example": "I drink water every day.", "exampleMeaning": "我每天喝水。" }, + { "word": "milk", "phonetic": "/mɪlk/", "meaning": "牛奶", "example": "I drink a glass of milk.", "exampleMeaning": "我喝一杯牛奶。" }, + { "word": "juice", "phonetic": "/dʒuːs/", "meaning": "果汁", "example": "Orange juice is sweet.", "exampleMeaning": "橙汁很甜。" }, + { "word": "tea", "phonetic": "/tiː/", "meaning": "茶", "example": "I drink tea in the afternoon.", "exampleMeaning": "我下午喝茶。" }, + { "word": "coffee", "phonetic": "/ˈkɔːfi/", "meaning": "咖啡", "example": "I need a cup of coffee.", "exampleMeaning": "我需要一杯咖啡。" }, + { "word": "beer", "phonetic": "/bɪr/", "meaning": "啤酒", "example": "He drinks beer with friends.", "exampleMeaning": "他和朋友喝啤酒。" }, + { "word": "wine", "phonetic": "/waɪn/", "meaning": "葡萄酒", "example": "Red wine is good for health.", "exampleMeaning": "红酒对健康有好处。" } + ] + }, + { + "name": "调料", + "words": [ + { "word": "salt", "phonetic": "/sɔːlt/", "meaning": "盐", "example": "Don't add too much salt.", "exampleMeaning": "不要加太多盐。" }, + { "word": "sugar", "phonetic": "/ˈʃʊɡər/", "meaning": "糖", "example": "I put sugar in my coffee.", "exampleMeaning": "我在咖啡里加糖。" }, + { "word": "oil", "phonetic": "/ɔɪl/", "meaning": "油", "example": "Add some oil to the pan.", "exampleMeaning": "往锅里加点油。" }, + { "word": "sauce", "phonetic": "/sɔːs/", "meaning": "酱", "example": "The sauce is delicious.", "exampleMeaning": "这个酱很好吃。" } + ] + }, + { + "name": "餐食", + "words": [ + { "word": "breakfast", "phonetic": "/ˈbrekfəst/", "meaning": "早餐", "example": "Breakfast is the most important meal.", "exampleMeaning": "早餐是最重要的一餐。" }, + { "word": "lunch", "phonetic": "/lʌntʃ/", "meaning": "午餐", "example": "I have lunch at twelve.", "exampleMeaning": "我十二点吃午餐。" }, + { "word": "dinner", "phonetic": "/ˈdɪnər/", "meaning": "晚餐", "example": "We have dinner at six.", "exampleMeaning": "我们六点吃晚餐。" }, + { "word": "soup", "phonetic": "/suːp/", "meaning": "汤", "example": "The soup is hot.", "exampleMeaning": "汤是热的。" } + ] + }, + { + "name": "零食甜品", + "words": [ + { "word": "cake", "phonetic": "/keɪk/", "meaning": "蛋糕", "example": "I like chocolate cake.", "exampleMeaning": "我喜欢巧克力蛋糕。" }, + { "word": "cookie", "phonetic": "/ˈkʊki/", "meaning": "饼干", "example": "The cookie is crunchy.", "exampleMeaning": "饼干很脆。" }, + { "word": "ice cream", "phonetic": "/ˌaɪs ˈkriːm/", "meaning": "冰淇淋", "example": "Ice cream is cold and sweet.", "exampleMeaning": "冰淇淋又冰又甜。" }, + { "word": "chocolate", "phonetic": "/ˈtʃɔːklət/", "meaning": "巧克力", "example": "I love dark chocolate.", "exampleMeaning": "我爱黑巧克力。" }, + { "word": "candy", "phonetic": "/ˈkændi/", "meaning": "糖果", "example": "The child likes candy.", "exampleMeaning": "小孩喜欢糖果。" } + ] + }, + { + "name": "其他", + "words": [ + { "word": "sandwich", "phonetic": "/ˈsænwɪtʃ/", "meaning": "三明治", "example": "I made a sandwich for lunch.", "exampleMeaning": "我做了三明治当午餐。" }, + { "word": "pizza", "phonetic": "/ˈpiːtsə/", "meaning": "披萨", "example": "Pizza is from Italy.", "exampleMeaning": "披萨来自意大利。" }, + { "word": "hamburger", "phonetic": "/ˈhæmbɜːrɡər/", "meaning": "汉堡", "example": "The hamburger is big.", "exampleMeaning": "这个汉堡很大。" }, + { "word": "cheese", "phonetic": "/tʃiːz/", "meaning": "奶酪", "example": "Cheese is made from milk.", "exampleMeaning": "奶酪是用牛奶做的。" }, + { "word": "butter", "phonetic": "/ˈbʌtər/", "meaning": "黄油", "example": "I spread butter on bread.", "exampleMeaning": "我在面包上涂黄油。" } + ] + } ] } ] diff --git a/LearnEnglish/LearnEnglish/Services/WordStore.swift b/LearnEnglish/LearnEnglish/Services/WordStore.swift index 6a8df25..ee44418 100644 --- a/LearnEnglish/LearnEnglish/Services/WordStore.swift +++ b/LearnEnglish/LearnEnglish/Services/WordStore.swift @@ -28,22 +28,29 @@ final class WordStore { let data = try Data(contentsOf: url) let decoded = try JSONDecoder().decode(WordBank.self, from: data) let categories = decoded.categories.map { category -> WordCategory in + var cat = category + let source: [Word] + if let subs = cat.subcategories, !subs.isEmpty { + source = subs.flatMap { $0.words } + } else { + source = cat.words + } let tagged: [Word] if category.id == "numbers" { - var words = NumberWords.makeWords(atoms: category.words) - let extras = category.words.filter { NumberWords.atomNumbers[$0.word] == nil } + var words = NumberWords.makeWords(atoms: source) + let extras = source.filter { NumberWords.atomNumbers[$0.word] == nil } words.append(contentsOf: extras) tagged = words } else { - tagged = category.words + tagged = source } let words = tagged.map { word -> Word in var w = word w.categoryId = category.id return w } - return WordCategory(id: category.id, name: category.name, icon: category.icon, - words: words) + cat.words = words + return cat } bank = WordBank(version: decoded.version, categories: categories) } catch { diff --git a/LearnEnglish/LearnEnglish/Views/WordListViewController.swift b/LearnEnglish/LearnEnglish/Views/WordListViewController.swift index 8fa03ca..20d064e 100644 --- a/LearnEnglish/LearnEnglish/Views/WordListViewController.swift +++ b/LearnEnglish/LearnEnglish/Views/WordListViewController.swift @@ -137,13 +137,33 @@ final class WordListViewController: UIViewController { } extension WordListViewController: UITableViewDataSource, UITableViewDelegate { + private var sections: [Subcategory]? { + category.subcategories.flatMap { $0.isEmpty ? nil : $0 } + } + + func numberOfSections(in tableView: UITableView) -> Int { + sections?.count ?? 1 + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + sections?[section].name + } + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - category.words.count + if let sections { + return sections[section].words.count + } + return category.words.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! WordCardCell - let word = category.words[indexPath.row] + let word: Word + if let sections { + word = sections[indexPath.section].words[indexPath.row] + } else { + word = category.words[indexPath.row] + } cell.configure(with: word) cell.onSpeak = { word in SpeechService.shared.speak(word.word) @@ -158,7 +178,13 @@ extension WordListViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { Haptics.selection() - let detail = WordDetailViewController(word: category.words[indexPath.row], categoryName: category.name) + let word: Word + if let sections { + word = sections[indexPath.section].words[indexPath.row] + } else { + word = category.words[indexPath.row] + } + let detail = WordDetailViewController(word: word, categoryName: category.name) navigationController?.pushViewController(detail, animated: true) } }