User Settings & DataStore
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/kotlin/com/fathiraz/flowbell/data/local/preferences/DataStoreManager.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/repositories/UserPreferencesRepositoryImpl.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/repositories/UserPreferencesRoomRepository.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/local/database/entities/UserPreferencesEntity.kt
- app/src/main/kotlin/com/fathiraz/flowbell/presentation/screens/settings/SettingsViewModel.kt
- app/src/main/kotlin/com/fathiraz/flowbell/domain/usecases/ManageUserSettingsUseCase.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/local/database/FlowBellDatabase.kt
The User Settings & DataStore system in FlowBell is a multi-layered persistence architecture designed to manage application configurations, theme preferences, and webhook synchronization. It utilizes a hybrid approach, combining Jetpack DataStore for key-value preferences and Room (SQLite) for structured user preference entities, ensuring high reliability across various Android hardware manufacturers, particularly Samsung devices.
This module provides the backbone for user-controlled features such as dark mode toggling, notification filtering, and debug tool visibility. By encapsulating logic within specialized repositories and use cases, the system maintains a clear separation of concerns between the UI layer and the persistent storage mechanisms.
Sources: README.md, DataStoreManager.kt, UserPreferencesEntity.kt
Architecture Overview
The system follows Clean Architecture principles, routing requests from the UI through ViewModels and Use Cases to specific Repository implementations.
This diagram illustrates the flow of configuration data from the UI to the underlying storage engines.
Sources: ManageUserSettingsUseCase.kt:14-17, DataModule.kt:37-45, SettingsViewModel.kt:41-45
DataStore Persistence Layer
The DataStoreManager handles low-level key-value storage. A critical feature of this implementation is its "Samsung Compatibility Mode," which addresses specific eMMC corruption issues common in some hardware by providing a fallback to traditional SharedPreferences.
Samsung Compatibility Mechanism
On Samsung devices, critical data like the Webhook URL is mirrored across both DataStore and a fallback SharedPreferences file. If the DataStore read/write fails due to an IOException, the system automatically attempts to recover the data from the legacy storage.
Sequence of a webhook update operation with hardware-specific safety checks.
Sources: DataStoreManager.kt:76-114, DataStoreManager.kt:185-201
Persistent Configuration Fields
The following preferences are managed primarily through the DataStore/SharedPreferences layer:
| Key | Type | Description |
|---|---|---|
THEME_MODE | String/Enum | User's preferred theme (Light, Dark, or System). |
WEBHOOK_URL | String | The endpoint URL for notification forwarding. |
NOTIFICATIONS_ENABLED | Boolean | Global toggle for the notification listener service. |
IS_DEBUG_MODE_ENABLED | Boolean | Controls visibility of Beagle and Chucker debug tools. |
AUTO_START_SERVICE | Boolean | Whether the service starts automatically on boot. |
Sources: DataStoreManager.kt:205-231, UserPreferencesRepositoryImpl.kt:45-100
Room-Based Preferences (SQLite)
In addition to DataStore, FlowBell utilizes the UserPreferencesEntity within Room to store more structured or relational configuration data, such as notification filter lists and timestamp metadata.
Schema Migration Path
The database schema has evolved through 10 versions to support expanding preference features. Key migrations related to settings include:
- Migration 2→3: Introduction of the
user_preferencestable. - Migration 8→9: Addition of
global_filter_wordsandfilter_wordsper app. - Migration 9→10: Addition of the
notification_filter_enabledflag.
Sources: FlowBellDatabase.kt:53-76, FlowBellDatabase.kt:156-180
Entity Structure
@Entity(tableName = "user_preferences")
data class UserPreferencesEntity(
@PrimaryKey val id: Int = 1,
val themeMode: String = ThemeMode.SYSTEM.name,
val notificationFilterEnabled: Boolean = false,
val globalFilterWords: String = "", // Comma-separated
val updatedAt: Long = System.currentTimeMillis()
)
Sources: UserPreferencesEntity.kt:14-43
Notification Filtering Logic
The settings system enables users to manage keyword-based filters. These filters are defined in the SettingsScreen and processed by the ManageUserSettingsUseCase.
- Input Processing: Users enter keywords in a comma-separated format in the UI.
- Normalization: The
SettingsViewModelsplits, trims, and filters blank entries before passing them to the repository. - Persistence: The list is joined back into a single string for storage in the
user_preferencestable or DataStore.
Data transformation flow for notification keyword filters.
Sources: SettingsViewModel.kt:130-150, UserPreferencesRoomRepository.kt:55-63
Initialization & Safety
The system includes specific logic for handling fresh installs to prevent stale data from interfering with new configurations.
- Fresh Install Detection:
DataStoreManagerchecks for anapp_versionSharedPreferences key. If missing, it triggersclearAllPreferences()to wipe DataStore, fallbacks, and legacy legacy storage. - Corruption Handling: A
ReplaceFileCorruptionHandleris attached to the DataStore instance to automatically recreate a clean state if the underlying file becomes unreadable.
Sources: DataStoreManager.kt:25-33, DataStoreManager.kt:167-183
Summary
The User Settings & DataStore module provides a robust, fail-safe environment for managing user intent and application state. By bridging reactive Flow streams from both Room and DataStore, it ensures the UI remains synchronized with the latest configurations while maintaining compatibility across diverse Android hardware environments.