上周对于数据库的设计、搭建与优化已基本完成,对于基础功能也进行了一定的开发,本周
主要是对于单词列表、单词学习、单选练习、单词默写练习等功能的开发。
本周开发的所有功能均在study文件夹中,架构如下所示:
一、单词列表显示功能的开发
1.根据学习计划的选择和设定,WordListViewModel分别接受三个参数:start、wordListsize和vocabularyName,根据这三个参数从数据库中取出相应的单词,代码实现如下:
val progress = studyProgressRepository.getStudyProgressLatest()
if (progress != null) {
val wordList = vocabularyViewRepository.getWordList(
start = progress.start,
wordListSize = progress.wordListSize,
vocabularyName = progress.vocabularyName
)
wordListUiState.value = WordListUiState
.Success(
wordList = wordList
)
} else {
wordListUiState.value = WordListUiState
.Error(DataResult.Error.Code.UNKNOWN)
}
2.在此功能的实现过程中,设置了缓存机制,其实现逻辑如下:
sequenceDiagram
ViewModel->>Repository: getWordList(start=0, size=10, BEGINNER)
alt 缓存命中
Repository-->>ViewModel: 返回缓存数据
else 缓存未命中
Repository->>DAO: 查询数据库
DAO-->>Repository: 返回数据
Repository->>Repository: 更新缓存
Repository-->>ViewModel: 返回数据
end
此处的缓存机制通过一个列表实现对于数据的暂时存储,命中与清空更新缓存代码如下:
//命中
suspend fun getWordList(
start: Int,
wordListSize: Int,
vocabularyName: Vocabulary.Name
): List<Word> {
if (beginCache != start || numCache != wordListSize) {
beginCache = start
numCache = wordListSize
wordListCache = when (vocabularyName) {
Vocabulary.Name.BEGINNER -> getWordListBeginner(start, wordListSize)
Vocabulary.Name.INTERMEDIATE -> getWordListIntermediate(start, wordListSize)
Vocabulary.Name.NONE -> emptyList()
}
}
return wordListCache
}
//清空缓存
fun emptyWordListCache() {
if (wordListCache.isNotEmpty()) {
wordListCache = emptyList()
beginCache = -1
numCache = -1
}
}
最终实现页面如下所示:
二、单词学习功能的开发
1.功能架构:在单词学习功能的开发过程中,有一个创新点--实现横向翻页切换功能。具体实现:通过LearnScreen对横向的两个页面进行管理,0->>LearnPager,1 ->> QuizPager。LearnPager和QuizPager两个kt文件分别用于管理两个页面的组件和内容。架构逻辑图如下:
A[LearnScreen] --> B[LearnContent]
B --> C[状态管理: LearnUiState]
B --> D[横向分页: LearnPager + QuizPager]
B --> E[底部操作栏: InputButtonRow]
2.创新点设计:
分页同步控制:触发时机:点击"下一题"时自动返回学习页(第0页)
scope.launch {
pagerState.animateScrollToPage(0) // 切换到学习页
}
状态驱动UI:根据是否最后一题、是否答对动态改变按钮功能和图标
val lastOne = (uiState.current + 1) == uiState.totalNum
val rightActionInfo = if (uiState.learned && lastOne) {
R.drawable.ic_start_24dp to { navigateToChoice() } // 完成学习
} else {
R.drawable.ic_double_arrow_right_24dp to getNextWord // 下一题
}
协程动画控制:平滑处理分页切换,统一视觉风格,并通过底部操作栏设计便于用户使用。
InputButtonRow(
leftButtonIconId = R.drawable.ic_submit_24dp, // 提交/重置按钮
rightButtonIconId = R.drawable.ic_double_arrow_right_24dp, // 下一题/完成按钮
playPron = { playPron(word.pronName) } // 发音按钮
)
3.最终设计界面如下所示:
三、单词练习功能的开发
1.页面布局:页面主要由四个选项组成,每个选项对应一个单词释义,用户通过点击相应的选项完成作答,此部分由ChoiceScreen完成。当用户做出选择后,页面跳转,通过不同颜色显示答案的正确与否,并根据不同主题模式设置了不同颜色,界面如下:
四、单词默写练习功能开发
1.动态区域设计:在页面的底部,设计了动态区域,根据 uiState.submitted 的状态驱动ui。
未提交时,显示键盘:
LandingKeyboard(
write = write, // 字母按键回调
remove = remove // 删除键回调
)
提交后,显示答案:
Column {
// 正确答案
Text(uiState.word.spelling, style = MaterialTheme.typography.headlineLarge)
// 音标
Text(uiState.word.ipa, color = MaterialTheme.colorScheme.outline)
// 对错图标
Icon(
painter = if (uiState.input == uiState.word.spelling)
R.drawable.ic_correct_24dp
else
R.drawable.ic_close_24dp
)
}
2.局部弹窗设计:在 Composable 函数中根据 dialog 状态显示不同弹窗,弹窗状态与主状态绑定,避免不同步,代码如下:
@Composable
fun SpellingScreen(viewModel: SpellingViewModel) {
val uiState by viewModel.uiState.collectAsState()
if (uiState is SpellingUiState.Success) {
when (uiState.dialog) {
is SpellingUiState.Success.Dialog.None -> Unit // 不显示
is SpellingUiState.Success.Dialog.Processing -> {
LoadingDialog(onDismiss = viewModel::closeDialog)
}
is SpellingUiState.Success.Dialog.Dictionary -> {
val word = uiState.dialog.word
WordDetailDialog(
word = word,
onDismiss = viewModel::closeDialog
)
}
}
}
}
3.界面开发如下:
五、错题列表功能开发
1.错题列表主要通过弹窗显示释义,此设计更贴合用户使用习惯。通过openDictionaryDialog方法进行条件检查,clickedWrongWord:保存当前选中的单词对象(用于弹窗内容展示),dialog:将弹窗状态设为 Dictionary 类型(触发UI渲染弹窗)。而closeDialog 方法关闭当前显示的任何弹窗(包括词典弹窗或处理中弹窗)。
// 打开前:
Success(
showWrongList = true,
clickedWrongWord = null,
dialog = Dialog.None
)
// 打开后:
Success(
showWrongList = true,
clickedWrongWord = word, // 实际单词对象
dialog = Dialog.Dictionary
)
2.交互流程如下:
User->>UI: 点击错词按钮
UI->>ViewModel: 调用 openDictionaryDialog(word)
ViewModel->>UI: 更新状态显示词典弹窗
六、实时同步学习进度(可视化展示)