diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/git/TabState.kt b/src/main/kotlin/com/jetpackduba/gitnuro/git/TabState.kt index 3678674..5d52cd9 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/git/TabState.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/git/TabState.kt @@ -107,9 +107,7 @@ class TabState @Inject constructor( } if (positiveFeedbackText != null) { - launch { - errorsManager.emitPositiveNotification(positiveFeedbackText) - } + errorsManager.emitPositiveNotification(positiveFeedbackText) } } catch (ex: Exception) { hasProcessFailed = true diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/managers/ErrorsManager.kt b/src/main/kotlin/com/jetpackduba/gitnuro/managers/ErrorsManager.kt index e078bb0..bd5e10f 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/managers/ErrorsManager.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/managers/ErrorsManager.kt @@ -3,17 +3,16 @@ package com.jetpackduba.gitnuro.managers import com.jetpackduba.gitnuro.TaskType import com.jetpackduba.gitnuro.di.TabScope import com.jetpackduba.gitnuro.exceptions.GitnuroException -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.withContext +import com.jetpackduba.gitnuro.extensions.lockUse +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.sync.Mutex import javax.inject.Inject @TabScope -class ErrorsManager @Inject constructor() { +class ErrorsManager @Inject constructor( + private val coroutineScope: CoroutineScope +) { private val _errorsList = MutableStateFlow(listOf()) val errorsList: StateFlow> get() = _errorsList @@ -21,13 +20,32 @@ class ErrorsManager @Inject constructor() { private val _error = MutableSharedFlow() val error: SharedFlow = _error - private val _notification = MutableStateFlow(null) - val notification: StateFlow = _notification + private val _notification = MutableStateFlow>(hashMapOf()) + val notification: StateFlow> = _notification - suspend fun emitPositiveNotification(text: String) { - _notification.emit(text) - delay(2000) - _notification.emit(null) + private val notificationsMutex = Mutex() + + suspend fun emitPositiveNotification(text: String) = coroutineScope.launch { + val time = System.currentTimeMillis() + notificationsMutex.lockUse { + _notification.update { notifications -> + notifications + .toMutableMap() + .apply { put(time, text) } + } + } + + launch { + delay(2000) + + notificationsMutex.lockUse { + _notification.update { notifications -> + notifications + .toMutableMap() + .apply { remove(time) } + } + } + } } suspend fun addError(error: Error) = withContext(Dispatchers.IO) { diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/AppTab.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/AppTab.kt index de1d05e..f8ded32 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/AppTab.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/AppTab.kt @@ -1,11 +1,8 @@ package com.jetpackduba.gitnuro.ui -import androidx.compose.animation.* +import androidx.compose.animation.Crossfade 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.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -36,20 +33,15 @@ fun AppTab( val errorManager = tabViewModel.errorsManager val lastError by errorManager.error.collectAsState(null) val showError by tabViewModel.showError.collectAsState() - val notification = errorManager.notification.collectAsState().value - var visibleNotification by remember { mutableStateOf("") } -// val (tabPosition, setTabPosition) = remember { mutableStateOf(null) } + val notifications = errorManager.notification.collectAsState().value + .toList() + .sortedBy { it.first } + .map { it.second } val repositorySelectionStatus = tabViewModel.repositorySelectionStatus.collectAsState() val repositorySelectionStatusValue = repositorySelectionStatus.value val processingState = tabViewModel.processing.collectAsState().value - LaunchedEffect(notification) { - if (notification != null) { - visibleNotification = notification - } - } - LaunchedEffect(tabViewModel) { // Init the tab content when the tab is selected and also remove the "initialPath" to avoid opening the // repository everytime the user changes between tabs @@ -135,22 +127,24 @@ fun AppTab( ) } - AnimatedVisibility( - visible = notification != null, - modifier = Modifier.align(Alignment.BottomCenter), - enter = fadeIn() + slideInVertically { it * 2 }, - exit = fadeOut() + slideOutVertically { it * 2 }, + Column( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter) + .padding(bottom = 48.dp), + horizontalAlignment = Alignment.CenterHorizontally, ) { - Text( - text = visibleNotification, - modifier = Modifier - .padding(bottom = 48.dp) - .clip(RoundedCornerShape(8.dp)) - .background(MaterialTheme.colors.primary) - .padding(8.dp), - color = MaterialTheme.colors.onPrimary, - style = MaterialTheme.typography.body1, - ) + for (notification in notifications) + Text( + text = notification, + modifier = Modifier + .padding(bottom = 12.dp) + .clip(RoundedCornerShape(8.dp)) + .background(MaterialTheme.colors.primary) + .padding(8.dp), + color = MaterialTheme.colors.onPrimary, + style = MaterialTheme.typography.body1, + ) } } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/StatusViewModel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/StatusViewModel.kt index 05caad3..0351c89 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/StatusViewModel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/StatusViewModel.kt @@ -349,7 +349,7 @@ class StatusViewModel @Inject constructor( fun commit(message: String) = tabState.safeProcessing( refreshType = RefreshType.ALL_DATA, taskType = TaskType.DO_COMMIT, - positiveFeedbackText = "New commit added", + positiveFeedbackText = if (isAmend.value) "Commit amended" else "New commit created", ) { git -> val amend = isAmend.value