From 40ab25798c49a778e0c75b11ba74e6592f7840f0 Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Sun, 25 Sep 2022 07:08:40 +0900 Subject: [PATCH 1/2] :recycle: Update Introduce error handring to contributors --- .../DataContributorsRepository.kt | 19 ++++---- .../FakeContributorsRepository.kt | 1 - .../feature/contributors/Contributors.kt | 25 ++++++++++- .../contributors/ContributorsUiModel.kt | 6 ++- .../contributors/ContributorsViewModel.kt | 43 ++++++++++++++++--- 5 files changed, 76 insertions(+), 18 deletions(-) diff --git a/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched2022/data/contributors/DataContributorsRepository.kt b/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched2022/data/contributors/DataContributorsRepository.kt index 87d77f3d0..de88be1ec 100644 --- a/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched2022/data/contributors/DataContributorsRepository.kt +++ b/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched2022/data/contributors/DataContributorsRepository.kt @@ -3,27 +3,30 @@ package io.github.droidkaigi.confsched2022.data.contributors import io.github.droidkaigi.confsched2022.model.Contributor import io.github.droidkaigi.confsched2022.model.ContributorsRepository import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList -import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.callbackFlow // TODO: Move to core-testing, once contributors server is created public class DataContributorsRepository( private val contributorsApi: ContributorsApi, ) : ContributorsRepository { + private val contributorsStateFlow = + MutableStateFlow>(persistentListOf()) + override fun contributors(): Flow> { return callbackFlow { - send( - contributorsApi - .contributors() - .toPersistentList() - ) - awaitClose { } + contributorsStateFlow.collect { + send(it) + } } } override suspend fun refresh() { - TODO("Not yet implemented") + contributorsStateFlow.value = contributorsApi + .contributors() + .toPersistentList() } } diff --git a/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched2022/data/contributors/FakeContributorsRepository.kt b/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched2022/data/contributors/FakeContributorsRepository.kt index 4b6b33579..9824f1236 100644 --- a/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched2022/data/contributors/FakeContributorsRepository.kt +++ b/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched2022/data/contributors/FakeContributorsRepository.kt @@ -14,6 +14,5 @@ public class FakeContributorsRepository : ContributorsRepository { } override suspend fun refresh() { - TODO("Not yet implemented") } } diff --git a/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/Contributors.kt b/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/Contributors.kt index 082af67d7..fc2d34275 100644 --- a/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/Contributors.kt +++ b/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/Contributors.kt @@ -7,9 +7,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview @@ -19,6 +21,7 @@ import io.github.droidkaigi.confsched2022.designsystem.components.KaigiScaffold import io.github.droidkaigi.confsched2022.designsystem.components.KaigiTopAppBar import io.github.droidkaigi.confsched2022.designsystem.components.UsernameRow import io.github.droidkaigi.confsched2022.designsystem.theme.KaigiTheme +import io.github.droidkaigi.confsched2022.feature.announcement.AppErrorSnackbarEffect import io.github.droidkaigi.confsched2022.model.Contributor import io.github.droidkaigi.confsched2022.model.fakes import io.github.droidkaigi.confsched2022.strings.Strings @@ -38,6 +41,8 @@ fun ContributorsScreenRoot( uiModel = uiModel, showNavigationIcon = showNavigationIcon, onNavigationIconClick = onNavigationIconClick, + onRetryButtonClick = { viewModel.onRetryButtonClick() }, + onAppErrorNotified = { viewModel.onAppErrorNotified() }, onLinkClick = onLinkClick ) } @@ -47,10 +52,15 @@ fun Contributors( uiModel: ContributorsUiModel, showNavigationIcon: Boolean, onNavigationIconClick: () -> Unit, + onRetryButtonClick: () -> Unit, + onAppErrorNotified: () -> Unit, onLinkClick: (url: String, packageName: String?) -> Unit, modifier: Modifier = Modifier, ) { + val snackbarHostState = remember { SnackbarHostState() } + KaigiScaffold( + snackbarHostState = snackbarHostState, modifier = modifier, topBar = { KaigiTopAppBar( @@ -64,9 +74,17 @@ fun Contributors( ) } ) { innerPadding -> + AppErrorSnackbarEffect( + appError = uiModel.appError, + snackBarHostState = snackbarHostState, + onAppErrorNotified = onAppErrorNotified, + onRetryButtonClick = onRetryButtonClick + ) Box { when (uiModel.state) { - is Error -> TODO() + is Error -> { + // Do nothing + } Loading -> Box( modifier = Modifier.padding(innerPadding).fillMaxSize(), contentAlignment = Alignment.Center, @@ -103,10 +121,13 @@ fun ContributorsPreview() { uiModel = ContributorsUiModel( state = Success( Contributor.fakes() - ) + ), + appError = null, ), showNavigationIcon = true, onNavigationIconClick = {}, + onRetryButtonClick = {}, + onAppErrorNotified = {}, onLinkClick = { _, _ -> }, ) } diff --git a/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/ContributorsUiModel.kt b/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/ContributorsUiModel.kt index a07ddd2d7..6d167e09d 100644 --- a/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/ContributorsUiModel.kt +++ b/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/ContributorsUiModel.kt @@ -1,7 +1,11 @@ package io.github.droidkaigi.confsched2022.feature.contributors +import io.github.droidkaigi.confsched2022.model.AppError import io.github.droidkaigi.confsched2022.model.Contributor import io.github.droidkaigi.confsched2022.ui.UiLoadState import kotlinx.collections.immutable.PersistentList -data class ContributorsUiModel(val state: UiLoadState>) +data class ContributorsUiModel( + val state: UiLoadState>, + val appError: AppError? +) diff --git a/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/ContributorsViewModel.kt b/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/ContributorsViewModel.kt index 86aab043a..0460b5045 100644 --- a/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/ContributorsViewModel.kt +++ b/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/ContributorsViewModel.kt @@ -3,33 +3,64 @@ package io.github.droidkaigi.confsched2022.feature.contributors import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.cash.molecule.AndroidUiDispatcher import app.cash.molecule.RecompositionClock.ContextClock import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.droidkaigi.confsched2022.model.AppError import io.github.droidkaigi.confsched2022.model.ContributorsRepository import io.github.droidkaigi.confsched2022.ui.UiLoadState import io.github.droidkaigi.confsched2022.ui.asLoadState import io.github.droidkaigi.confsched2022.ui.moleculeComposeState import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class ContributorsViewModel @Inject constructor( - contributorsRepository: ContributorsRepository, + private val contributorsRepository: ContributorsRepository, ) : ViewModel() { private val moleculeScope = CoroutineScope(viewModelScope.coroutineContext + AndroidUiDispatcher.Main) - val uiModel: State + private val contributorsFlow = contributorsRepository + .contributors() + .asLoadState() + + private var appError by mutableStateOf(null) + + val uiModel: State = moleculeScope.moleculeComposeState( + clock = ContextClock + ) { + val contributorLoadState by contributorsFlow.collectAsState(initial = UiLoadState.Loading) + ContributorsUiModel( + state = contributorLoadState, + appError = appError + ) + } init { - val dataFlow = contributorsRepository.contributors().asLoadState() + refresh() + } - uiModel = moleculeScope.moleculeComposeState(clock = ContextClock) { - val data by dataFlow.collectAsState(initial = UiLoadState.Loading) - ContributorsUiModel(data) + fun onRetryButtonClick() { + refresh() + } + + private fun refresh() { + viewModelScope.launch { + try { + contributorsRepository.refresh() + } catch (e: AppError) { + appError = e + } } } + + fun onAppErrorNotified() { + appError = null + } } From 4fe77ca61da80c681f4f1340c7d9da9ef38da5d3 Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Sun, 25 Sep 2022 07:10:31 +0900 Subject: [PATCH 2/2] :memo: Change Moved the AppErrorSnackbarEffect class package to common. --- .../feature/{announcement => common}/AppErrorSnackbarEffect.kt | 2 +- .../confsched2022/feature/announcement/Announcements.kt | 1 + .../confsched2022/feature/contributors/Contributors.kt | 2 +- .../droidkaigi/confsched2022/feature/sessions/Sessions.kt | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) rename core/ui/src/main/java/io/github/droidkaigi/confsched2022/feature/{announcement => common}/AppErrorSnackbarEffect.kt (94%) diff --git a/core/ui/src/main/java/io/github/droidkaigi/confsched2022/feature/announcement/AppErrorSnackbarEffect.kt b/core/ui/src/main/java/io/github/droidkaigi/confsched2022/feature/common/AppErrorSnackbarEffect.kt similarity index 94% rename from core/ui/src/main/java/io/github/droidkaigi/confsched2022/feature/announcement/AppErrorSnackbarEffect.kt rename to core/ui/src/main/java/io/github/droidkaigi/confsched2022/feature/common/AppErrorSnackbarEffect.kt index 3d097df68..541924d60 100644 --- a/core/ui/src/main/java/io/github/droidkaigi/confsched2022/feature/announcement/AppErrorSnackbarEffect.kt +++ b/core/ui/src/main/java/io/github/droidkaigi/confsched2022/feature/common/AppErrorSnackbarEffect.kt @@ -1,4 +1,4 @@ -package io.github.droidkaigi.confsched2022.feature.announcement +package io.github.droidkaigi.confsched2022.feature.common import androidx.compose.material3.SnackbarDuration.Long import androidx.compose.material3.SnackbarHostState diff --git a/feature/announcement/src/main/java/io/github/droidkaigi/confsched2022/feature/announcement/Announcements.kt b/feature/announcement/src/main/java/io/github/droidkaigi/confsched2022/feature/announcement/Announcements.kt index 82547aa89..4a895143d 100644 --- a/feature/announcement/src/main/java/io/github/droidkaigi/confsched2022/feature/announcement/Announcements.kt +++ b/feature/announcement/src/main/java/io/github/droidkaigi/confsched2022/feature/announcement/Announcements.kt @@ -37,6 +37,7 @@ import io.github.droidkaigi.confsched2022.designsystem.components.KaigiScaffold import io.github.droidkaigi.confsched2022.designsystem.components.KaigiTopAppBar import io.github.droidkaigi.confsched2022.designsystem.theme.KaigiColors import io.github.droidkaigi.confsched2022.designsystem.theme.KaigiTheme +import io.github.droidkaigi.confsched2022.feature.common.AppErrorSnackbarEffect import io.github.droidkaigi.confsched2022.model.AnnouncementsByDate import io.github.droidkaigi.confsched2022.model.fakes import io.github.droidkaigi.confsched2022.strings.Strings diff --git a/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/Contributors.kt b/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/Contributors.kt index fc2d34275..a1517c0c3 100644 --- a/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/Contributors.kt +++ b/feature/contributors/src/main/java/io/github/droidkaigi/confsched2022/feature/contributors/Contributors.kt @@ -21,7 +21,7 @@ import io.github.droidkaigi.confsched2022.designsystem.components.KaigiScaffold import io.github.droidkaigi.confsched2022.designsystem.components.KaigiTopAppBar import io.github.droidkaigi.confsched2022.designsystem.components.UsernameRow import io.github.droidkaigi.confsched2022.designsystem.theme.KaigiTheme -import io.github.droidkaigi.confsched2022.feature.announcement.AppErrorSnackbarEffect +import io.github.droidkaigi.confsched2022.feature.common.AppErrorSnackbarEffect import io.github.droidkaigi.confsched2022.model.Contributor import io.github.droidkaigi.confsched2022.model.fakes import io.github.droidkaigi.confsched2022.strings.Strings diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2022/feature/sessions/Sessions.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2022/feature/sessions/Sessions.kt index eca80447e..319d388e4 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2022/feature/sessions/Sessions.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2022/feature/sessions/Sessions.kt @@ -66,7 +66,7 @@ import dev.icerock.moko.resources.compose.stringResource import io.github.droidkaigi.confsched2022.designsystem.components.KaigiScaffold import io.github.droidkaigi.confsched2022.designsystem.components.KaigiTopAppBar import io.github.droidkaigi.confsched2022.designsystem.theme.KaigiTheme -import io.github.droidkaigi.confsched2022.feature.announcement.AppErrorSnackbarEffect +import io.github.droidkaigi.confsched2022.feature.common.AppErrorSnackbarEffect import io.github.droidkaigi.confsched2022.model.DroidKaigi2022Day import io.github.droidkaigi.confsched2022.model.DroidKaigiSchedule import io.github.droidkaigi.confsched2022.model.TimetableItemId