Added basic implementation of error manager

This commit is contained in:
Abdelilah El Aissaoui 2021-10-26 18:59:52 +02:00
parent 469fe530ee
commit 40fe4c694f
3 changed files with 157 additions and 37 deletions

View File

@ -0,0 +1,34 @@
package app.app
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
class ErrorsManager @Inject constructor() {
private val _errorsList = MutableStateFlow(listOf<Error>())
val errorsList: StateFlow<List<Error>>
get() = _errorsList
private val _lastError = MutableStateFlow<Error?>(null)
val lastError: StateFlow<Error?>
get() = _lastError
fun addError(error: Error) {
_errorsList.value = _errorsList.value.toMutableList().apply {
add(error)
}
_lastError.value = error
}
fun removeError(error: Error) {
_errorsList.value = _errorsList.value.toMutableList().apply {
remove(error)
}
}
}
data class Error(val date: Long, val exception: Exception, val message: String)
fun newErrorNow(exception: Exception,message: String) = Error(System.currentTimeMillis(), exception, message)

View File

@ -12,6 +12,9 @@ import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.revwalk.RevCommit
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
import app.AppStateManager
import app.app.Error
import app.app.ErrorsManager
import app.app.newErrorNow
import java.io.File
import javax.inject.Inject
@ -23,6 +26,7 @@ class GitManager @Inject constructor(
private val branchesManager: BranchesManager,
private val stashManager: StashManager,
private val diffManager: DiffManager,
val errorsManager: ErrorsManager,
val appStateManager: AppStateManager,
) {
val repositoryName: String
@ -109,7 +113,7 @@ class GitManager @Inject constructor(
} catch (ex: Exception) {
ex.printStackTrace()
onRepositoryChanged(null)
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
}
}
}
@ -192,8 +196,10 @@ class GitManager @Inject constructor(
}
fun createBranch(branchName: String) = managerScope.launch {
branchesManager.createBranch(safeGit, branchName)
coLoadLog()
safeProcessing {
branchesManager.createBranch(safeGit, branchName)
coLoadLog()
}
}
fun deleteBranch(branch: Ref) = managerScope.launch {
@ -238,6 +244,8 @@ class GitManager @Inject constructor(
_processing.value = true
try {
callback()
} catch (ex: Exception) {
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
} finally {
_processing.value = false
}

View File

@ -1,30 +1,63 @@
package app.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.material.Card
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.DefaultAlpha
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import app.DialogManager
import app.LoadingRepository
import app.git.GitManager
import app.git.RepositorySelectionStatus
import app.ui.components.DialogBox
import kotlinx.coroutines.delay
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AppTab(gitManager: GitManager, dialogManager: DialogManager, repositoryPath: String?, tabName: MutableState<String>) {
fun AppTab(
gitManager: GitManager,
dialogManager: DialogManager,
repositoryPath: String?,
tabName: MutableState<String>
) {
LaunchedEffect(gitManager) {
if (repositoryPath != null)
gitManager.openRepository(repositoryPath)
}
val errorManager = remember(gitManager) { // TODO Is remember here necessary?
gitManager.errorsManager
}
val lastError by errorManager.lastError.collectAsState()
var showError by remember {
mutableStateOf(false)
}
if (lastError != null)
LaunchedEffect(lastError) {
showError = true
delay(5000)
showError = false
}
val repositorySelectionStatus by gitManager.repositorySelectionStatus.collectAsState()
val isProcessing by gitManager.processing.collectAsState()
@ -33,42 +66,87 @@ fun AppTab(gitManager: GitManager, dialogManager: DialogManager, repositoryPath:
tabName.value = gitManager.repositoryName
}
Column(
modifier = Modifier
.background(MaterialTheme.colors.background)
.fillMaxSize()
) {
val linearProgressAlpha = if (isProcessing)
DefaultAlpha
else
0f
LinearProgressIndicator(
Box {
Column(
modifier = Modifier
.fillMaxWidth()
.alpha(linearProgressAlpha)
)
.background(MaterialTheme.colors.background)
.fillMaxSize()
) {
Box(modifier = Modifier.fillMaxSize()) {
Crossfade(targetState = repositorySelectionStatus) {
val linearProgressAlpha = if (isProcessing)
DefaultAlpha
else
0f
@Suppress("UnnecessaryVariable") // Don't inline it because smart cast won't work
when (repositorySelectionStatus) {
RepositorySelectionStatus.None -> {
WelcomePage(gitManager = gitManager)
LinearProgressIndicator(
modifier = Modifier
.fillMaxWidth()
.alpha(linearProgressAlpha)
)
Box(modifier = Modifier.fillMaxSize()) {
Crossfade(targetState = repositorySelectionStatus) {
@Suppress("UnnecessaryVariable") // Don't inline it because smart cast won't work
when (repositorySelectionStatus) {
RepositorySelectionStatus.None -> {
WelcomePage(gitManager = gitManager)
}
RepositorySelectionStatus.Loading -> {
LoadingRepository()
}
is RepositorySelectionStatus.Open -> {
RepositoryOpenPage(gitManager = gitManager, dialogManager = dialogManager)
}
}
RepositorySelectionStatus.Loading -> {
LoadingRepository()
}
is RepositorySelectionStatus.Open -> {
RepositoryOpenPage(gitManager = gitManager, dialogManager = dialogManager)
}
if (isProcessing)
Box(modifier = Modifier.fillMaxSize()) //TODO this should block of the mouse/keyboard events while visible
}
}
val safeLastError = lastError
if (safeLastError != null) {
AnimatedVisibility(
visible = showError,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(end = 32.dp, bottom = 32.dp)
) {
val interactionSource = remember { MutableInteractionSource() }
Card(
modifier = Modifier
.defaultMinSize(minWidth = 200.dp, minHeight = 100.dp)
.clickable(
enabled = true,
onClick = {},
interactionSource = interactionSource,
indication = null
),
backgroundColor = MaterialTheme.colors.error,
) {
Column(
modifier = Modifier
.padding(horizontal = 32.dp)
) {
Text(
text = "Error",
fontSize = 20.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier
.padding(top = 16.dp)
) // TODO Add more descriptive title
Text(
text = safeLastError.message,
modifier = Modifier
.padding(top = 8.dp)
)
}
}
}
if (isProcessing)
Box(modifier = Modifier.fillMaxSize()) //TODO this should block of the mouse/keyboard events while visible
}
}
}