Implemented close view with ESC
This commit is contained in:
parent
355cbc3f79
commit
1af4542c7c
@ -12,6 +12,8 @@ import com.jetpackduba.gitnuro.models.Notification
|
||||
import com.jetpackduba.gitnuro.ui.SelectedItem
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.ObjectId
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
@ -54,9 +56,10 @@ class TabState @Inject constructor(
|
||||
}
|
||||
|
||||
private val refreshData = MutableSharedFlow<RefreshType>()
|
||||
private val closeableViews = ArrayDeque<Int>()
|
||||
private val closeableViews = ArrayDeque<CloseableView>()
|
||||
private val closeableViewsMutex = Mutex()
|
||||
|
||||
private val _closeView = MutableSharedFlow<Int>()
|
||||
private val _closeView = MutableSharedFlow<CloseableView>()
|
||||
val closeViewFlow = _closeView.asSharedFlow()
|
||||
|
||||
/**
|
||||
@ -311,15 +314,16 @@ class TabState @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun addCloseableView(id: Int) {
|
||||
closeableViews.add(id)
|
||||
suspend fun addCloseableView(view: CloseableView): Unit = closeableViewsMutex.withLock {
|
||||
closeableViews.remove(view) // Remove any previous elements if present
|
||||
closeableViews.add(view)
|
||||
}
|
||||
|
||||
fun removeCloseableView(id: Int) {
|
||||
closeableViews.remove(id)
|
||||
suspend fun removeCloseableView(view: CloseableView): Unit = closeableViewsMutex.withLock {
|
||||
closeableViews.remove(view)
|
||||
}
|
||||
|
||||
suspend fun closeLastView() {
|
||||
suspend fun closeLastView(): Unit = closeableViewsMutex.withLock {
|
||||
val last = closeableViews.removeLastOrNull()
|
||||
|
||||
if (last != null) {
|
||||
@ -344,3 +348,8 @@ enum class RefreshType {
|
||||
REMOTES,
|
||||
REBASE_INTERACTIVE_STATE,
|
||||
}
|
||||
|
||||
enum class CloseableView {
|
||||
DIFF,
|
||||
LOG_SEARCH,
|
||||
}
|
@ -105,50 +105,54 @@ fun RepositoryOpenPage(
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
LaunchedEffect(selectedItem) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
Column (
|
||||
modifier = Modifier.onPreviewKeyEvent {
|
||||
println("Key event $it")
|
||||
when {
|
||||
it.matchesBinding(KeybindingOption.PULL) -> {
|
||||
repositoryOpenViewModel.pull(PullType.DEFAULT)
|
||||
true
|
||||
}
|
||||
it.matchesBinding(KeybindingOption.PUSH) -> {
|
||||
repositoryOpenViewModel.push()
|
||||
true
|
||||
}
|
||||
it.matchesBinding(KeybindingOption.BRANCH_CREATE) -> {
|
||||
if (!showNewBranchDialog) {
|
||||
showNewBranchDialog = true
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.focusable(true)
|
||||
.onPreviewKeyEvent {
|
||||
when {
|
||||
it.matchesBinding(KeybindingOption.PULL) -> {
|
||||
repositoryOpenViewModel.pull(PullType.DEFAULT)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
it.matchesBinding(KeybindingOption.STASH) -> {
|
||||
repositoryOpenViewModel.stash()
|
||||
true
|
||||
}
|
||||
it.matchesBinding(KeybindingOption.STASH_POP) -> {
|
||||
repositoryOpenViewModel.popStash()
|
||||
true
|
||||
}
|
||||
it.matchesBinding(KeybindingOption.EXIT) -> {
|
||||
repositoryOpenViewModel.closeLastView()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
}
|
||||
it.matchesBinding(KeybindingOption.PUSH) -> {
|
||||
repositoryOpenViewModel.push()
|
||||
true
|
||||
}
|
||||
|
||||
it.matchesBinding(KeybindingOption.BRANCH_CREATE) -> {
|
||||
if (!showNewBranchDialog) {
|
||||
showNewBranchDialog = true
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
it.matchesBinding(KeybindingOption.STASH) -> {
|
||||
repositoryOpenViewModel.stash()
|
||||
true
|
||||
}
|
||||
|
||||
it.matchesBinding(KeybindingOption.STASH_POP) -> {
|
||||
repositoryOpenViewModel.popStash()
|
||||
true
|
||||
}
|
||||
|
||||
it.matchesBinding(KeybindingOption.EXIT) -> {
|
||||
repositoryOpenViewModel.closeLastView()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
}
|
||||
) {
|
||||
Row(modifier = Modifier.weight(1f)) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.focusable()
|
||||
.onKeyEvent { keyEvent ->
|
||||
if (keyEvent.matchesBinding(KeybindingOption.REFRESH)) {
|
||||
@ -211,6 +215,10 @@ fun RepositoryOpenPage(
|
||||
onShowAuthorInfoDialog = { repositoryOpenViewModel.showAuthorInfoDialog() },
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(repositoryOpenViewModel) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -20,6 +20,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
@ -38,6 +39,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
import com.jetpackduba.gitnuro.extensions.*
|
||||
import com.jetpackduba.gitnuro.git.CloseableView
|
||||
import com.jetpackduba.gitnuro.git.DiffType
|
||||
import com.jetpackduba.gitnuro.git.EntryContent
|
||||
import com.jetpackduba.gitnuro.git.animatedImages
|
||||
@ -62,6 +64,7 @@ import com.jetpackduba.gitnuro.viewmodels.DiffViewModel
|
||||
import com.jetpackduba.gitnuro.viewmodels.TextDiffType
|
||||
import com.jetpackduba.gitnuro.viewmodels.ViewDiffResult
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.diff.DiffEntry
|
||||
import org.eclipse.jgit.submodule.SubmoduleStatusType
|
||||
@ -93,12 +96,23 @@ fun Diff(
|
||||
val viewDiffResult = diffResultState.value ?: return
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
diffViewModel.closeViewFlow.collectLatest {
|
||||
if (it == CloseableView.DIFF) onCloseDiffView()
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colors.background)
|
||||
.fillMaxSize()
|
||||
.focusable()
|
||||
.focusable(true)
|
||||
.focusRequester(focusRequester)
|
||||
.onFocusChanged {
|
||||
if (it.isFocused) {
|
||||
diffViewModel.addToCloseables()
|
||||
}
|
||||
}
|
||||
.onPreviewKeyEvent { keyEvent ->
|
||||
if (keyEvent.matchesBinding(KeybindingOption.EXIT) && keyEvent.type == KeyEventType.KeyDown) {
|
||||
onCloseDiffView()
|
||||
|
@ -24,6 +24,7 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
@ -115,6 +116,7 @@ fun Log(
|
||||
repositoryState = repositoryState,
|
||||
changeDefaultUpstreamBranchViewModel = changeDefaultUpstreamBranchViewModel,
|
||||
)
|
||||
|
||||
LogStatus.Loading -> LogLoading()
|
||||
}
|
||||
}
|
||||
@ -204,8 +206,13 @@ private fun LogLoaded(
|
||||
|
||||
|
||||
if (searchFilterValue is LogSearch.SearchResults) {
|
||||
SearchFilter(logViewModel, searchFilterValue)
|
||||
SearchFilter(
|
||||
logViewModel = logViewModel,
|
||||
searchFilterResults = searchFilterValue,
|
||||
searchFocused = { logViewModel.addSearchToCloseableView() },
|
||||
)
|
||||
}
|
||||
|
||||
GraphHeader(
|
||||
graphWidth = graphWidth,
|
||||
onPaddingChange = {
|
||||
@ -353,7 +360,8 @@ suspend fun scrollToUncommittedChanges(
|
||||
@Composable
|
||||
fun SearchFilter(
|
||||
logViewModel: LogViewModel,
|
||||
searchFilterResults: LogSearch.SearchResults
|
||||
searchFilterResults: LogSearch.SearchResults,
|
||||
searchFocused: () -> Unit,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
var searchFilterText by remember { mutableStateOf(logViewModel.savedSearchFilter) }
|
||||
@ -381,6 +389,11 @@ fun SearchFilter(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.focusRequester(textFieldFocusRequester)
|
||||
.onFocusChanged {
|
||||
if (it.isFocused) {
|
||||
searchFocused()
|
||||
}
|
||||
}
|
||||
.onPreviewKeyEvent { keyEvent ->
|
||||
when {
|
||||
keyEvent.matchesBinding(KeybindingOption.SIMPLE_ACCEPT) -> {
|
||||
|
@ -3,6 +3,7 @@ package com.jetpackduba.gitnuro.viewmodels
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import com.jetpackduba.gitnuro.exceptions.MissingDiffEntryException
|
||||
import com.jetpackduba.gitnuro.extensions.delayedStateChange
|
||||
import com.jetpackduba.gitnuro.git.CloseableView
|
||||
import com.jetpackduba.gitnuro.git.DiffType
|
||||
import com.jetpackduba.gitnuro.git.RefreshType
|
||||
import com.jetpackduba.gitnuro.git.TabState
|
||||
@ -38,10 +39,12 @@ class DiffViewModel @Inject constructor(
|
||||
private val discardUnstagedHunkLineUseCase: DiscardUnstagedHunkLineUseCase,
|
||||
private val tabsManager: TabsManager,
|
||||
tabScope: CoroutineScope,
|
||||
) {
|
||||
) : AutoCloseable {
|
||||
private val _diffResult = MutableStateFlow<ViewDiffResult>(ViewDiffResult.Loading(""))
|
||||
val diffResult: StateFlow<ViewDiffResult?> = _diffResult
|
||||
|
||||
val closeViewFlow = tabState.closeViewFlow
|
||||
|
||||
val diffTypeFlow = settings.textDiffTypeFlow
|
||||
val isDisplayFullFile = settings.diffDisplayFullFileFlow
|
||||
|
||||
@ -92,6 +95,8 @@ class DiffViewModel @Inject constructor(
|
||||
)
|
||||
|
||||
fun updateDiff(diffType: DiffType) {
|
||||
addToCloseables()
|
||||
|
||||
diffJob = tabState.runOperation(refreshType = RefreshType.NONE) { git ->
|
||||
this.diffType = diffType
|
||||
|
||||
@ -223,6 +228,19 @@ class DiffViewModel @Inject constructor(
|
||||
fun openSubmodule(path: String) = tabState.runOperation(refreshType = RefreshType.NONE) { git ->
|
||||
tabsManager.addNewTabFromPath("${git.repository.workTree}/$path", true)
|
||||
}
|
||||
|
||||
fun addToCloseables() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
|
||||
tabState.addCloseableView(CloseableView.DIFF)
|
||||
}
|
||||
|
||||
private fun removeFromCloseables() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
|
||||
tabState.removeCloseableView(CloseableView.DIFF)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
cancelRunningJobs()
|
||||
removeFromCloseables()
|
||||
}
|
||||
}
|
||||
|
||||
enum class TextDiffType(val value: Int) {
|
||||
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.lazy.LazyListState
|
||||
import com.jetpackduba.gitnuro.TaskType
|
||||
import com.jetpackduba.gitnuro.extensions.delayedStateChange
|
||||
import com.jetpackduba.gitnuro.extensions.shortName
|
||||
import com.jetpackduba.gitnuro.git.CloseableView
|
||||
import com.jetpackduba.gitnuro.git.RefreshType
|
||||
import com.jetpackduba.gitnuro.git.TabState
|
||||
import com.jetpackduba.gitnuro.git.TaskEvent
|
||||
@ -124,6 +125,14 @@ class LogViewModel @Inject constructor(
|
||||
refresh(tabState.git)
|
||||
}
|
||||
}
|
||||
|
||||
tabScope.launch {
|
||||
tabState.closeViewFlow.collectLatest {
|
||||
if (it == CloseableView.LOG_SEARCH) {
|
||||
_logSearchFilterResults.value = LogSearch.NotSearching
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -325,8 +334,11 @@ class LogViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
_logSearchFilterResults.value = LogSearch.SearchResults(matchingCommits, startingUiIndex)
|
||||
} else
|
||||
addSearchToCloseableView()
|
||||
} else {
|
||||
_logSearchFilterResults.value = LogSearch.SearchResults(emptyList(), NONE_MATCHING_INDEX)
|
||||
addSearchToCloseableView()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun selectPreviousFilterCommit() {
|
||||
@ -347,6 +359,7 @@ class LogViewModel @Inject constructor(
|
||||
|
||||
_logSearchFilterResults.value = logSearchFilterResultsValue.copy(index = newIndex)
|
||||
_focusCommit.emit(newCommitToSelect)
|
||||
addSearchToCloseableView()
|
||||
}
|
||||
|
||||
suspend fun selectNextFilterCommit() {
|
||||
@ -369,6 +382,7 @@ class LogViewModel @Inject constructor(
|
||||
|
||||
_logSearchFilterResults.value = logSearchFilterResultsValue.copy(index = newIndex)
|
||||
_focusCommit.emit(newCommitToSelect)
|
||||
addSearchToCloseableView()
|
||||
}
|
||||
|
||||
fun showDialog(dialog: LogDialog) {
|
||||
@ -377,6 +391,15 @@ class LogViewModel @Inject constructor(
|
||||
|
||||
fun closeSearch() {
|
||||
_logSearchFilterResults.value = LogSearch.NotSearching
|
||||
removeSearchFromCloseableView()
|
||||
}
|
||||
|
||||
fun addSearchToCloseableView() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
|
||||
tabState.addCloseableView(CloseableView.LOG_SEARCH)
|
||||
}
|
||||
|
||||
private fun removeSearchFromCloseableView() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
|
||||
tabState.removeCloseableView(CloseableView.LOG_SEARCH)
|
||||
}
|
||||
|
||||
fun rebaseInteractive(revCommit: RevCommit) = tabState.safeProcessing(
|
||||
|
@ -122,8 +122,6 @@ class RepositoryOpenViewModel @Inject constructor(
|
||||
launch {
|
||||
watchRepositoryChanges(tabState.git)
|
||||
}
|
||||
|
||||
launch { tabState.refreshData(RefreshType.ALL_DATA) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +250,7 @@ class RepositoryOpenViewModel @Inject constructor(
|
||||
diffViewModel?.cancelRunningJobs()
|
||||
diffViewModel?.updateDiff(diffSelected)
|
||||
} else {
|
||||
diffViewModel?.cancelRunningJobs()
|
||||
diffViewModel?.close()
|
||||
diffViewModel = null // Free the view model from the memory if not being used.
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user