Skip to content

Instantly share code, notes, and snippets.

@morganbovi
Created April 20, 2022 16:32
Show Gist options
  • Save morganbovi/7abebad65f49638947cc9d16e28c08cb to your computer and use it in GitHub Desktop.
Save morganbovi/7abebad65f49638947cc9d16e28c08cb to your computer and use it in GitHub Desktop.
Presenter using callbacks instead of and event bus
// VIEW
@Composable
fun ArticleScreen() {
val presenter: ArticlePresenter by inject() // koin compose ext
val model = presenter.present()
ArticleView(model, presenter)
}
@Composable
fun ArticleView(uiModel: ArticleUiModel, uiActions: ArticleUiActions) {
when (uiModel) {
is ArticleUiModel.Loading -> Shimmer()
is ArticleUiModel.Data -> {
Row {
Text(uiModel.title)
Button(onClick = { uiActions.onShareArticle() }) {
Text(stringResource(R.string.share_article))
}
ContentView(uiModel.content)
}
}
}
}
@Composable
fun ContentView(uiModel: ContentUiModel) {
when (uiModel) {
is ContentUiModel.Error -> Unit // nothing to render
is ContentUiModel.Data -> Text(uiModel.content)
}
}
// PRESENTATION
sealed interface ArticleUiModel : UiModel {
object Loading : ArticleUiModel
data class Data(val title: String, val content: ContentUiModel) : ArticleUiModel
}
class ArticlePresenter(
private val resourceFetcher: ResourceFetcher,
private val navigator: Navigator,
private val getLatestArticleUseCase: GetLatestArticleUseCase,
private val contentPresenter: ContentPresenter
) : ArticleUiActions, ResourceFetcher by resourceFetcher {
@Composable
fun present(): ArticleUiModel {
val latestArticleResult by getLatestArticleUseCase.toFlow().collectAsState(initial = null)
val latestArticle = latestArticleResult?.getOrNull() ?: return ArticleUiModel.Loading
return ArticleUiModel.Data(
title = latestArticle.title,
content = contentPresenter.present(latestArticle.content)
)
}
override fun onShareArticle() {
val message = getString(R.string.share_article_message, latestArticle.title)
navigator.navigate(IntentTarget.Share(message))
}
}
interface ArticleUiActions {
fun onShareArticle()
}
sealed interface ContentUiModel : UiModel {
object Error : ContentUiModel
data class Data(val content: String) : ContentUiModel
}
class ContentPresenter(
private val formatArticleContentUseCase: FormatArticleContentUseCase
) {
@Composable
fun present(articleContent: String): ContentUiModel {
// cache result from SynchronousUseCase
val formattedContentResult = remember(articleContent) {
formartArticleContentUseCase(FormartArticleContentUseCase.Params(articleContent))
}
return formattedContentResult.getOrNull()?.let { formattedContent ->
ContentUiModel.Data(formattedContent)
} ?: ContentUiModel.Error
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment