{"id":13610574,"url":"https://github.com/leonard-palm/compose-state-events","last_synced_at":"2025-04-12T22:34:12.936Z","repository":{"id":60514124,"uuid":"543655655","full_name":"leonard-palm/compose-state-events","owner":"leonard-palm","description":"A new way to implement One-Time-UI-Events (former SingleLiveEvent) in a Compose world.","archived":false,"fork":false,"pushed_at":"2023-12-07T12:37:00.000Z","size":182,"stargazers_count":180,"open_issues_count":0,"forks_count":14,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-07T16:44:06.784Z","etag":null,"topics":["android","android-development","android-library","compose-ui","jetpack-android","jetpack-compose","kotlin","kotlin-android","state-management"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leonard-palm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-30T15:03:05.000Z","updated_at":"2024-11-07T11:30:30.000Z","dependencies_parsed_at":"2024-08-01T19:44:10.851Z","dependency_job_id":"d2914df4-d261-4ef2-8082-ddd9dcde75b2","html_url":"https://github.com/leonard-palm/compose-state-events","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonard-palm%2Fcompose-state-events","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonard-palm%2Fcompose-state-events/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonard-palm%2Fcompose-state-events/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonard-palm%2Fcompose-state-events/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leonard-palm","download_url":"https://codeload.github.com/leonard-palm/compose-state-events/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248642288,"owners_count":21138350,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-development","android-library","compose-ui","jetpack-android","jetpack-compose","kotlin","kotlin-android","state-management"],"created_at":"2024-08-01T19:01:46.027Z","updated_at":"2025-04-12T22:34:12.676Z","avatar_url":"https://github.com/leonard-palm.png","language":"Kotlin","funding_links":[],"categories":["Kotlin"],"sub_categories":[],"readme":"![JitPack](https://img.shields.io/jitpack/version/com.github.leonard-palm/compose-state-events?color=%23%233cdb83\u0026style=for-the-badge)\n![GitHub](https://img.shields.io/github/license/leonard-palm/compose-state-events?color=%234185f3\u0026style=for-the-badge)\n![GitHub top language](https://img.shields.io/github/languages/top/leonard-palm/compose-state-events?color=%237f52ff\u0026style=for-the-badge)\n\n\u003cbr\u003e\n\u003cp align=\"center\"\u003e \n   \u003cimg height=\"150\" src=\"https://user-images.githubusercontent.com/20493984/194604428-89476453-8455-4bc5-803d-7ab604c41b9b.png\"/\u003e \n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e \n   Compose-State-Events\n\u003c/h1\u003e\n\nA new way to implement One-Time-UI-Events (former SingleLiveEvent) in a Compose world.\n\nThis library will help you to avoid implementing any antipatterns regarding One-Time-UI-Events as despribed by Manuel Vivo's [article](https://medium.com/androiddevelopers/viewmodel-one-off-event-antipatterns-16a1da869b95).\n\nSee the samples below on how to effectively use `StateEvent` in your view's state and `EventEffect` in your composables.\n\nTo get an in depth idea on how to migrate see this [article](https://medium.com/proandroiddev/how-to-handle-viewmodel-one-time-events-in-jetpack-compose-a01af0678b76) from Yanneck Reiß.\n\n# How to use\n\n\u003e Imagine a simple usecase where you need to fetch some list data from an API and display the result on the screen.\n\n\n\n### View State Object\n```kotlin\ndata class FlowerViewState(\n    val flowers: List\u003cFlower\u003e = emptyList(),\n    val isLoadingFlowers: Boolean = false,\n    val downloadSucceededEvent: StateEvent = consumed,\n    val downloadFailedEvent: StateEventWithContent\u003cInt\u003e = consumed()\n)\n```\n\u003e Imagine we would like to show a green success snackbar or a red failure snackbar after the loading has finished. \nThese two events would be represented with the two new fields `downloadSucceededEvent` and `downloadFailedEvent` in our view state object.\n\nUse the `StateEventWithContent\u003cT\u003e` when you need to pass some data to the consumer (the composable). \nIn the example above a StringRes with a fitting error description is passed.\n\n### ViewModel\n```kotlin\nprivate val _stateStream = MutableStateFlow(FlowerViewState())\nval stateStream = _stateStream.asStateFlow()\n\nprivate var state: FlowerViewState\n    get() = _stateStream.value\n    set(newState) {\n        _stateStream.update { newState }\n    }\n    \nfun loadFlowers(){\n  viewModelScope.launch {\n    state = state.copy(isLoading = true)\n    state = when (val apiResult = loadAllFlowersFromApiUseCase.call()) {\n        is Success -\u003e state.copy(flowers = apiResult, downloadSucceededEvent = triggered)\n        is Failure -\u003e state.copy(downloadFailedEvent = triggered(R.string.error_load_flowers))\n    }\n    state = state.copy(isLoading = false)\n  }\n}\n\nfun onConsumedDownloadSucceededEvent(){\n  state = state.copy(downloadSucceededEvent = consumed)\n}\n\nfun onConsumedDownloadFailedEvent(){\n  state = state.copy(downloadFailedEvent = consumed())\n}\n```\nTo trigger an event without any data just use the `triggered` value, otherwise use the `triggered(content: T)` function.\nTo consume an event without any data just use the `consumed` value, otherwise use the `consumed()` function.\n\n### Composable\n\n```kotlin\nval viewModel: MainViewModel = viewModel()\nval viewState: MainViewState by viewModel.stateStream.collectAsStateLifecycleAware()\n\nEventEffect(\n    event = viewState.downloadSucceededEvent, \n    onConsumed = viewModel::onConsumedDownloadSucceededEvent\n) {\n    scaffoldState.snackbarHostState.showSnackbar(\"Download succeeded.\")\n}\n\nEventEffect(\n    event = viewState.downloadFailedEvent, \n    onConsumed = viewModel::onConsumedDownloadFailedEvent\n) { stringRes -\u003e\n    scaffoldState.snackbarHostState.showSnackbar(context.resources.getString(stringRes))\n}\n```\nThe `EventEffect` is a `LaunchedEffect` that will be executed, when the event is in its triggered state. \nWhen the event action was executed the effect calls the passed `onConsumed` callback to force you to set the view state field to be consumed.\n\n### Special Case: Navigation\nIn the regular way you only want to consume your event when it really got processed. However, in some special cases you want to make sure that the `StateEvent` gets consumed no matter what the outcome of your code that gets triggered will be.\nOne case in which that gets relevant is when you want to navigate to another screen, if a `StateEvent` or `StateEventWithContent\u003cT\u003e` got invoked.\n\nFor this special case, instead of `EventEffect`, you can use the `NavigationEventEffect`.\n\n```kotlin\nNavigationEventEffect(  \n  event = viewState.downloadFailedEvent,  \n  onConsumed = viewModel::onConsumedDownloadFailedEvent  \n) {\n  navigator.navigateBack()  \n}\n```\n\n# Installation\n\n```gradle\nallprojects {\n   repositories {\n       ...\n       maven { url \"https://jitpack.io\" }\n   }\n}\ndependencies {\n   implementation 'com.github.leonard-palm:compose-state-events:2.2.0'\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleonard-palm%2Fcompose-state-events","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleonard-palm%2Fcompose-state-events","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleonard-palm%2Fcompose-state-events/lists"}