-
Notifications
You must be signed in to change notification settings - Fork 0
Screen UI Providers
The ScreenUiProvider pattern is a mechanism used to decouple the "Chrome" of a screen (TopAppBar, FloatingActionButton) from the screen's content and the main navigation host.
In a modular app, the MainScreen (which holds the Scaffold) doesn't know about specific screens inside feature modules. We wanted to avoid a monolithic when(route) statement in MainScreen to determine which Title or FAB to show.
We define an interface ScreenUiProvider in :core:ui. Each Feature module implements this interface for its screens if they need a TopBar or FAB.
interface ScreenUiProvider {
val route: String
val topBar: (@Composable () -> Unit)? get() = null
val fab: (@Composable () -> Unit)? get() = null
}In the feature module (e.g., Settings), we create an implementation binding it to a specific route:
class DefaultCurrencyScreenUiProviderImpl(
override val route: String = Routes.SETTINGS_DEFAULT_CURRENCY
) : ScreenUiProvider {
override val topBar: @Composable () -> Unit = {
TopAppBar(title = { Text("Currency") })
}
}We register it in Koin as a ScreenUiProvider:
single { DefaultCurrencyScreenUiProviderImpl() } bind ScreenUiProvider::classIn MainScreen (or FeatureScaffold), we inject all providers:
val providers: List<ScreenUiProvider> = getKoin().getAll()
val currentProvider = providers.find { it.route == currentRoute }
Scaffold(
topBar = { currentProvider?.topBar?.invoke() }
) { content() }This makes the architecture extensible. Adding a new screen with a toolbar requires zero changes in the MainScreen code.