Implemented manual refresh with F5
This commit is contained in:
parent
0f835edc35
commit
4c48cd995e
@ -115,34 +115,36 @@ class TabState @Inject constructor(
|
|||||||
refreshEvenIfCrashes: Boolean = false,
|
refreshEvenIfCrashes: Boolean = false,
|
||||||
block: suspend (git: Git) -> Unit
|
block: suspend (git: Git) -> Unit
|
||||||
) = managerScope.launch(Dispatchers.IO) {
|
) = managerScope.launch(Dispatchers.IO) {
|
||||||
var hasProcessFailed = false
|
mutex.withLock {
|
||||||
|
var hasProcessFailed = false
|
||||||
|
|
||||||
operationRunning = true
|
operationRunning = true
|
||||||
try {
|
try {
|
||||||
block(safeGit)
|
block(safeGit)
|
||||||
|
|
||||||
if (refreshType != RefreshType.NONE)
|
if (refreshType != RefreshType.NONE)
|
||||||
_refreshData.emit(refreshType)
|
_refreshData.emit(refreshType)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
|
|
||||||
hasProcessFailed = true
|
hasProcessFailed = true
|
||||||
|
|
||||||
if (showError)
|
if (showError)
|
||||||
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
|
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
|
||||||
} finally {
|
} finally {
|
||||||
launch {
|
launch {
|
||||||
// Add a slight delay because sometimes the file watcher takes a few moments to notify a change in the
|
// 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
|
// 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
|
// refresh because there have been changes in the git dir). This can be easily triggered by interactive
|
||||||
// rebase.
|
// rebase.
|
||||||
delay(500)
|
delay(500)
|
||||||
operationRunning = false
|
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,
|
refreshEvenIfCrashes: Boolean = false,
|
||||||
block: suspend (git: Git) -> Unit
|
block: suspend (git: Git) -> Unit
|
||||||
) = withContext(Dispatchers.IO) {
|
) = withContext(Dispatchers.IO) {
|
||||||
var hasProcessFailed = false
|
mutex.withLock {
|
||||||
|
var hasProcessFailed = false
|
||||||
|
|
||||||
operationRunning = true
|
operationRunning = true
|
||||||
try {
|
try {
|
||||||
block(safeGit)
|
block(safeGit)
|
||||||
|
|
||||||
if (refreshType != RefreshType.NONE)
|
if (refreshType != RefreshType.NONE)
|
||||||
_refreshData.emit(refreshType)
|
_refreshData.emit(refreshType)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
|
|
||||||
hasProcessFailed = true
|
hasProcessFailed = true
|
||||||
|
|
||||||
if (showError)
|
if (showError)
|
||||||
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
|
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
|
||||||
} finally {
|
} finally {
|
||||||
launch {
|
launch {
|
||||||
// Add a slight delay because sometimes the file watcher takes a few moments to notify a change in the
|
// 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
|
// 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
|
// refresh because there have been changes in the git dir). This can be easily triggered by interactive
|
||||||
// rebase.
|
// rebase.
|
||||||
delay(500)
|
delay(500)
|
||||||
operationRunning = false
|
operationRunning = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (refreshType != RefreshType.NONE && (!hasProcessFailed || refreshEvenIfCrashes))
|
||||||
|
_refreshData.emit(refreshType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (refreshType != RefreshType.NONE && (!hasProcessFailed || refreshEvenIfCrashes))
|
|
||||||
_refreshData.emit(refreshType)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,13 +3,21 @@
|
|||||||
package app.ui
|
package app.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.focusable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
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.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.PointerIcon
|
||||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||||
import androidx.compose.ui.unit.dp
|
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
|
val rebaseInteractiveViewModel = tabViewModel.rebaseInteractiveViewModel
|
||||||
|
|
||||||
if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) {
|
if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) {
|
||||||
@ -166,6 +192,7 @@ fun RepoContent(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainContentView(
|
fun MainContentView(
|
||||||
tabViewModel: TabViewModel,
|
tabViewModel: TabViewModel,
|
||||||
@ -174,134 +201,132 @@ fun MainContentView(
|
|||||||
repositoryState: RepositoryState,
|
repositoryState: RepositoryState,
|
||||||
blameState: BlameState
|
blameState: BlameState
|
||||||
) {
|
) {
|
||||||
Row {
|
HorizontalSplitPane {
|
||||||
HorizontalSplitPane {
|
first(minSize = 250.dp) {
|
||||||
first(minSize = 250.dp) {
|
ScrollableColumn(modifier = Modifier.fillMaxHeight()) {
|
||||||
ScrollableColumn(modifier = Modifier.fillMaxHeight( )) {
|
Branches(
|
||||||
Branches(
|
branchesViewModel = tabViewModel.branchesViewModel,
|
||||||
branchesViewModel = tabViewModel.branchesViewModel,
|
)
|
||||||
)
|
Remotes(
|
||||||
Remotes(
|
remotesViewModel = tabViewModel.remotesViewModel,
|
||||||
remotesViewModel = tabViewModel.remotesViewModel,
|
)
|
||||||
)
|
Tags(
|
||||||
Tags(
|
tagsViewModel = tabViewModel.tagsViewModel,
|
||||||
tagsViewModel = tabViewModel.tagsViewModel,
|
)
|
||||||
)
|
Stashes(
|
||||||
Stashes(
|
stashesViewModel = tabViewModel.stashesViewModel,
|
||||||
stashesViewModel = tabViewModel.stashesViewModel,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
splitter {
|
splitter {
|
||||||
this.repositorySplitter()
|
this.repositorySplitter()
|
||||||
}
|
}
|
||||||
|
|
||||||
second {
|
second {
|
||||||
HorizontalSplitPane(
|
HorizontalSplitPane(
|
||||||
splitPaneState = rememberSplitPaneState(0.9f)
|
splitPaneState = rememberSplitPaneState(0.9f)
|
||||||
) {
|
) {
|
||||||
first {
|
first {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
if (blameState is BlameState.Loaded && !blameState.isMinimized) {
|
if (blameState is BlameState.Loaded && !blameState.isMinimized) {
|
||||||
Blame(
|
Blame(
|
||||||
filePath = blameState.filePath,
|
filePath = blameState.filePath,
|
||||||
blameResult = blameState.blameResult,
|
blameResult = blameState.blameResult,
|
||||||
onClose = { tabViewModel.resetBlameState() },
|
onClose = { tabViewModel.resetBlameState() },
|
||||||
onSelectCommit = { tabViewModel.selectCommit(it) }
|
onSelectCommit = { tabViewModel.selectCommit(it) }
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Column {
|
Column {
|
||||||
Box(modifier = Modifier.weight(1f, true)) {
|
Box(modifier = Modifier.weight(1f, true)) {
|
||||||
when (diffSelected) {
|
when (diffSelected) {
|
||||||
null -> {
|
null -> {
|
||||||
Log(
|
Log(
|
||||||
logViewModel = tabViewModel.logViewModel,
|
logViewModel = tabViewModel.logViewModel,
|
||||||
selectedItem = selectedItem,
|
selectedItem = selectedItem,
|
||||||
repositoryState = repositoryState,
|
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
|
if (blameState is BlameState.Loaded) { // BlameState.isMinimized is true here
|
||||||
MinimizedBlame(
|
MinimizedBlame(
|
||||||
filePath = blameState.filePath,
|
filePath = blameState.filePath,
|
||||||
onExpand = { tabViewModel.expandBlame() },
|
onExpand = { tabViewModel.expandBlame() },
|
||||||
onClose = { tabViewModel.resetBlameState() }
|
onClose = { tabViewModel.resetBlameState() }
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
splitter {
|
splitter {
|
||||||
this.repositorySplitter()
|
this.repositorySplitter()
|
||||||
}
|
}
|
||||||
|
|
||||||
second(minSize = 300.dp) {
|
second(minSize = 300.dp) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
) {
|
) {
|
||||||
val safeSelectedItem = selectedItem
|
val safeSelectedItem = selectedItem
|
||||||
if (safeSelectedItem == SelectedItem.UncommitedChanges) {
|
if (safeSelectedItem == SelectedItem.UncommitedChanges) {
|
||||||
UncommitedChanges(
|
UncommitedChanges(
|
||||||
statusViewModel = tabViewModel.statusViewModel,
|
statusViewModel = tabViewModel.statusViewModel,
|
||||||
selectedEntryType = diffSelected,
|
selectedEntryType = diffSelected,
|
||||||
repositoryState = repositoryState,
|
repositoryState = repositoryState,
|
||||||
onStagedDiffEntrySelected = { diffEntry ->
|
onStagedDiffEntrySelected = { diffEntry ->
|
||||||
tabViewModel.minimizeBlame()
|
tabViewModel.minimizeBlame()
|
||||||
|
|
||||||
tabViewModel.newDiffSelected = if (diffEntry != null) {
|
|
||||||
if (repositoryState == RepositoryState.SAFE)
|
|
||||||
DiffEntryType.SafeStagedDiff(diffEntry)
|
|
||||||
else
|
|
||||||
DiffEntryType.UnsafeStagedDiff(diffEntry)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onUnstagedDiffEntrySelected = { diffEntry ->
|
|
||||||
tabViewModel.minimizeBlame()
|
|
||||||
|
|
||||||
|
tabViewModel.newDiffSelected = if (diffEntry != null) {
|
||||||
if (repositoryState == RepositoryState.SAFE)
|
if (repositoryState == RepositoryState.SAFE)
|
||||||
tabViewModel.newDiffSelected = DiffEntryType.SafeUnstagedDiff(diffEntry)
|
DiffEntryType.SafeStagedDiff(diffEntry)
|
||||||
else
|
else
|
||||||
tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry)
|
DiffEntryType.UnsafeStagedDiff(diffEntry)
|
||||||
},
|
} else {
|
||||||
onBlameFile = { tabViewModel.blameFile(it) },
|
null
|
||||||
onHistoryFile = { tabViewModel.fileHistory(it) }
|
}
|
||||||
)
|
},
|
||||||
} else if (safeSelectedItem is SelectedItem.CommitBasedItem) {
|
onUnstagedDiffEntrySelected = { diffEntry ->
|
||||||
CommitChanges(
|
tabViewModel.minimizeBlame()
|
||||||
commitChangesViewModel = tabViewModel.commitChangesViewModel,
|
|
||||||
selectedItem = safeSelectedItem,
|
if (repositoryState == RepositoryState.SAFE)
|
||||||
diffSelected = diffSelected,
|
tabViewModel.newDiffSelected = DiffEntryType.SafeUnstagedDiff(diffEntry)
|
||||||
onDiffSelected = { diffEntry ->
|
else
|
||||||
tabViewModel.minimizeBlame()
|
tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry)
|
||||||
tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry)
|
},
|
||||||
},
|
onBlameFile = { tabViewModel.blameFile(it) },
|
||||||
onBlame = { tabViewModel.blameFile(it) },
|
onHistoryFile = { tabViewModel.fileHistory(it) }
|
||||||
onHistory = { 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) },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ class TabViewModel @Inject constructor(
|
|||||||
loadRepositoryState(git)
|
loadRepositoryState(git)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun refreshRepositoryInfo() = tabState.safeProcessing(
|
private fun refreshRepositoryInfo() = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.NONE,
|
refreshType = RefreshType.NONE,
|
||||||
) { git ->
|
) { git ->
|
||||||
loadRepositoryState(git)
|
loadRepositoryState(git)
|
||||||
@ -427,6 +427,13 @@ class TabViewModel @Inject constructor(
|
|||||||
_showHistory.value = false
|
_showHistory.value = false
|
||||||
historyViewModel = null
|
historyViewModel = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun refreshAll() {
|
||||||
|
printLog(TAG, "Manual refresh triggered")
|
||||||
|
if (!tabState.operationRunning) {
|
||||||
|
refreshRepositoryInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user