Feature: Dictionary Details Screen
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/java/com/vocabri/ui/screens/dictionarydetails/DictionaryDetailsScreen.kt
- app/src/main/java/com/vocabri/ui/screens/dictionarydetails/viewmodel/DictionaryDetailsViewModel.kt
- app/src/main/java/com/vocabri/ui/screens/dictionarydetails/components/WordListItem.kt
- app/src/main/java/com/vocabri/di/AppModule.kt
- app/src/main/java/com/vocabri/ui/navigation/AppNavigation.kt
- app/src/test/java/com/vocabri/ui/dictionarydetails/DictionaryDetailsViewModelTest.kt
- app/src/main/res/values/strings.xml
The Dictionary Details Screen is a core feature of the Vocabri application that displays a list of words belonging to a specific category (Part of Speech), such as "Nouns" or "Verbs". Users navigate to this screen from the main Dictionary Screen by selecting a word group. The screen allows users to view the words in the selected category and provides functionality to delete words via a swipe gesture.
This feature follows a modern Android architecture, utilizing Jetpack Compose for the UI, a ViewModel for state management, and Use Cases to interact with the data layer. The UI is reactive, observing a state flow from the ViewModel to render the appropriate content, whether it's a list of words, a loading skeleton, an empty state message, or an error.
Architecture Overview
The Dictionary Details feature is implemented using an MVVM (Model-View-ViewModel) architecture with a clean separation of concerns between the UI, business logic, and data layers.
The diagram below illustrates the architectural flow for this feature.
UI Layer
The UI is built entirely with Jetpack Compose and is responsible for rendering the state provided by the DictionaryDetailsViewModel and forwarding user events to it.
Sources: app/src/main/java/com/vocabri/ui/screens/dictionarydetails/DictionaryDetailsScreen.kt
Core Composables
DictionaryDetailsScreen: The main entry point for the screen's UI. It collects the state from theDictionaryDetailsViewModeland dispatches events to theNavControlleror the ViewModel.DictionaryDetailsScreenRoot: A container composable that uses awhenstatement to decide which state-specific composable to render based on the currentDictionaryDetailsState.- State-Specific Composables:
LoadingScreen: Displays a shimmer effect with skeletons to indicate that data is being loaded.WordListScreen: Displays the list of words using aLazyColumnandWordListItemcomposables.EmptyScreen: Shown when there are no words in the selected category. It provides a message and a button to add a new word.ErrorScreen: Displays an error message and a "Retry" button.
WordListItem Component
The WordListItem is a key component that represents a single word in the list. It displays the word's text, translations, and examples. It also implements swipe-to-delete functionality.
- Swipe-to-Delete: Swiping an item from end to start (left swipe in LTR layouts) triggers the
DictionaryDetailsEvent.DeleteWordClickedevent with the word's ID. This is implemented using theSwipeToDismisscomposable.
Sources: app/src/main/java/com/vocabri/ui/screens/dictionarydetails/components/WordListItem.kt
ViewModel and State Management
The DictionaryDetailsViewModel is the centerpiece of the screen's logic. It is responsible for fetching words, managing the UI state, and handling user actions like deletion.
Sources: app/src/main/java/com/vocabri/ui/screens/dictionarydetails/viewmodel/DictionaryDetailsViewModel.kt
Dependencies
The ViewModel depends on two use cases to interact with the data layer:
ObserveWordsUseCase: To get a reactive flow of words for a givenPartOfSpeech.DeleteWordUseCase: To delete a specific word by its ID.
State (DictionaryDetailsState)
The ViewModel exposes its state via a StateFlow<DictionaryDetailsState>. DictionaryDetailsState is a sealed interface representing all possible states of the UI.
This diagram shows the possible state transitions.
| State | Description |
|---|---|
Loading | The initial state while words are being fetched. The UI shows a loading indicator. |
WordsLoaded | Contains a list of WordUiModel to be displayed. |
Empty | Indicates that the fetch was successful but no words were found for the category. |
Error | Indicates that an error occurred during data fetching. Contains an error message. |
Sources: app/src/main/java/com/vocabri/ui/screens/dictionarydetails/viewmodel/DictionaryDetailsState.kt (Inferred from ViewModel)
Events (DictionaryDetailsEvent)
User interactions are modeled as events using the DictionaryDetailsEvent sealed interface.
| Event | Description | Handler |
|---|---|---|
DeleteWordClicked(id: String) | Triggered when a user swipes to delete a word. | DictionaryDetailsViewModel.handleDeleteWord() |
OnWordClicked(id: String) | Triggered when a user taps on a word item. | DictionaryDetailsScreen (navigates back). |
AddWordClicked | Triggered from the EmptyScreen to add a new word. | DictionaryDetailsScreen (navigates to Add Word). |
OnBackClicked | Triggered to navigate back. | DictionaryDetailsScreen (pops back stack). |
RetryClicked | Triggered from the ErrorScreen. | DictionaryDetailsViewModel.retry() |
Sources: app/src/main/java/com/vocabri/ui/screens/dictionarydetails/viewmodel/DictionaryDetailsEvent.kt (Inferred from Screen/ViewModel), app/src/main/java/com/vocabri/ui/screens/dictionarydetails/DictionaryDetailsScreen.kt:81-99
Data Flow
Loading Words
The following sequence diagram shows how words are loaded when the screen is initialized.
Deleting a Word
This diagram illustrates the process of deleting a word.
Navigation and Dependency Injection
Navigation
Navigation to the DictionaryDetailsScreen is handled by NavHost. The route requires a partOfSpeech argument to know which category of words to display.
The route is defined as: dictionary_details/{partOfSpeech}.
Sources: app/src/main/java/com/vocabri/ui/navigation/AppNavigation.kt:70-83
Dependency Injection with Koin
A separate DictionaryDetailsViewModel instance is required for each PartOfSpeech. This is achieved using Koin's named qualifiers. The AppModule dynamically creates a ViewModel factory for every entry in the PartOfSpeech enum.
When navigating, the AppNavigation composable retrieves the correct ViewModel instance by passing a qualifier generated from the partOfSpeech navigation argument.
// From app/src/main/java/com/vocabri/di/AppModule.kt
PartOfSpeech.entries.forEach { partOfSpeech ->
viewModel(qualifier = DictionaryDetailsQualifiers.fromPartOfSpeech(partOfSpeech)) {
DictionaryDetailsViewModel(
partOfSpeech = partOfSpeech,
observeWordsUseCase = get(),
deleteWordUseCase = get(),
ioScope = get(),
)
}
}
Sources: app/src/main/java/com/vocabri/di/AppModule.kt:47-56
// From app/src/main/java/com/vocabri/ui/navigation/AppNavigation.kt
val viewModel: DictionaryDetailsViewModel = koinViewModel(
qualifier = DictionaryDetailsQualifiers.fromPartOfSpeech(PartOfSpeech.valueOf(partOfSpeech)),
viewModelStoreOwner = backStackEntry,
)
Sources: app/src/main/java/com/vocabri/ui/navigation/AppNavigation.kt:79-82
Summary
The Dictionary Details Screen serves as a focused view for words within a specific category. It demonstrates a robust implementation of the MVVM pattern with a reactive, state-driven UI built in Jetpack Compose. Its architecture promotes a clean separation of concerns, and it leverages Koin for dynamic dependency injection, allowing it to be highly scalable and maintainable. The optimistic UI update on word deletion provides a smooth user experience.