gracefully handling errors within the profile screen

This commit is contained in:
Adam Brown 2022-04-25 23:09:20 +01:00
parent 347074b10f
commit 21be4a4b1d
5 changed files with 38 additions and 4 deletions

View File

@ -161,7 +161,7 @@ internal class FeatureModules internal constructor(
coroutineDispatchers coroutineDispatchers
) )
} }
val profileModule by unsafeLazy { ProfileModule(matrixModules.profile, matrixModules.sync, matrixModules.room) } val profileModule by unsafeLazy { ProfileModule(matrixModules.profile, matrixModules.sync, matrixModules.room, trackingModule.errorTracker) }
val notificationsModule by unsafeLazy { val notificationsModule by unsafeLazy {
NotificationsModule( NotificationsModule(
matrixModules.push, matrixModules.push,

View File

@ -0,0 +1,22 @@
package app.dapk.st.design.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@Composable
fun GenericError(retryAction: () -> Unit) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("Something went wrong...")
Button(onClick = { retryAction() }) {
Text("Retry")
}
}
}
}

View File

@ -1,6 +1,7 @@
package app.dapk.st.profile package app.dapk.st.profile
import app.dapk.st.core.ProvidableModule import app.dapk.st.core.ProvidableModule
import app.dapk.st.core.extensions.ErrorTracker
import app.dapk.st.matrix.room.ProfileService import app.dapk.st.matrix.room.ProfileService
import app.dapk.st.matrix.room.RoomService import app.dapk.st.matrix.room.RoomService
import app.dapk.st.matrix.sync.SyncService import app.dapk.st.matrix.sync.SyncService
@ -9,10 +10,11 @@ class ProfileModule(
private val profileService: ProfileService, private val profileService: ProfileService,
private val syncService: SyncService, private val syncService: SyncService,
private val roomService: RoomService, private val roomService: RoomService,
private val errorTracker: ErrorTracker,
) : ProvidableModule { ) : ProvidableModule {
fun profileViewModel(): ProfileViewModel { fun profileViewModel(): ProfileViewModel {
return ProfileViewModel(profileService, syncService, roomService) return ProfileViewModel(profileService, syncService, roomService, errorTracker)
} }
} }

View File

@ -67,6 +67,7 @@ private fun ProfilePage(context: Context, viewModel: ProfileViewModel, profile:
when (val state = profile.content) { when (val state = profile.content) {
is Lce.Loading -> CenteredLoading() is Lce.Loading -> CenteredLoading()
is Lce.Error -> GenericError { viewModel.start() }
is Lce.Content -> { is Lce.Content -> {
val configuration = LocalConfiguration.current val configuration = LocalConfiguration.current
val content = state.value val content = state.value

View File

@ -2,6 +2,7 @@ package app.dapk.st.profile
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import app.dapk.st.core.Lce import app.dapk.st.core.Lce
import app.dapk.st.core.extensions.ErrorTracker
import app.dapk.st.design.components.SpiderPage import app.dapk.st.design.components.SpiderPage
import app.dapk.st.matrix.common.RoomId import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.room.ProfileService import app.dapk.st.matrix.room.ProfileService
@ -16,6 +17,7 @@ class ProfileViewModel(
private val profileService: ProfileService, private val profileService: ProfileService,
private val syncService: SyncService, private val syncService: SyncService,
private val roomService: RoomService, private val roomService: RoomService,
private val errorTracker: ErrorTracker,
) : DapkViewModel<ProfileScreenState, ProfileEvent>( ) : DapkViewModel<ProfileScreenState, ProfileEvent>(
ProfileScreenState(SpiderPage(Page.Routes.profile, "Profile", null, Page.Profile(Lce.Loading()), hasToolbar = false)) ProfileScreenState(SpiderPage(Page.Routes.profile, "Profile", null, Page.Profile(Lce.Loading()), hasToolbar = false))
) { ) {
@ -31,13 +33,20 @@ class ProfileViewModel(
syncingJob = syncService.startSyncing().launchIn(viewModelScope) syncingJob = syncService.startSyncing().launchIn(viewModelScope)
combine( combine(
flow { emit(profileService.me(forceRefresh = true)) }, flow {
val result = runCatching { profileService.me(forceRefresh = true) }
.onFailure { errorTracker.track(it, "Loading profile") }
emit(result)
},
syncService.invites(), syncService.invites(),
transform = { me, invites -> me to invites } transform = { me, invites -> me to invites }
) )
.onEach { (me, invites) -> .onEach { (me, invites) ->
updatePageState<Page.Profile> { updatePageState<Page.Profile> {
copy(content = Lce.Content(Page.Profile.Content(me, invites.size))) when (me.isSuccess) {
true -> copy(content = Lce.Content(Page.Profile.Content(me.getOrThrow(), invites.size)))
false -> copy(content = Lce.Error(me.exceptionOrNull()!!))
}
} }
} }
.launchPageJob() .launchPageJob()