实现背单词首页功能:内置分类词库,支持分类浏览、单词详情和离线发音
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CategoryListView: View {
|
||||
let categories: [WordCategory]
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
List(categories) { category in
|
||||
NavigationLink(value: category) {
|
||||
HStack(spacing: 16) {
|
||||
Image(systemName: category.icon)
|
||||
.font(.title2)
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 44, height: 44)
|
||||
.background(.tint, in: RoundedRectangle(cornerRadius: 10))
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(category.name)
|
||||
.font(.headline)
|
||||
Text("\(category.words.count) 个单词")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
}
|
||||
.navigationTitle("单词分类")
|
||||
.navigationDestination(for: WordCategory.self) { category in
|
||||
WordListView(category: category)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
CategoryListView(categories: [
|
||||
WordCategory(id: "colors", name: "颜色", icon: "paintpalette.fill", words: [
|
||||
Word(word: "red", phonetic: "/red/", meaning: "红色", example: "The apple is red.", exampleMeaning: "苹果是红色的。")
|
||||
])
|
||||
])
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import SwiftUI
|
||||
|
||||
struct WordDetailView: View {
|
||||
let word: Word
|
||||
@Environment(SpeechService.self) private var speech
|
||||
|
||||
private var isSpeaking: Bool {
|
||||
speech.speakingText == word.word
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(spacing: 32) {
|
||||
VStack(spacing: 12) {
|
||||
Text(word.word)
|
||||
.font(.system(size: 48, weight: .bold))
|
||||
Text(word.phonetic)
|
||||
.font(.title3)
|
||||
.foregroundStyle(.secondary)
|
||||
Button {
|
||||
speech.speak(word.word)
|
||||
} label: {
|
||||
Label(isSpeaking ? "朗读中" : "发音", systemImage: isSpeaking ? "speaker.wave.3.fill" : "speaker.wave.2.fill")
|
||||
.font(.headline)
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.vertical, 10)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.disabled(isSpeaking)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text("释义")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
Text(word.meaning)
|
||||
.font(.title2)
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text("例句")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
HStack(alignment: .top) {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(word.example)
|
||||
.font(.body)
|
||||
Text(word.exampleMeaning)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
Button {
|
||||
speech.speak(word.example)
|
||||
} label: {
|
||||
Image(systemName: "speaker.wave.2")
|
||||
}
|
||||
.buttonStyle(.borderless)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding()
|
||||
.background(.quaternary.opacity(0.5), in: RoundedRectangle(cornerRadius: 16))
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.navigationTitle(word.word)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
WordDetailView(word: Word(word: "red", phonetic: "/red/", meaning: "红色", example: "The apple is red.", exampleMeaning: "苹果是红色的。"))
|
||||
.environment(SpeechService())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import SwiftUI
|
||||
|
||||
struct WordListView: View {
|
||||
let category: WordCategory
|
||||
|
||||
var body: some View {
|
||||
List(category.words) { word in
|
||||
NavigationLink(value: word) {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(word.word)
|
||||
.font(.headline)
|
||||
Text(word.meaning)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.padding(.vertical, 2)
|
||||
}
|
||||
}
|
||||
.navigationTitle(category.name)
|
||||
.navigationDestination(for: Word.self) { word in
|
||||
WordDetailView(word: word)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
WordListView(category: WordCategory(id: "colors", name: "颜色", icon: "paintpalette.fill", words: [
|
||||
Word(word: "red", phonetic: "/red/", meaning: "红色", example: "The apple is red.", exampleMeaning: "苹果是红色的。")
|
||||
]))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user