Implemented manual refresh with F5

This commit is contained in:
Abdelilah El Aissaoui 2022-06-27 20:36:24 +02:00
parent 0f835edc35
commit 4c48cd995e
3 changed files with 195 additions and 159 deletions

View File

@ -115,34 +115,36 @@ class TabState @Inject constructor(
refreshEvenIfCrashes: Boolean = false,
block: suspend (git: Git) -> Unit
) = managerScope.launch(Dispatchers.IO) {
var hasProcessFailed = false
mutex.withLock {
var hasProcessFailed = false
operationRunning = true
try {
block(safeGit)
operationRunning = true
try {
block(safeGit)
if (refreshType != RefreshType.NONE)
_refreshData.emit(refreshType)
} catch (ex: Exception) {
ex.printStackTrace()
if (refreshType != RefreshType.NONE)
_refreshData.emit(refreshType)
} catch (ex: Exception) {
ex.printStackTrace()
hasProcessFailed = true
hasProcessFailed = true
if (showError)
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
} finally {
launch {
// Add a slight delay because sometimes the file watcher takes a few moments to notify a change in the
// filesystem, therefore notifying late and being operationRunning already false (which leads to a full
// refresh because there have been changes in the git dir). This can be easily triggered by interactive
// rebase.
delay(500)
operationRunning = false
if (showError)
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
} finally {
launch {
// Add a slight delay because sometimes the file watcher takes a few moments to notify a change in the
// filesystem, therefore notifying late and being operationRunning already false (which leads to a full
// refresh because there have been changes in the git dir). This can be easily triggered by interactive
// rebase.
delay(500)
operationRunning = false
}
if (refreshType != RefreshType.NONE && (!hasProcessFailed || refreshEvenIfCrashes))
_refreshData.emit(refreshType)
}
if (refreshType != RefreshType.NONE && (!hasProcessFailed || refreshEvenIfCrashes))
_refreshData.emit(refreshType)
}
}
@ -152,34 +154,36 @@ class TabState @Inject constructor(
refreshEvenIfCrashes: Boolean = false,
block: suspend (git: Git) -> Unit
) = withContext(Dispatchers.IO) {
var hasProcessFailed = false
mutex.withLock {
var hasProcessFailed = false
operationRunning = true
try {
block(safeGit)
operationRunning = true
try {
block(safeGit)
if (refreshType != RefreshType.NONE)
_refreshData.emit(refreshType)
} catch (ex: Exception) {
ex.printStackTrace()
if (refreshType != RefreshType.NONE)
_refreshData.emit(refreshType)
} catch (ex: Exception) {
ex.printStackTrace()
hasProcessFailed = true
hasProcessFailed = true
if (showError)
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
} finally {
launch {
// Add a slight delay because sometimes the file watcher takes a few moments to notify a change in the
// filesystem, therefore notifying late and being operationRunning already false (which leads to a full
// refresh because there have been changes in the git dir). This can be easily triggered by interactive
// rebase.
delay(500)
operationRunning = false
if (showError)
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
} finally {
launch {
// Add a slight delay because sometimes the file watcher takes a few moments to notify a change in the
// filesystem, therefore notifying late and being operationRunning already false (which leads to a full
// refresh because there have been changes in the git dir). This can be easily triggered by interactive
// rebase.
delay(500)
operationRunning = false
}
if (refreshType != RefreshType.NONE && (!hasProcessFailed || refreshEvenIfCrashes))
_refreshData.emit(refreshType)
}
if (refreshType != RefreshType.NONE && (!hasProcessFailed || refreshEvenIfCrashes))
_refreshData.emit(refreshType)
}
}

View File

@ -3,13 +3,21 @@
package app.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.pointer.PointerIcon
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.unit.dp
@ -79,7 +87,25 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
}
}
Column {
val focusRequester = remember { FocusRequester() }
LaunchedEffect(selectedItem) {
focusRequester.requestFocus()
}
Column(
modifier = Modifier
.focusRequester(focusRequester)
.focusable()
.onKeyEvent { event ->
if (event.key == Key.F5) {
tabViewModel.refreshAll()
true
} else {
false
}
}
) {
val rebaseInteractiveViewModel = tabViewModel.rebaseInteractiveViewModel
if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) {
@ -166,6 +192,7 @@ fun RepoContent(
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun MainContentView(
tabViewModel: TabViewModel,
@ -174,134 +201,132 @@ fun MainContentView(
repositoryState: RepositoryState,
blameState: BlameState
) {
Row {
HorizontalSplitPane {
first(minSize = 250.dp) {
ScrollableColumn(modifier = Modifier.fillMaxHeight( )) {
Branches(
branchesViewModel = tabViewModel.branchesViewModel,
)
Remotes(
remotesViewModel = tabViewModel.remotesViewModel,
)
Tags(
tagsViewModel = tabViewModel.tagsViewModel,
)
Stashes(
stashesViewModel = tabViewModel.stashesViewModel,
)
}
HorizontalSplitPane {
first(minSize = 250.dp) {
ScrollableColumn(modifier = Modifier.fillMaxHeight()) {
Branches(
branchesViewModel = tabViewModel.branchesViewModel,
)
Remotes(
remotesViewModel = tabViewModel.remotesViewModel,
)
Tags(
tagsViewModel = tabViewModel.tagsViewModel,
)
Stashes(
stashesViewModel = tabViewModel.stashesViewModel,
)
}
}
splitter {
this.repositorySplitter()
}
splitter {
this.repositorySplitter()
}
second {
HorizontalSplitPane(
splitPaneState = rememberSplitPaneState(0.9f)
) {
first {
Box(
modifier = Modifier
.fillMaxSize()
) {
if (blameState is BlameState.Loaded && !blameState.isMinimized) {
Blame(
filePath = blameState.filePath,
blameResult = blameState.blameResult,
onClose = { tabViewModel.resetBlameState() },
onSelectCommit = { tabViewModel.selectCommit(it) }
)
} else {
Column {
Box(modifier = Modifier.weight(1f, true)) {
when (diffSelected) {
null -> {
Log(
logViewModel = tabViewModel.logViewModel,
selectedItem = selectedItem,
repositoryState = repositoryState,
second {
HorizontalSplitPane(
splitPaneState = rememberSplitPaneState(0.9f)
) {
first {
Box(
modifier = Modifier
.fillMaxSize()
) {
if (blameState is BlameState.Loaded && !blameState.isMinimized) {
Blame(
filePath = blameState.filePath,
blameResult = blameState.blameResult,
onClose = { tabViewModel.resetBlameState() },
onSelectCommit = { tabViewModel.selectCommit(it) }
)
} else {
Column {
Box(modifier = Modifier.weight(1f, true)) {
when (diffSelected) {
null -> {
Log(
logViewModel = tabViewModel.logViewModel,
selectedItem = selectedItem,
repositoryState = repositoryState,
)
}
else -> {
val diffViewModel = tabViewModel.diffViewModel
if (diffViewModel != null) {
Diff(
diffViewModel = diffViewModel,
onCloseDiffView = {
tabViewModel.newDiffSelected = null
}
)
}
else -> {
val diffViewModel = tabViewModel.diffViewModel
if (diffViewModel != null) {
Diff(
diffViewModel = diffViewModel,
onCloseDiffView = {
tabViewModel.newDiffSelected = null
}
)
}
}
}
}
}
if (blameState is BlameState.Loaded) { // BlameState.isMinimized is true here
MinimizedBlame(
filePath = blameState.filePath,
onExpand = { tabViewModel.expandBlame() },
onClose = { tabViewModel.resetBlameState() }
)
}
if (blameState is BlameState.Loaded) { // BlameState.isMinimized is true here
MinimizedBlame(
filePath = blameState.filePath,
onExpand = { tabViewModel.expandBlame() },
onClose = { tabViewModel.resetBlameState() }
)
}
}
}
}
}
splitter {
this.repositorySplitter()
}
splitter {
this.repositorySplitter()
}
second(minSize = 300.dp) {
Box(
modifier = Modifier
.fillMaxHeight()
) {
val safeSelectedItem = selectedItem
if (safeSelectedItem == SelectedItem.UncommitedChanges) {
UncommitedChanges(
statusViewModel = tabViewModel.statusViewModel,
selectedEntryType = diffSelected,
repositoryState = repositoryState,
onStagedDiffEntrySelected = { diffEntry ->
tabViewModel.minimizeBlame()
tabViewModel.newDiffSelected = if (diffEntry != null) {
if (repositoryState == RepositoryState.SAFE)
DiffEntryType.SafeStagedDiff(diffEntry)
else
DiffEntryType.UnsafeStagedDiff(diffEntry)
} else {
null
}
},
onUnstagedDiffEntrySelected = { diffEntry ->
tabViewModel.minimizeBlame()
second(minSize = 300.dp) {
Box(
modifier = Modifier
.fillMaxHeight()
) {
val safeSelectedItem = selectedItem
if (safeSelectedItem == SelectedItem.UncommitedChanges) {
UncommitedChanges(
statusViewModel = tabViewModel.statusViewModel,
selectedEntryType = diffSelected,
repositoryState = repositoryState,
onStagedDiffEntrySelected = { diffEntry ->
tabViewModel.minimizeBlame()
tabViewModel.newDiffSelected = if (diffEntry != null) {
if (repositoryState == RepositoryState.SAFE)
tabViewModel.newDiffSelected = DiffEntryType.SafeUnstagedDiff(diffEntry)
DiffEntryType.SafeStagedDiff(diffEntry)
else
tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry)
},
onBlameFile = { tabViewModel.blameFile(it) },
onHistoryFile = { tabViewModel.fileHistory(it) }
)
} else if (safeSelectedItem is SelectedItem.CommitBasedItem) {
CommitChanges(
commitChangesViewModel = tabViewModel.commitChangesViewModel,
selectedItem = safeSelectedItem,
diffSelected = diffSelected,
onDiffSelected = { diffEntry ->
tabViewModel.minimizeBlame()
tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry)
},
onBlame = { tabViewModel.blameFile(it) },
onHistory = { tabViewModel.fileHistory(it) },
)
}
DiffEntryType.UnsafeStagedDiff(diffEntry)
} else {
null
}
},
onUnstagedDiffEntrySelected = { diffEntry ->
tabViewModel.minimizeBlame()
if (repositoryState == RepositoryState.SAFE)
tabViewModel.newDiffSelected = DiffEntryType.SafeUnstagedDiff(diffEntry)
else
tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry)
},
onBlameFile = { tabViewModel.blameFile(it) },
onHistoryFile = { tabViewModel.fileHistory(it) }
)
} else if (safeSelectedItem is SelectedItem.CommitBasedItem) {
CommitChanges(
commitChangesViewModel = tabViewModel.commitChangesViewModel,
selectedItem = safeSelectedItem,
diffSelected = diffSelected,
onDiffSelected = { diffEntry ->
tabViewModel.minimizeBlame()
tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry)
},
onBlame = { tabViewModel.blameFile(it) },
onHistory = { tabViewModel.fileHistory(it) },
)
}
}
}

View File

@ -313,7 +313,7 @@ class TabViewModel @Inject constructor(
loadRepositoryState(git)
}
private suspend fun refreshRepositoryInfo() = tabState.safeProcessing(
private fun refreshRepositoryInfo() = tabState.safeProcessing(
refreshType = RefreshType.NONE,
) { git ->
loadRepositoryState(git)
@ -427,6 +427,13 @@ class TabViewModel @Inject constructor(
_showHistory.value = false
historyViewModel = null
}
fun refreshAll() {
printLog(TAG, "Manual refresh triggered")
if (!tabState.operationRunning) {
refreshRepositoryInfo()
}
}
}