Renamed CloneStatus to CloneState

This commit is contained in:
Abdelilah El Aissaoui 2023-04-25 22:29:06 +02:00
parent 50fff76b1f
commit 35d7b23913
No known key found for this signature in database
GPG Key ID: 7587FC860F594869
4 changed files with 46 additions and 56 deletions

View File

@ -3,12 +3,12 @@ package com.jetpackduba.gitnuro.git
import org.eclipse.jgit.transport.RemoteRefUpdate import org.eclipse.jgit.transport.RemoteRefUpdate
import java.io.File import java.io.File
sealed class CloneStatus { sealed class CloneState {
object None : CloneStatus() object None : CloneState()
data class Cloning(val taskName: String, val progress: Int, val total: Int) : CloneStatus() data class Cloning(val taskName: String, val progress: Int, val total: Int) : CloneState()
object Cancelling : CloneStatus() object Cancelling : CloneState()
data class Fail(val reason: String) : CloneStatus() data class Fail(val reason: String) : CloneState()
data class Completed(val repoDir: File) : CloneStatus() data class Completed(val repoDir: File) : CloneState()
} }
val RemoteRefUpdate.Status.isRejected: Boolean val RemoteRefUpdate.Status.isRejected: Boolean

View File

@ -1,6 +1,6 @@
package com.jetpackduba.gitnuro.git.remote_operations package com.jetpackduba.gitnuro.git.remote_operations
import com.jetpackduba.gitnuro.git.CloneStatus import com.jetpackduba.gitnuro.git.CloneState
import com.jetpackduba.gitnuro.logging.printDebug import com.jetpackduba.gitnuro.logging.printDebug
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
@ -18,14 +18,14 @@ private const val TAG = "CloneRepositoryUseCase"
class CloneRepositoryUseCase @Inject constructor( class CloneRepositoryUseCase @Inject constructor(
private val handleTransportUseCase: HandleTransportUseCase, private val handleTransportUseCase: HandleTransportUseCase,
) { ) {
operator fun invoke(directory: File, url: String, cloneSubmodules: Boolean): Flow<CloneStatus> = callbackFlow { operator fun invoke(directory: File, url: String, cloneSubmodules: Boolean): Flow<CloneState> = callbackFlow {
var lastTitle: String = "" var lastTitle: String = ""
var lastTotalWork = 0 var lastTotalWork = 0
var progress = 0 var progress = 0
try { try {
ensureActive() ensureActive()
trySend(CloneStatus.Cloning("Starting...", progress, lastTotalWork)) trySend(CloneState.Cloning("Starting...", progress, lastTotalWork))
Git.cloneRepository() Git.cloneRepository()
.setDirectory(directory) .setDirectory(directory)
@ -41,7 +41,7 @@ class CloneRepositoryUseCase @Inject constructor(
lastTitle = title.orEmpty() lastTitle = title.orEmpty()
lastTotalWork = totalWork lastTotalWork = totalWork
progress = 0 progress = 0
trySend(CloneStatus.Cloning(lastTitle, progress, lastTotalWork)) trySend(CloneState.Cloning(lastTitle, progress, lastTotalWork))
} }
override fun update(completed: Int) { override fun update(completed: Int) {
@ -49,7 +49,7 @@ class CloneRepositoryUseCase @Inject constructor(
ensureActive() ensureActive()
progress += completed progress += completed
trySend(CloneStatus.Cloning(lastTitle, progress, lastTotalWork)) trySend(CloneState.Cloning(lastTitle, progress, lastTotalWork))
} }
override fun endTask() { override fun endTask() {
@ -68,13 +68,13 @@ class CloneRepositoryUseCase @Inject constructor(
.call() .call()
ensureActive() ensureActive()
trySend(CloneStatus.Completed(directory)) trySend(CloneState.Completed(directory))
channel.close() channel.close()
} catch (ex: Exception) { } catch (ex: Exception) {
if (ex.cause?.cause is CancellationException) { if (ex.cause?.cause is CancellationException) {
printDebug(TAG, "Clone cancelled") printDebug(TAG, "Clone cancelled")
} else { } else {
trySend(CloneStatus.Fail(ex.localizedMessage)) trySend(CloneState.Fail(ex.localizedMessage))
} }
channel.close() channel.close()

View File

@ -1,5 +1,6 @@
package com.jetpackduba.gitnuro.ui.dialogs package com.jetpackduba.gitnuro.ui.dialogs
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
@ -20,7 +21,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.jetpackduba.gitnuro.extensions.handMouseClickable import com.jetpackduba.gitnuro.extensions.handMouseClickable
import com.jetpackduba.gitnuro.git.CloneStatus import com.jetpackduba.gitnuro.git.CloneState
import com.jetpackduba.gitnuro.theme.outlinedTextFieldColors import com.jetpackduba.gitnuro.theme.outlinedTextFieldColors
import com.jetpackduba.gitnuro.theme.textButtonColors import com.jetpackduba.gitnuro.theme.textButtonColors
@ -36,7 +37,7 @@ fun CloneDialog(
onClose: () -> Unit, onClose: () -> Unit,
onOpenRepository: (File) -> Unit, onOpenRepository: (File) -> Unit,
) { ) {
val cloneStatus = cloneViewModel.cloneStatus.collectAsState() val cloneStatus = cloneViewModel.cloneState.collectAsState()
val cloneStatusValue = cloneStatus.value val cloneStatusValue = cloneStatus.value
MaterialDialog( MaterialDialog(
@ -46,30 +47,29 @@ fun CloneDialog(
Box( Box(
modifier = Modifier modifier = Modifier
.width(720.dp) .width(720.dp)
.height(280.dp)
.animateContentSize() .animateContentSize()
) { ) {
when (cloneStatusValue) { when (cloneStatusValue) {
is CloneStatus.Cloning -> { is CloneState.Cloning -> {
Cloning(cloneViewModel, cloneStatusValue) Cloning(cloneViewModel, cloneStatusValue)
} }
is CloneStatus.Cancelling -> { is CloneState.Cancelling -> {
Cancelling() Cancelling()
} }
is CloneStatus.Completed -> { is CloneState.Completed -> {
onOpenRepository(cloneStatusValue.repoDir) onOpenRepository(cloneStatusValue.repoDir)
onClose() onClose()
} }
is CloneStatus.Fail -> CloneInput( is CloneState.Fail -> CloneInput(
cloneViewModel = cloneViewModel, cloneViewModel = cloneViewModel,
onClose = onClose, onClose = onClose,
errorMessage = cloneStatusValue.reason errorMessage = cloneStatusValue.reason
) )
CloneStatus.None -> CloneInput( CloneState.None -> CloneInput(
cloneViewModel = cloneViewModel, cloneViewModel = cloneViewModel,
onClose = onClose, onClose = onClose,
) )
@ -94,10 +94,6 @@ private fun CloneInput(
val cloneButtonFocusRequester = remember { FocusRequester() } val cloneButtonFocusRequester = remember { FocusRequester() }
val cancelButtonFocusRequester = remember { FocusRequester() } val cancelButtonFocusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) {
urlFocusRequester.requestFocus()
}
Column( Column(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
.padding(horizontal = 8.dp) .padding(horizontal = 8.dp)
@ -133,7 +129,7 @@ private fun CloneInput(
) { ) {
TextInput( TextInput(
modifier = Modifier.weight(1f), modifier = Modifier.padding(top = 16.dp),
title = "Directory", title = "Directory",
value = directory, value = directory,
focusRequester = directoryFocusRequester, focusRequester = directoryFocusRequester,
@ -204,7 +200,7 @@ private fun CloneInput(
) )
} }
if (errorMessage != null) { AnimatedVisibility (errorMessage != null) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -213,17 +209,15 @@ private fun CloneInput(
.background(MaterialTheme.colors.error) .background(MaterialTheme.colors.error)
) { ) {
Text( Text(
errorMessage, errorMessage.orEmpty(),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = 4.dp, horizontal = 8.dp), .padding(vertical = 4.dp, horizontal = 8.dp),
color = MaterialTheme.colors.onError, color = MaterialTheme.colors.onError,
) )
} }
} }
Spacer(Modifier.weight(1f))
Row( Row(
modifier = Modifier modifier = Modifier
.padding(top = 16.dp) .padding(top = 16.dp)
@ -258,18 +252,18 @@ private fun CloneInput(
} }
@Composable @Composable
private fun Cloning(cloneViewModel: CloneViewModel, cloneStatusValue: CloneStatus.Cloning) { private fun Cloning(cloneViewModel: CloneViewModel, cloneStateValue: CloneState.Cloning) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize(), .fillMaxWidth(),
) { ) {
val progress = remember(cloneStatusValue) { val progress = remember(cloneStateValue) {
val total = cloneStatusValue.total val total = cloneStateValue.total
if (total == 0) // Prevent division by 0 if (total == 0) // Prevent division by 0
-1f -1f
else else
cloneStatusValue.progress / total.toFloat() cloneStateValue.progress / total.toFloat()
} }
Column( Column(
@ -278,7 +272,7 @@ private fun Cloning(cloneViewModel: CloneViewModel, cloneStatusValue: CloneStatu
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Text(cloneStatusValue.taskName, color = MaterialTheme.colors.onBackground) Text(cloneStateValue.taskName, color = MaterialTheme.colors.onBackground)
if (progress >= 0f) if (progress >= 0f)
CircularProgressIndicator( CircularProgressIndicator(
@ -318,7 +312,7 @@ private fun Cloning(cloneViewModel: CloneViewModel, cloneStatusValue: CloneStatu
private fun Cancelling() { private fun Cancelling() {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize(), .fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
) { ) {
@ -346,23 +340,19 @@ private fun TextInput(
onValueChange: (String) -> Unit, onValueChange: (String) -> Unit,
textFieldShape: Shape = RoundedCornerShape(4.dp), textFieldShape: Shape = RoundedCornerShape(4.dp),
) { ) {
Row( Column(
modifier = modifier modifier = modifier,
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) { ) {
Text( Text(
text = title, text = title,
style = MaterialTheme.typography.body1, style = MaterialTheme.typography.body1,
modifier = Modifier modifier = Modifier
.width(100.dp) .padding(bottom = 8.dp),
.padding(end = 16.dp),
) )
AdjustableOutlinedTextField( AdjustableOutlinedTextField(
value = value, value = value,
modifier = Modifier modifier = Modifier
.weight(1f)
.focusRequester(focusRequester) .focusRequester(focusRequester)
.focusProperties(focusProperties), .focusProperties(focusProperties),
enabled = enabled, enabled = enabled,

View File

@ -1,6 +1,6 @@
package com.jetpackduba.gitnuro.viewmodels package com.jetpackduba.gitnuro.viewmodels
import com.jetpackduba.gitnuro.git.CloneStatus import com.jetpackduba.gitnuro.git.CloneState
import com.jetpackduba.gitnuro.git.TabState import com.jetpackduba.gitnuro.git.TabState
import com.jetpackduba.gitnuro.git.remote_operations.CloneRepositoryUseCase import com.jetpackduba.gitnuro.git.remote_operations.CloneRepositoryUseCase
import com.jetpackduba.gitnuro.system.OpenFilePickerUseCase import com.jetpackduba.gitnuro.system.OpenFilePickerUseCase
@ -20,9 +20,9 @@ class CloneViewModel @Inject constructor(
private val openFilePickerUseCase: OpenFilePickerUseCase, private val openFilePickerUseCase: OpenFilePickerUseCase,
) { ) {
private val _cloneStatus = MutableStateFlow<CloneStatus>(CloneStatus.None) private val _cloneState = MutableStateFlow<CloneState>(CloneState.None)
val cloneStatus: StateFlow<CloneStatus> val cloneState: StateFlow<CloneState>
get() = _cloneStatus get() = _cloneState
var url: String = "" var url: String = ""
var directory: String = "" var directory: String = ""
@ -32,12 +32,12 @@ class CloneViewModel @Inject constructor(
fun clone(directoryPath: String, url: String, cloneSubmodules: Boolean) { fun clone(directoryPath: String, url: String, cloneSubmodules: Boolean) {
cloneJob = tabState.safeProcessingWithoutGit { cloneJob = tabState.safeProcessingWithoutGit {
if (directoryPath.isBlank()) { if (directoryPath.isBlank()) {
_cloneStatus.value = CloneStatus.Fail("Invalid empty directory") _cloneState.value = CloneState.Fail("Invalid empty directory")
return@safeProcessingWithoutGit return@safeProcessingWithoutGit
} }
if (url.isBlank()) { if (url.isBlank()) {
_cloneStatus.value = CloneStatus.Fail("Invalid empty URL") _cloneState.value = CloneState.Fail("Invalid empty URL")
return@safeProcessingWithoutGit return@safeProcessingWithoutGit
} }
@ -57,7 +57,7 @@ class CloneViewModel @Inject constructor(
} }
if (repoName.isNullOrBlank()) { if (repoName.isNullOrBlank()) {
_cloneStatus.value = CloneStatus.Fail("Check your URL and try again") _cloneState.value = CloneState.Fail("Check your URL and try again")
return@safeProcessingWithoutGit return@safeProcessingWithoutGit
} }
@ -75,25 +75,25 @@ class CloneViewModel @Inject constructor(
cloneRepositoryUseCase(repoDir, url, cloneSubmodules) cloneRepositoryUseCase(repoDir, url, cloneSubmodules)
.flowOn(Dispatchers.IO) .flowOn(Dispatchers.IO)
.collect { newCloneStatus -> .collect { newCloneStatus ->
_cloneStatus.value = newCloneStatus _cloneState.value = newCloneStatus
} }
} }
} }
fun reset() { fun reset() {
_cloneStatus.value = CloneStatus.None _cloneState.value = CloneState.None
url = "" url = ""
directory = "" directory = ""
} }
fun cancelClone() = tabState.safeProcessingWithoutGit { fun cancelClone() = tabState.safeProcessingWithoutGit {
_cloneStatus.value = CloneStatus.Cancelling _cloneState.value = CloneState.Cancelling
cloneJob?.cancelAndJoin() cloneJob?.cancelAndJoin()
_cloneStatus.value = CloneStatus.None _cloneState.value = CloneState.None
} }
fun resetStateIfError() { fun resetStateIfError() {
_cloneStatus.value = CloneStatus.None _cloneState.value = CloneState.None
} }
fun openDirectoryPicker(): String? { fun openDirectoryPicker(): String? {