Implemented close view with ESC

This commit is contained in:
Abdelilah El Aissaoui 2024-09-09 00:31:43 +02:00
parent 355cbc3f79
commit 1af4542c7c
No known key found for this signature in database
GPG Key ID: 7587FC860F594869
7 changed files with 135 additions and 52 deletions

View File

@ -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,
}

View File

@ -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

View File

@ -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()

View File

@ -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) -> {

View File

@ -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) {

View File

@ -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(

View File

@ -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.
}
}