This guide explains the shared snackbar flow that powers every platform.
core/presentation/src/commonMain/kotlin/com/softartdev/notedelight/interactor/SnackbarInteractor.kt– multiplatform contract withsetDependencies,releaseDependencies, andshowMessagereturning aJob?.ui/shared/src/commonMain/kotlin/com/softartdev/notedelight/interactor/SnackbarInteractorImpl.kt– Compose-aware implementation that wires aSnackbarHostState, clipboard access, and coroutine scope.ui/shared/src/commonMain/kotlin/com/softartdev/notedelight/ui/GlobalSnackbarHost.kt– composable that installs a globalSnackbarHostand feeds the implementation viaDisposableEffect.ui/shared/src/commonMain/kotlin/com/softartdev/notedelight/App.kt– registers the host at the root and injectsSnackbarInteractorthrough Koin.
Keep the interface free from Compose types so it can be used in tests and on non-Compose platforms.
SnackbarMessage is a sealed interface designed for AI-facing ergonomics:
Simple(text: String)– fire-and-forget message.Copyable(text: String)– shows aCopyaction and writes to the clipboard when the action is triggered.Resource(res: SnackbarTextResource, suffix: String = "")– resolves a string resource (SAVED,EMPTY,DELETED) and optionally appends context text.
If you need a new reusable message, extend SnackbarTextResource instead of duplicating strings.
GlobalSnackbarHostcreates a host state, clipboard, and coroutine scope, then callssetDependencieson the interactor.SnackbarInteractorImpl.showMessagelaunches work on that scope, routing messages to the host and clipboard.- When the host leaves composition
releaseDependenciesclears references, preventing leaks on iOS/desktop.
Do not re-create or inject SnackbarHostState elsewhere—always rely on the global host.
- Inject
SnackbarInteractorin the ViewModel constructor (see Koin registrations inui/shared/di/uiModules.kt). - Call
snackbarInteractor.showMessage(...)directly; the coroutine is launched inside the interactor soviewModelScope.launchis unnecessary unless you need structured cancellation. - Optionally keep the returned
Jobif you need to cancel an in-flight snackbar before triggering another one.
Example usage inside NoteViewModel:
snackbarInteractor.showMessage(
message = SnackbarMessage.Resource(
res = SnackbarTextResource.SAVED,
suffix = noteTitle,
)
)- ✅ Add new snackbar entry points through the interactor, never by manipulating
SnackbarHostStateyourself. - ✅ Use
SnackbarMessage.Resourcefor translated strings—resources live inui/shared/src/commonMain/composeResources/values. - ✅ Keep UI wiring in
GlobalSnackbarHost; screens should only consume the interactor. ⚠️ Remember to update tests: use a fake implementation ofSnackbarInteractorrather than asserting on Compose state.⚠️ Clean up any manual clipboard usage;Copyablealready performs the write.