Improved focus handling in the whole tab

This commit is contained in:
Abdelilah El Aissaoui 2024-09-09 01:49:26 +02:00
parent 51bcedc828
commit e5a84705e9
No known key found for this signature in database
GPG Key ID: 7587FC860F594869
14 changed files with 259 additions and 79 deletions

View File

@ -352,4 +352,8 @@ enum class RefreshType {
enum class CloseableView {
DIFF,
LOG_SEARCH,
SIDE_PANEL_SEARCH,
COMMIT_CHANGES_SEARCH,
STAGED_CHANGES_SEARCH,
UNSTAGED_CHANGES_SEARCH,
}

View File

@ -81,6 +81,9 @@ fun CommitChanges(
onSearchFilterToggled = { visible ->
commitChangesViewModel.onSearchFilterToggled(visible)
},
onSearchFocused = {
commitChangesViewModel.addSearchToCloseableView()
},
onSearchFilterChanged = { filter ->
searchFilter = filter
commitChangesViewModel.onSearchFilterChanged(filter)
@ -105,6 +108,7 @@ private fun CommitChangesView(
onHistory: (String) -> Unit,
onDiffSelected: (DiffEntry) -> Unit,
onSearchFilterToggled: (Boolean) -> Unit,
onSearchFocused: () -> Unit,
onSearchFilterChanged: (TextFieldValue) -> Unit,
onDirectoryClicked: (TreeItem.Dir) -> Unit,
onAlternateShowAsTree: () -> Unit,
@ -129,6 +133,7 @@ private fun CommitChangesView(
searchFilter,
onSearchFilterChanged,
onSearchFilterToggled,
onSearchFocused,
showAsTree = showAsTree,
onAlternateShowAsTree = onAlternateShowAsTree,
)
@ -182,6 +187,7 @@ private fun Header(
searchFilter: TextFieldValue,
onSearchFilterChanged: (TextFieldValue) -> Unit,
onSearchFilterToggled: (Boolean) -> Unit,
onSearchFocused: () -> Unit,
showAsTree: Boolean,
onAlternateShowAsTree: () -> Unit,
) {
@ -250,6 +256,7 @@ private fun Header(
onSearchFilterChanged = onSearchFilterChanged,
searchFocusRequester = searchFocusRequester,
onClose = { onSearchFilterToggled(false) },
onSearchFocused = onSearchFocused,
)
}

View File

@ -10,8 +10,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.dp
import com.jetpackduba.gitnuro.AppConstants
import com.jetpackduba.gitnuro.extensions.handMouseClickable
@ -34,6 +36,9 @@ import kotlinx.coroutines.launch
import org.eclipse.jgit.lib.RepositoryState
import org.eclipse.jgit.revwalk.RevCommit
val LocalTabFocusRequester = compositionLocalOf { FocusRequester() }
@Composable
fun RepositoryOpenPage(
repositoryOpenViewModel: RepositoryOpenViewModel,
@ -109,6 +114,7 @@ fun RepositoryOpenPage(
.focusRequester(focusRequester)
.focusable(true)
.onPreviewKeyEvent {
println("onPreviewKeyEvent: $it")
when {
it.matchesBinding(KeybindingOption.PULL) -> {
repositoryOpenViewModel.pull(PullType.DEFAULT)
@ -153,6 +159,9 @@ fun RepositoryOpenPage(
}
}
) {
CompositionLocalProvider(
LocalTabFocusRequester provides focusRequester
) {
Column(modifier = Modifier.weight(1f)) {
Menu(
@ -185,6 +194,7 @@ fun RepositoryOpenPage(
showHistory = showHistory,
)
}
}
Spacer(
modifier = Modifier
@ -354,10 +364,12 @@ fun MainContentView(
val diffViewModel = repositoryOpenViewModel.diffViewModel
if (diffViewModel != null) {
val tabFocusRequester = LocalTabFocusRequester.current
Diff(
diffViewModel = diffViewModel,
onCloseDiffView = {
repositoryOpenViewModel.newDiffSelected = null
tabFocusRequester.requestFocus()
}
)
}

View File

@ -9,6 +9,9 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@ -32,6 +35,7 @@ import com.jetpackduba.gitnuro.ui.dialogs.AddSubmodulesDialog
import com.jetpackduba.gitnuro.ui.dialogs.SetDefaultUpstreamBranchDialog
import com.jetpackduba.gitnuro.viewmodels.ChangeDefaultUpstreamBranchViewModel
import com.jetpackduba.gitnuro.viewmodels.sidepanel.*
import kotlinx.coroutines.flow.collectLatest
import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.revwalk.RevCommit
import org.eclipse.jgit.submodule.SubmoduleStatus
@ -47,7 +51,7 @@ fun SidePanel(
stashesViewModel: StashesViewModel = sidePanelViewModel.stashesViewModel,
submodulesViewModel: SubmodulesViewModel = sidePanelViewModel.submodulesViewModel,
) {
var filter by remember(sidePanelViewModel) { mutableStateOf(sidePanelViewModel.filter.value) }
val filter by sidePanelViewModel.filter.collectAsState()
val selectedItem by sidePanelViewModel.selectedItem.collectAsState()
val branchesState by branchesViewModel.branchesState.collectAsState()
@ -59,16 +63,31 @@ fun SidePanel(
val (showAddEditRemote, setShowAddEditRemote) = remember { mutableStateOf<RemoteWrapper?>(null) }
val (branchToChangeUpstream, setBranchToChangeUpstream) = remember { mutableStateOf<Ref?>(null) }
var showEditSubmodulesDialog by remember { mutableStateOf(false) }
val searchFocusRequester = remember { FocusRequester() }
val tabFocusRequester = LocalTabFocusRequester.current
LaunchedEffect(sidePanelViewModel) {
sidePanelViewModel.freeSearchFocusFlow.collectLatest {
tabFocusRequester.requestFocus()
}
}
Column {
FilterTextField(
value = filter,
onValueChange = { newValue ->
filter = newValue
sidePanelViewModel.newFilter(newValue)
},
modifier = Modifier
.padding(start = 8.dp)
.focusRequester(searchFocusRequester)
.onFocusChanged {
if (it.isFocused) {
sidePanelViewModel.addSidePanelSearchToCloseables()
} else {
sidePanelViewModel.removeSidePanelSearchFromCloseables()
}
}
)
ScrollableLazyColumn(
@ -142,7 +161,11 @@ fun SidePanel(
}
@Composable
fun FilterTextField(value: String, onValueChange: (String) -> Unit, modifier: Modifier) {
fun FilterTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier
) {
AdjustableOutlinedTextField(
value = value,
hint = "Search for branches, tags & more",

View File

@ -6,7 +6,10 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.*
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.focusable
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.*
@ -20,6 +23,7 @@ import androidx.compose.ui.ExperimentalComposeUiApi
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.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.compositeOver
@ -49,6 +53,8 @@ import com.jetpackduba.gitnuro.ui.tree_files.TreeItem
import com.jetpackduba.gitnuro.viewmodels.CommitterDataRequestState
import com.jetpackduba.gitnuro.viewmodels.StageStateUi
import com.jetpackduba.gitnuro.viewmodels.StatusViewModel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.eclipse.jgit.lib.RepositoryState
@Composable
@ -88,13 +94,32 @@ fun UncommittedChanges(
val canCommit = commitMessage.isNotEmpty() && stageStateUi.hasStagedFiles
val canAmend = commitMessage.isNotEmpty() && statusViewModel.hasPreviousCommits
val tabFocusRequester = LocalTabFocusRequester.current
LaunchedEffect(statusViewModel) {
launch {
statusViewModel.commitMessageChangesFlow.collect { newCommitMessage ->
setCommitMessage(newCommitMessage)
}
}
launch {
statusViewModel.showSearchUnstaged.collectLatest { show ->
if (!show) {
tabFocusRequester.requestFocus()
}
}
}
launch {
statusViewModel.showSearchStaged.collectLatest { show ->
if (!show) {
tabFocusRequester.requestFocus()
}
}
}
}
if (committerDataRequestStateValue is CommitterDataRequestState.WaitingInput) {
CommitAuthorDialog(
committerDataRequestStateValue.authorInfo,
@ -131,6 +156,7 @@ fun UncommittedChanges(
stagedListState,
selectedEntryType,
onSearchFilterToggled = { statusViewModel.onSearchFilterToggledStaged(it) },
onSearchFocused = { statusViewModel.addStagedSearchToCloseableView() },
onDiffEntryOptionSelected = { statusViewModel.unstage(it) },
onDiffEntrySelected = onStagedDiffEntrySelected,
onSearchFilterChanged = { statusViewModel.onSearchFilterChangedStaged(it) },
@ -154,6 +180,7 @@ fun UncommittedChanges(
unstagedListState,
selectedEntryType,
onSearchFilterToggled = { statusViewModel.onSearchFilterToggledUnstaged(it) },
onSearchFocused = { statusViewModel.addUnstagedSearchToCloseableView() },
onDiffEntryOptionSelected = { statusViewModel.stage(it) },
onDiffEntrySelected = onUnstagedDiffEntrySelected,
onSearchFilterChanged = { statusViewModel.onSearchFilterChangedUnstaged(it) },
@ -323,6 +350,7 @@ fun ColumnScope.StagedView(
stagedListState: LazyListState,
selectedEntryType: DiffType?,
onSearchFilterToggled: (Boolean) -> Unit,
onSearchFocused: () -> Unit,
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
onDiffEntrySelected: (StatusEntry) -> Unit,
onSearchFilterChanged: (TextFieldValue) -> Unit,
@ -356,6 +384,7 @@ fun ColumnScope.StagedView(
listState = stagedListState,
selectedEntryType = selectedEntryType,
onSearchFilterToggled = onSearchFilterToggled,
onSearchFocused = onSearchFocused,
onDiffEntryOptionSelected = onDiffEntryOptionSelected,
onDiffEntrySelected = onDiffEntrySelected,
onSearchFilterChanged = onSearchFilterChanged,
@ -381,6 +410,7 @@ fun ColumnScope.UnstagedView(
unstagedListState: LazyListState,
selectedEntryType: DiffType?,
onSearchFilterToggled: (Boolean) -> Unit,
onSearchFocused: () -> Unit,
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
onDiffEntrySelected: (StatusEntry) -> Unit,
onSearchFilterChanged: (TextFieldValue) -> Unit,
@ -414,6 +444,7 @@ fun ColumnScope.UnstagedView(
listState = unstagedListState,
selectedEntryType = selectedEntryType,
onSearchFilterToggled = onSearchFilterToggled,
onSearchFocused = onSearchFocused,
onDiffEntryOptionSelected = onDiffEntryOptionSelected,
onDiffEntrySelected = onDiffEntrySelected,
onSearchFilterChanged = onSearchFilterChanged,
@ -448,6 +479,7 @@ fun ColumnScope.NeutralView(
onTreeEntries: (StageStateUi.TreeLoaded) -> List<TreeItem<StatusEntry>>,
onListEntries: (StageStateUi.ListLoaded) -> List<StatusEntry>,
onSearchFilterToggled: (Boolean) -> Unit,
onSearchFocused: () -> Unit,
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
onDiffEntrySelected: (StatusEntry) -> Unit,
onSearchFilterChanged: (TextFieldValue) -> Unit,
@ -477,6 +509,7 @@ fun ColumnScope.NeutralView(
showSearch = showSearchUnstaged,
searchFilter = searchFilterUnstaged,
onSearchFilterToggled = onSearchFilterToggled,
onSearchFocused = onSearchFocused,
onSearchFilterChanged = onSearchFilterChanged,
statusEntries = onTreeEntries(stageStateUi),
lazyListState = listState,
@ -516,6 +549,7 @@ fun ColumnScope.NeutralView(
showSearch = showSearchUnstaged,
searchFilter = searchFilterUnstaged,
onSearchFilterToggled = onSearchFilterToggled,
onSearchFocused = onSearchFocused,
onSearchFilterChanged = onSearchFilterChanged,
statusEntries = onListEntries(stageStateUi),
lazyListState = listState,
@ -789,6 +823,7 @@ private fun EntriesList(
showSearch: Boolean,
searchFilter: TextFieldValue,
onSearchFilterToggled: (Boolean) -> Unit,
onSearchFocused: () -> Unit,
onSearchFilterChanged: (TextFieldValue) -> Unit,
statusEntries: List<StatusEntry>,
lazyListState: LazyListState,
@ -816,6 +851,7 @@ private fun EntriesList(
onSearchFilterToggled = onSearchFilterToggled,
showAsTree = false,
showSearch = showSearch,
onSearchFocused = onSearchFocused,
)
@ -859,6 +895,7 @@ private fun TreeEntriesList(
showSearch: Boolean,
searchFilter: TextFieldValue,
onSearchFilterToggled: (Boolean) -> Unit,
onSearchFocused: () -> Unit,
onSearchFilterChanged: (TextFieldValue) -> Unit,
statusEntries: List<TreeItem<StatusEntry>>,
lazyListState: LazyListState,
@ -886,6 +923,7 @@ private fun TreeEntriesList(
searchFilter = searchFilter,
onSearchFilterChanged = onSearchFilterChanged,
onSearchFilterToggled = onSearchFilterToggled,
onSearchFocused = onSearchFocused,
showAsTree = true,
showSearch = showSearch,
)
@ -939,6 +977,7 @@ fun EntriesHeader(
onAllAction: () -> Unit,
onAlternateShowAsTree: () -> Unit,
onSearchFilterToggled: (Boolean) -> Unit,
onSearchFocused: () -> Unit,
searchFilter: TextFieldValue,
onSearchFilterChanged: (TextFieldValue) -> Unit,
) {
@ -1022,6 +1061,7 @@ fun EntriesHeader(
searchFilter = searchFilter,
onSearchFilterChanged = onSearchFilterChanged,
searchFocusRequester = searchFocusRequester,
onSearchFocused = onSearchFocused,
onClose = { onSearchFilterToggled(false) },
)
}

View File

@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.key.type
@ -28,20 +29,14 @@ import com.jetpackduba.gitnuro.keybindings.matchesBinding
fun SearchTextField(
searchFilter: TextFieldValue,
onSearchFilterChanged: (TextFieldValue) -> Unit,
onSearchFocused: () -> Unit,
searchFocusRequester: FocusRequester,
onClose: () -> Unit,
) {
Box(
modifier = Modifier
.background(MaterialTheme.colors.background)
.padding(horizontal = 4.dp, vertical = 4.dp)
.onPreviewKeyEvent { keyEvent ->
if (keyEvent.matchesBinding(KeybindingOption.EXIT) && keyEvent.type == KeyEventType.KeyDown) {
onClose()
true
} else
false
},
.padding(horizontal = 4.dp, vertical = 4.dp),
) {
AdjustableOutlinedTextField(
value = searchFilter,
@ -51,7 +46,8 @@ fun SearchTextField(
hint = "Search files by name or path",
modifier = Modifier.fillMaxWidth()
.focusable()
.focusRequester(searchFocusRequester),
.focusRequester(searchFocusRequester)
.onFocusChanged { if (it.isFocused) onSearchFocused() },
trailingIcon = {
IconButton(
onClick = onClose,

View File

@ -24,9 +24,6 @@ import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.onPointerEvent
import androidx.compose.ui.res.loadImageBitmap
@ -49,8 +46,6 @@ import com.jetpackduba.gitnuro.git.diff.Line
import com.jetpackduba.gitnuro.git.diff.LineType
import com.jetpackduba.gitnuro.git.workspace.StatusEntry
import com.jetpackduba.gitnuro.git.workspace.StatusType
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
import com.jetpackduba.gitnuro.keybindings.matchesBinding
import com.jetpackduba.gitnuro.theme.*
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
import com.jetpackduba.gitnuro.ui.components.ScrollableLazyColumn
@ -113,13 +108,6 @@ fun Diff(
diffViewModel.addToCloseables()
}
}
.onPreviewKeyEvent { keyEvent ->
if (keyEvent.matchesBinding(KeybindingOption.EXIT) && keyEvent.type == KeyEventType.KeyDown) {
onCloseDiffView()
true
} else
false
}
) {
when (viewDiffResult) {
ViewDiffResult.DiffNotFound -> {

View File

@ -403,11 +403,6 @@ fun SearchFilter(
true
}
keyEvent.matchesBinding(KeybindingOption.EXIT) -> {
logViewModel.closeSearch()
true
}
else -> false
}
},

View File

@ -7,6 +7,7 @@ import com.jetpackduba.gitnuro.extensions.delayedStateChange
import com.jetpackduba.gitnuro.extensions.filePath
import com.jetpackduba.gitnuro.extensions.fullData
import com.jetpackduba.gitnuro.extensions.lowercaseContains
import com.jetpackduba.gitnuro.git.CloseableView
import com.jetpackduba.gitnuro.git.RefreshType
import com.jetpackduba.gitnuro.git.TabState
import com.jetpackduba.gitnuro.git.diff.GetCommitDiffEntriesUseCase
@ -15,6 +16,7 @@ import com.jetpackduba.gitnuro.ui.tree_files.TreeItem
import com.jetpackduba.gitnuro.ui.tree_files.entriesToTreeEntry
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import org.eclipse.jgit.diff.DiffEntry
import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject
@ -25,7 +27,7 @@ class CommitChangesViewModel @Inject constructor(
private val tabState: TabState,
private val getCommitDiffEntriesUseCase: GetCommitDiffEntriesUseCase,
private val appSettingsRepository: AppSettingsRepository,
tabScope: CoroutineScope,
private val tabScope: CoroutineScope,
) {
private val _showSearch = MutableStateFlow(false)
val showSearch: StateFlow<Boolean> = _showSearch
@ -82,6 +84,26 @@ class CommitChangesViewModel @Inject constructor(
)
init {
tabScope.launch {
_showSearch.collectLatest {
if (it) {
addSearchToCloseableView()
} else {
removeSearchFromCloseableView()
}
}
}
tabScope.launch {
tabState.closeViewFlow.collectLatest {
if (it == CloseableView.COMMIT_CHANGES_SEARCH) {
onSearchFilterToggled(false)
}
}
}
}
fun loadChanges(commit: RevCommit) = tabState.runOperation(
refreshType = RefreshType.NONE,
) { git ->
@ -153,6 +175,14 @@ class CommitChangesViewModel @Inject constructor(
fun onSearchFilterChanged(filter: TextFieldValue) {
_searchFilter.value = filter
}
fun addSearchToCloseableView() = tabScope.launch {
tabState.addCloseableView(CloseableView.COMMIT_CHANGES_SEARCH)
}
private fun removeSearchFromCloseableView() = tabScope.launch {
tabState.removeCloseableView(CloseableView.COMMIT_CHANGES_SEARCH)
}
}
private sealed interface CommitChangesState {
@ -167,6 +197,7 @@ sealed interface CommitChangesStateUi {
sealed interface Loaded : CommitChangesStateUi {
val commit: RevCommit
}
data class ListLoaded(override val commit: RevCommit, val changes: List<DiffEntry>) :
Loaded

View File

@ -38,7 +38,7 @@ class DiffViewModel @Inject constructor(
private val generateSplitHunkFromDiffResultUseCase: GenerateSplitHunkFromDiffResultUseCase,
private val discardUnstagedHunkLineUseCase: DiscardUnstagedHunkLineUseCase,
private val tabsManager: TabsManager,
tabScope: CoroutineScope,
private val tabScope: CoroutineScope,
) : AutoCloseable {
private val _diffResult = MutableStateFlow<ViewDiffResult>(ViewDiffResult.Loading(""))
val diffResult: StateFlow<ViewDiffResult?> = _diffResult
@ -229,11 +229,11 @@ class DiffViewModel @Inject constructor(
tabsManager.addNewTabFromPath("${git.repository.workTree}/$path", true)
}
fun addToCloseables() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
fun addToCloseables() = tabScope.launch {
tabState.addCloseableView(CloseableView.DIFF)
}
private fun removeFromCloseables() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
private fun removeFromCloseables() = tabScope.launch {
tabState.removeCloseableView(CloseableView.DIFF)
}

View File

@ -59,7 +59,7 @@ class LogViewModel @Inject constructor(
private val startRebaseInteractiveUseCase: StartRebaseInteractiveUseCase,
private val tabState: TabState,
private val appSettingsRepository: AppSettingsRepository,
tabScope: CoroutineScope,
private val tabScope: CoroutineScope,
sharedStashViewModel: SharedStashViewModel,
sharedBranchesViewModel: SharedBranchesViewModel,
sharedRemotesViewModel: SharedRemotesViewModel,
@ -133,6 +133,15 @@ class LogViewModel @Inject constructor(
}
}
}
tabScope.launch {
_logSearchFilterResults.collectLatest {
when (it) {
LogSearch.NotSearching -> removeSearchFromCloseableView()
is LogSearch.SearchResults -> addSearchToCloseableView()
}
}
}
}
@ -334,10 +343,8 @@ class LogViewModel @Inject constructor(
}
_logSearchFilterResults.value = LogSearch.SearchResults(matchingCommits, startingUiIndex)
addSearchToCloseableView()
} else {
_logSearchFilterResults.value = LogSearch.SearchResults(emptyList(), NONE_MATCHING_INDEX)
addSearchToCloseableView()
}
}
@ -359,7 +366,6 @@ class LogViewModel @Inject constructor(
_logSearchFilterResults.value = logSearchFilterResultsValue.copy(index = newIndex)
_focusCommit.emit(newCommitToSelect)
addSearchToCloseableView()
}
suspend fun selectNextFilterCommit() {
@ -382,7 +388,6 @@ class LogViewModel @Inject constructor(
_logSearchFilterResults.value = logSearchFilterResultsValue.copy(index = newIndex)
_focusCommit.emit(newCommitToSelect)
addSearchToCloseableView()
}
fun showDialog(dialog: LogDialog) {
@ -391,14 +396,13 @@ class LogViewModel @Inject constructor(
fun closeSearch() {
_logSearchFilterResults.value = LogSearch.NotSearching
removeSearchFromCloseableView()
}
fun addSearchToCloseableView() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
fun addSearchToCloseableView() = tabScope.launch {
tabState.addCloseableView(CloseableView.LOG_SEARCH)
}
private fun removeSearchFromCloseableView() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
private fun removeSearchFromCloseableView() = tabScope.launch {
tabState.removeCloseableView(CloseableView.LOG_SEARCH)
}

View File

@ -5,6 +5,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import com.jetpackduba.gitnuro.SharedRepositoryStateManager
import com.jetpackduba.gitnuro.TaskType
import com.jetpackduba.gitnuro.extensions.*
import com.jetpackduba.gitnuro.git.CloseableView
import com.jetpackduba.gitnuro.git.RefreshType
import com.jetpackduba.gitnuro.git.TabState
import com.jetpackduba.gitnuro.git.author.LoadAuthorUseCase
@ -59,7 +60,7 @@ class StatusViewModel @Inject constructor(
private val sharedRepositoryStateManager: SharedRepositoryStateManager,
private val getSpecificCommitMessageUseCase: GetSpecificCommitMessageUseCase,
private val appSettingsRepository: AppSettingsRepository,
tabScope: CoroutineScope,
private val tabScope: CoroutineScope,
) {
private val _showSearchUnstaged = MutableStateFlow(false)
val showSearchUnstaged: StateFlow<Boolean> = _showSearchUnstaged
@ -182,6 +183,36 @@ class StatusViewModel @Inject constructor(
refresh(tabState.git)
}
}
tabScope.launch {
showSearchStaged.collectLatest {
if (it) {
addStagedSearchToCloseableView()
} else {
removeStagedSearchToCloseableView()
}
}
}
tabScope.launch {
showSearchUnstaged.collectLatest {
if (it) {
addUnstagedSearchToCloseableView()
} else {
removeUnstagedSearchToCloseableView()
}
}
}
tabScope.launch {
tabState.closeViewFlow.collectLatest {
if (it == CloseableView.STAGED_CHANGES_SEARCH) {
onSearchFilterToggledStaged(false)
} else if (it == CloseableView.UNSTAGED_CHANGES_SEARCH) {
onSearchFilterToggledUnstaged(false)
}
}
}
}
private fun persistMessage() = tabState.runOperation(
@ -547,6 +578,30 @@ class StatusViewModel @Inject constructor(
) { git ->
unstageByDirectoryUseCase(git, dir)
}
fun addStagedSearchToCloseableView() {
addSearchToCloseView(CloseableView.STAGED_CHANGES_SEARCH)
}
private fun removeStagedSearchToCloseableView() {
removeSearchFromCloseView(CloseableView.STAGED_CHANGES_SEARCH)
}
fun addUnstagedSearchToCloseableView() {
addSearchToCloseView(CloseableView.UNSTAGED_CHANGES_SEARCH)
}
private fun removeUnstagedSearchToCloseableView() {
removeSearchFromCloseView(CloseableView.UNSTAGED_CHANGES_SEARCH)
}
private fun addSearchToCloseView(view: CloseableView) = tabScope.launch {
tabState.addCloseableView(view)
}
private fun removeSearchFromCloseView(view: CloseableView) = tabScope.launch {
tabState.removeCloseableView(view)
}
}
sealed interface StageState {

View File

@ -75,9 +75,8 @@ class TabViewModel @Inject constructor(
val errorsManager: ErrorsManager = tabState.errorsManager
val selectedItem: StateFlow<SelectedItem> = tabState.selectedItem
val repositoryOpenViewModel: RepositoryOpenViewModel by lazy {
repositoryOpenViewModelProvider.get()
}
val repositoryOpenViewModel: RepositoryOpenViewModel = repositoryOpenViewModelProvider.get()
private val _repositorySelectionStatus = MutableStateFlow<RepositorySelectionStatus>(RepositorySelectionStatus.None)
val repositorySelectionStatus: StateFlow<RepositorySelectionStatus>
get() = _repositorySelectionStatus

View File

@ -1,10 +1,13 @@
package com.jetpackduba.gitnuro.viewmodels.sidepanel
import androidx.compose.runtime.collectAsState
import com.jetpackduba.gitnuro.di.factories.*
import com.jetpackduba.gitnuro.git.CloseableView
import com.jetpackduba.gitnuro.git.TabState
import com.jetpackduba.gitnuro.ui.SelectedItem
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
class SidePanelViewModel @Inject constructor(
@ -13,7 +16,8 @@ class SidePanelViewModel @Inject constructor(
tagsViewModelFactory: TagsViewModelFactory,
stashesViewModelFactory: StashesViewModelFactory,
submodulesViewModelFactory: SubmodulesViewModelFactory,
tabState: TabState,
private val tabState: TabState,
private val tabScope: CoroutineScope,
) {
private val _filter = MutableStateFlow("")
val filter: StateFlow<String> = _filter
@ -25,7 +29,29 @@ class SidePanelViewModel @Inject constructor(
val stashesViewModel: StashesViewModel = stashesViewModelFactory.create(filter)
val submodulesViewModel: SubmodulesViewModel = submodulesViewModelFactory.create(filter)
private val _freeSearchFocusFlow = MutableSharedFlow<Unit>()
val freeSearchFocusFlow = _freeSearchFocusFlow.asSharedFlow()
init {
tabScope.launch {
tabState.closeViewFlow.collectLatest {
if (it == CloseableView.SIDE_PANEL_SEARCH) {
newFilter("")
_freeSearchFocusFlow.emit(Unit)
}
}
}
}
fun newFilter(newValue: String) {
_filter.value = newValue
}
fun addSidePanelSearchToCloseables() = tabScope.launch {
tabState.addCloseableView(CloseableView.SIDE_PANEL_SEARCH)
}
fun removeSidePanelSearchFromCloseables() = tabScope.launch {
tabState.removeCloseableView(CloseableView.SIDE_PANEL_SEARCH)
}
}