Improved focus handling in the whole tab
This commit is contained in:
parent
51bcedc828
commit
e5a84705e9
@ -352,4 +352,8 @@ enum class RefreshType {
|
|||||||
enum class CloseableView {
|
enum class CloseableView {
|
||||||
DIFF,
|
DIFF,
|
||||||
LOG_SEARCH,
|
LOG_SEARCH,
|
||||||
|
SIDE_PANEL_SEARCH,
|
||||||
|
COMMIT_CHANGES_SEARCH,
|
||||||
|
STAGED_CHANGES_SEARCH,
|
||||||
|
UNSTAGED_CHANGES_SEARCH,
|
||||||
}
|
}
|
@ -81,6 +81,9 @@ fun CommitChanges(
|
|||||||
onSearchFilterToggled = { visible ->
|
onSearchFilterToggled = { visible ->
|
||||||
commitChangesViewModel.onSearchFilterToggled(visible)
|
commitChangesViewModel.onSearchFilterToggled(visible)
|
||||||
},
|
},
|
||||||
|
onSearchFocused = {
|
||||||
|
commitChangesViewModel.addSearchToCloseableView()
|
||||||
|
},
|
||||||
onSearchFilterChanged = { filter ->
|
onSearchFilterChanged = { filter ->
|
||||||
searchFilter = filter
|
searchFilter = filter
|
||||||
commitChangesViewModel.onSearchFilterChanged(filter)
|
commitChangesViewModel.onSearchFilterChanged(filter)
|
||||||
@ -105,6 +108,7 @@ private fun CommitChangesView(
|
|||||||
onHistory: (String) -> Unit,
|
onHistory: (String) -> Unit,
|
||||||
onDiffSelected: (DiffEntry) -> Unit,
|
onDiffSelected: (DiffEntry) -> Unit,
|
||||||
onSearchFilterToggled: (Boolean) -> Unit,
|
onSearchFilterToggled: (Boolean) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
onDirectoryClicked: (TreeItem.Dir) -> Unit,
|
onDirectoryClicked: (TreeItem.Dir) -> Unit,
|
||||||
onAlternateShowAsTree: () -> Unit,
|
onAlternateShowAsTree: () -> Unit,
|
||||||
@ -129,6 +133,7 @@ private fun CommitChangesView(
|
|||||||
searchFilter,
|
searchFilter,
|
||||||
onSearchFilterChanged,
|
onSearchFilterChanged,
|
||||||
onSearchFilterToggled,
|
onSearchFilterToggled,
|
||||||
|
onSearchFocused,
|
||||||
showAsTree = showAsTree,
|
showAsTree = showAsTree,
|
||||||
onAlternateShowAsTree = onAlternateShowAsTree,
|
onAlternateShowAsTree = onAlternateShowAsTree,
|
||||||
)
|
)
|
||||||
@ -182,6 +187,7 @@ private fun Header(
|
|||||||
searchFilter: TextFieldValue,
|
searchFilter: TextFieldValue,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
onSearchFilterToggled: (Boolean) -> Unit,
|
onSearchFilterToggled: (Boolean) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
showAsTree: Boolean,
|
showAsTree: Boolean,
|
||||||
onAlternateShowAsTree: () -> Unit,
|
onAlternateShowAsTree: () -> Unit,
|
||||||
) {
|
) {
|
||||||
@ -250,6 +256,7 @@ private fun Header(
|
|||||||
onSearchFilterChanged = onSearchFilterChanged,
|
onSearchFilterChanged = onSearchFilterChanged,
|
||||||
searchFocusRequester = searchFocusRequester,
|
searchFocusRequester = searchFocusRequester,
|
||||||
onClose = { onSearchFilterToggled(false) },
|
onClose = { onSearchFilterToggled(false) },
|
||||||
|
onSearchFocused = onSearchFocused,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,10 @@ import androidx.compose.ui.Alignment
|
|||||||
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.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.input.key.onPreviewKeyEvent
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.jetpackduba.gitnuro.AppConstants
|
import com.jetpackduba.gitnuro.AppConstants
|
||||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||||
@ -34,6 +36,9 @@ import kotlinx.coroutines.launch
|
|||||||
import org.eclipse.jgit.lib.RepositoryState
|
import org.eclipse.jgit.lib.RepositoryState
|
||||||
import org.eclipse.jgit.revwalk.RevCommit
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
|
|
||||||
|
val LocalTabFocusRequester = compositionLocalOf { FocusRequester() }
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RepositoryOpenPage(
|
fun RepositoryOpenPage(
|
||||||
repositoryOpenViewModel: RepositoryOpenViewModel,
|
repositoryOpenViewModel: RepositoryOpenViewModel,
|
||||||
@ -109,6 +114,7 @@ fun RepositoryOpenPage(
|
|||||||
.focusRequester(focusRequester)
|
.focusRequester(focusRequester)
|
||||||
.focusable(true)
|
.focusable(true)
|
||||||
.onPreviewKeyEvent {
|
.onPreviewKeyEvent {
|
||||||
|
println("onPreviewKeyEvent: $it")
|
||||||
when {
|
when {
|
||||||
it.matchesBinding(KeybindingOption.PULL) -> {
|
it.matchesBinding(KeybindingOption.PULL) -> {
|
||||||
repositoryOpenViewModel.pull(PullType.DEFAULT)
|
repositoryOpenViewModel.pull(PullType.DEFAULT)
|
||||||
@ -153,6 +159,9 @@ fun RepositoryOpenPage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
) {
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalTabFocusRequester provides focusRequester
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
Menu(
|
Menu(
|
||||||
@ -185,6 +194,7 @@ fun RepositoryOpenPage(
|
|||||||
showHistory = showHistory,
|
showHistory = showHistory,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -354,10 +364,12 @@ fun MainContentView(
|
|||||||
val diffViewModel = repositoryOpenViewModel.diffViewModel
|
val diffViewModel = repositoryOpenViewModel.diffViewModel
|
||||||
|
|
||||||
if (diffViewModel != null) {
|
if (diffViewModel != null) {
|
||||||
|
val tabFocusRequester = LocalTabFocusRequester.current
|
||||||
Diff(
|
Diff(
|
||||||
diffViewModel = diffViewModel,
|
diffViewModel = diffViewModel,
|
||||||
onCloseDiffView = {
|
onCloseDiffView = {
|
||||||
repositoryOpenViewModel.newDiffSelected = null
|
repositoryOpenViewModel.newDiffSelected = null
|
||||||
|
tabFocusRequester.requestFocus()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,9 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
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.focus.onFocusChanged
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
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.ui.dialogs.SetDefaultUpstreamBranchDialog
|
||||||
import com.jetpackduba.gitnuro.viewmodels.ChangeDefaultUpstreamBranchViewModel
|
import com.jetpackduba.gitnuro.viewmodels.ChangeDefaultUpstreamBranchViewModel
|
||||||
import com.jetpackduba.gitnuro.viewmodels.sidepanel.*
|
import com.jetpackduba.gitnuro.viewmodels.sidepanel.*
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import org.eclipse.jgit.lib.Ref
|
import org.eclipse.jgit.lib.Ref
|
||||||
import org.eclipse.jgit.revwalk.RevCommit
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
import org.eclipse.jgit.submodule.SubmoduleStatus
|
import org.eclipse.jgit.submodule.SubmoduleStatus
|
||||||
@ -47,7 +51,7 @@ fun SidePanel(
|
|||||||
stashesViewModel: StashesViewModel = sidePanelViewModel.stashesViewModel,
|
stashesViewModel: StashesViewModel = sidePanelViewModel.stashesViewModel,
|
||||||
submodulesViewModel: SubmodulesViewModel = sidePanelViewModel.submodulesViewModel,
|
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 selectedItem by sidePanelViewModel.selectedItem.collectAsState()
|
||||||
|
|
||||||
val branchesState by branchesViewModel.branchesState.collectAsState()
|
val branchesState by branchesViewModel.branchesState.collectAsState()
|
||||||
@ -59,16 +63,31 @@ fun SidePanel(
|
|||||||
val (showAddEditRemote, setShowAddEditRemote) = remember { mutableStateOf<RemoteWrapper?>(null) }
|
val (showAddEditRemote, setShowAddEditRemote) = remember { mutableStateOf<RemoteWrapper?>(null) }
|
||||||
val (branchToChangeUpstream, setBranchToChangeUpstream) = remember { mutableStateOf<Ref?>(null) }
|
val (branchToChangeUpstream, setBranchToChangeUpstream) = remember { mutableStateOf<Ref?>(null) }
|
||||||
var showEditSubmodulesDialog by remember { mutableStateOf(false) }
|
var showEditSubmodulesDialog by remember { mutableStateOf(false) }
|
||||||
|
val searchFocusRequester = remember { FocusRequester() }
|
||||||
|
val tabFocusRequester = LocalTabFocusRequester.current
|
||||||
|
|
||||||
|
LaunchedEffect(sidePanelViewModel) {
|
||||||
|
sidePanelViewModel.freeSearchFocusFlow.collectLatest {
|
||||||
|
tabFocusRequester.requestFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
FilterTextField(
|
FilterTextField(
|
||||||
value = filter,
|
value = filter,
|
||||||
onValueChange = { newValue ->
|
onValueChange = { newValue ->
|
||||||
filter = newValue
|
|
||||||
sidePanelViewModel.newFilter(newValue)
|
sidePanelViewModel.newFilter(newValue)
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = 8.dp)
|
.padding(start = 8.dp)
|
||||||
|
.focusRequester(searchFocusRequester)
|
||||||
|
.onFocusChanged {
|
||||||
|
if (it.isFocused) {
|
||||||
|
sidePanelViewModel.addSidePanelSearchToCloseables()
|
||||||
|
} else {
|
||||||
|
sidePanelViewModel.removeSidePanelSearchFromCloseables()
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
ScrollableLazyColumn(
|
ScrollableLazyColumn(
|
||||||
@ -142,7 +161,11 @@ fun SidePanel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FilterTextField(value: String, onValueChange: (String) -> Unit, modifier: Modifier) {
|
fun FilterTextField(
|
||||||
|
value: String,
|
||||||
|
onValueChange: (String) -> Unit,
|
||||||
|
modifier: Modifier
|
||||||
|
) {
|
||||||
AdjustableOutlinedTextField(
|
AdjustableOutlinedTextField(
|
||||||
value = value,
|
value = value,
|
||||||
hint = "Search for branches, tags & more",
|
hint = "Search for branches, tags & more",
|
||||||
|
@ -6,7 +6,10 @@ import androidx.compose.animation.AnimatedVisibility
|
|||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
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.MutableInteractionSource
|
||||||
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
@ -20,6 +23,7 @@ import androidx.compose.ui.ExperimentalComposeUiApi
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
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.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.graphics.compositeOver
|
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.CommitterDataRequestState
|
||||||
import com.jetpackduba.gitnuro.viewmodels.StageStateUi
|
import com.jetpackduba.gitnuro.viewmodels.StageStateUi
|
||||||
import com.jetpackduba.gitnuro.viewmodels.StatusViewModel
|
import com.jetpackduba.gitnuro.viewmodels.StatusViewModel
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.eclipse.jgit.lib.RepositoryState
|
import org.eclipse.jgit.lib.RepositoryState
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -88,13 +94,32 @@ fun UncommittedChanges(
|
|||||||
|
|
||||||
val canCommit = commitMessage.isNotEmpty() && stageStateUi.hasStagedFiles
|
val canCommit = commitMessage.isNotEmpty() && stageStateUi.hasStagedFiles
|
||||||
val canAmend = commitMessage.isNotEmpty() && statusViewModel.hasPreviousCommits
|
val canAmend = commitMessage.isNotEmpty() && statusViewModel.hasPreviousCommits
|
||||||
|
val tabFocusRequester = LocalTabFocusRequester.current
|
||||||
|
|
||||||
LaunchedEffect(statusViewModel) {
|
LaunchedEffect(statusViewModel) {
|
||||||
|
launch {
|
||||||
statusViewModel.commitMessageChangesFlow.collect { newCommitMessage ->
|
statusViewModel.commitMessageChangesFlow.collect { newCommitMessage ->
|
||||||
setCommitMessage(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) {
|
if (committerDataRequestStateValue is CommitterDataRequestState.WaitingInput) {
|
||||||
CommitAuthorDialog(
|
CommitAuthorDialog(
|
||||||
committerDataRequestStateValue.authorInfo,
|
committerDataRequestStateValue.authorInfo,
|
||||||
@ -131,6 +156,7 @@ fun UncommittedChanges(
|
|||||||
stagedListState,
|
stagedListState,
|
||||||
selectedEntryType,
|
selectedEntryType,
|
||||||
onSearchFilterToggled = { statusViewModel.onSearchFilterToggledStaged(it) },
|
onSearchFilterToggled = { statusViewModel.onSearchFilterToggledStaged(it) },
|
||||||
|
onSearchFocused = { statusViewModel.addStagedSearchToCloseableView() },
|
||||||
onDiffEntryOptionSelected = { statusViewModel.unstage(it) },
|
onDiffEntryOptionSelected = { statusViewModel.unstage(it) },
|
||||||
onDiffEntrySelected = onStagedDiffEntrySelected,
|
onDiffEntrySelected = onStagedDiffEntrySelected,
|
||||||
onSearchFilterChanged = { statusViewModel.onSearchFilterChangedStaged(it) },
|
onSearchFilterChanged = { statusViewModel.onSearchFilterChangedStaged(it) },
|
||||||
@ -154,6 +180,7 @@ fun UncommittedChanges(
|
|||||||
unstagedListState,
|
unstagedListState,
|
||||||
selectedEntryType,
|
selectedEntryType,
|
||||||
onSearchFilterToggled = { statusViewModel.onSearchFilterToggledUnstaged(it) },
|
onSearchFilterToggled = { statusViewModel.onSearchFilterToggledUnstaged(it) },
|
||||||
|
onSearchFocused = { statusViewModel.addUnstagedSearchToCloseableView() },
|
||||||
onDiffEntryOptionSelected = { statusViewModel.stage(it) },
|
onDiffEntryOptionSelected = { statusViewModel.stage(it) },
|
||||||
onDiffEntrySelected = onUnstagedDiffEntrySelected,
|
onDiffEntrySelected = onUnstagedDiffEntrySelected,
|
||||||
onSearchFilterChanged = { statusViewModel.onSearchFilterChangedUnstaged(it) },
|
onSearchFilterChanged = { statusViewModel.onSearchFilterChangedUnstaged(it) },
|
||||||
@ -323,6 +350,7 @@ fun ColumnScope.StagedView(
|
|||||||
stagedListState: LazyListState,
|
stagedListState: LazyListState,
|
||||||
selectedEntryType: DiffType?,
|
selectedEntryType: DiffType?,
|
||||||
onSearchFilterToggled: (Boolean) -> Unit,
|
onSearchFilterToggled: (Boolean) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
|
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
|
||||||
onDiffEntrySelected: (StatusEntry) -> Unit,
|
onDiffEntrySelected: (StatusEntry) -> Unit,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
@ -356,6 +384,7 @@ fun ColumnScope.StagedView(
|
|||||||
listState = stagedListState,
|
listState = stagedListState,
|
||||||
selectedEntryType = selectedEntryType,
|
selectedEntryType = selectedEntryType,
|
||||||
onSearchFilterToggled = onSearchFilterToggled,
|
onSearchFilterToggled = onSearchFilterToggled,
|
||||||
|
onSearchFocused = onSearchFocused,
|
||||||
onDiffEntryOptionSelected = onDiffEntryOptionSelected,
|
onDiffEntryOptionSelected = onDiffEntryOptionSelected,
|
||||||
onDiffEntrySelected = onDiffEntrySelected,
|
onDiffEntrySelected = onDiffEntrySelected,
|
||||||
onSearchFilterChanged = onSearchFilterChanged,
|
onSearchFilterChanged = onSearchFilterChanged,
|
||||||
@ -381,6 +410,7 @@ fun ColumnScope.UnstagedView(
|
|||||||
unstagedListState: LazyListState,
|
unstagedListState: LazyListState,
|
||||||
selectedEntryType: DiffType?,
|
selectedEntryType: DiffType?,
|
||||||
onSearchFilterToggled: (Boolean) -> Unit,
|
onSearchFilterToggled: (Boolean) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
|
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
|
||||||
onDiffEntrySelected: (StatusEntry) -> Unit,
|
onDiffEntrySelected: (StatusEntry) -> Unit,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
@ -414,6 +444,7 @@ fun ColumnScope.UnstagedView(
|
|||||||
listState = unstagedListState,
|
listState = unstagedListState,
|
||||||
selectedEntryType = selectedEntryType,
|
selectedEntryType = selectedEntryType,
|
||||||
onSearchFilterToggled = onSearchFilterToggled,
|
onSearchFilterToggled = onSearchFilterToggled,
|
||||||
|
onSearchFocused = onSearchFocused,
|
||||||
onDiffEntryOptionSelected = onDiffEntryOptionSelected,
|
onDiffEntryOptionSelected = onDiffEntryOptionSelected,
|
||||||
onDiffEntrySelected = onDiffEntrySelected,
|
onDiffEntrySelected = onDiffEntrySelected,
|
||||||
onSearchFilterChanged = onSearchFilterChanged,
|
onSearchFilterChanged = onSearchFilterChanged,
|
||||||
@ -448,6 +479,7 @@ fun ColumnScope.NeutralView(
|
|||||||
onTreeEntries: (StageStateUi.TreeLoaded) -> List<TreeItem<StatusEntry>>,
|
onTreeEntries: (StageStateUi.TreeLoaded) -> List<TreeItem<StatusEntry>>,
|
||||||
onListEntries: (StageStateUi.ListLoaded) -> List<StatusEntry>,
|
onListEntries: (StageStateUi.ListLoaded) -> List<StatusEntry>,
|
||||||
onSearchFilterToggled: (Boolean) -> Unit,
|
onSearchFilterToggled: (Boolean) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
|
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
|
||||||
onDiffEntrySelected: (StatusEntry) -> Unit,
|
onDiffEntrySelected: (StatusEntry) -> Unit,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
@ -477,6 +509,7 @@ fun ColumnScope.NeutralView(
|
|||||||
showSearch = showSearchUnstaged,
|
showSearch = showSearchUnstaged,
|
||||||
searchFilter = searchFilterUnstaged,
|
searchFilter = searchFilterUnstaged,
|
||||||
onSearchFilterToggled = onSearchFilterToggled,
|
onSearchFilterToggled = onSearchFilterToggled,
|
||||||
|
onSearchFocused = onSearchFocused,
|
||||||
onSearchFilterChanged = onSearchFilterChanged,
|
onSearchFilterChanged = onSearchFilterChanged,
|
||||||
statusEntries = onTreeEntries(stageStateUi),
|
statusEntries = onTreeEntries(stageStateUi),
|
||||||
lazyListState = listState,
|
lazyListState = listState,
|
||||||
@ -516,6 +549,7 @@ fun ColumnScope.NeutralView(
|
|||||||
showSearch = showSearchUnstaged,
|
showSearch = showSearchUnstaged,
|
||||||
searchFilter = searchFilterUnstaged,
|
searchFilter = searchFilterUnstaged,
|
||||||
onSearchFilterToggled = onSearchFilterToggled,
|
onSearchFilterToggled = onSearchFilterToggled,
|
||||||
|
onSearchFocused = onSearchFocused,
|
||||||
onSearchFilterChanged = onSearchFilterChanged,
|
onSearchFilterChanged = onSearchFilterChanged,
|
||||||
statusEntries = onListEntries(stageStateUi),
|
statusEntries = onListEntries(stageStateUi),
|
||||||
lazyListState = listState,
|
lazyListState = listState,
|
||||||
@ -789,6 +823,7 @@ private fun EntriesList(
|
|||||||
showSearch: Boolean,
|
showSearch: Boolean,
|
||||||
searchFilter: TextFieldValue,
|
searchFilter: TextFieldValue,
|
||||||
onSearchFilterToggled: (Boolean) -> Unit,
|
onSearchFilterToggled: (Boolean) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
statusEntries: List<StatusEntry>,
|
statusEntries: List<StatusEntry>,
|
||||||
lazyListState: LazyListState,
|
lazyListState: LazyListState,
|
||||||
@ -816,6 +851,7 @@ private fun EntriesList(
|
|||||||
onSearchFilterToggled = onSearchFilterToggled,
|
onSearchFilterToggled = onSearchFilterToggled,
|
||||||
showAsTree = false,
|
showAsTree = false,
|
||||||
showSearch = showSearch,
|
showSearch = showSearch,
|
||||||
|
onSearchFocused = onSearchFocused,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -859,6 +895,7 @@ private fun TreeEntriesList(
|
|||||||
showSearch: Boolean,
|
showSearch: Boolean,
|
||||||
searchFilter: TextFieldValue,
|
searchFilter: TextFieldValue,
|
||||||
onSearchFilterToggled: (Boolean) -> Unit,
|
onSearchFilterToggled: (Boolean) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
statusEntries: List<TreeItem<StatusEntry>>,
|
statusEntries: List<TreeItem<StatusEntry>>,
|
||||||
lazyListState: LazyListState,
|
lazyListState: LazyListState,
|
||||||
@ -886,6 +923,7 @@ private fun TreeEntriesList(
|
|||||||
searchFilter = searchFilter,
|
searchFilter = searchFilter,
|
||||||
onSearchFilterChanged = onSearchFilterChanged,
|
onSearchFilterChanged = onSearchFilterChanged,
|
||||||
onSearchFilterToggled = onSearchFilterToggled,
|
onSearchFilterToggled = onSearchFilterToggled,
|
||||||
|
onSearchFocused = onSearchFocused,
|
||||||
showAsTree = true,
|
showAsTree = true,
|
||||||
showSearch = showSearch,
|
showSearch = showSearch,
|
||||||
)
|
)
|
||||||
@ -939,6 +977,7 @@ fun EntriesHeader(
|
|||||||
onAllAction: () -> Unit,
|
onAllAction: () -> Unit,
|
||||||
onAlternateShowAsTree: () -> Unit,
|
onAlternateShowAsTree: () -> Unit,
|
||||||
onSearchFilterToggled: (Boolean) -> Unit,
|
onSearchFilterToggled: (Boolean) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
searchFilter: TextFieldValue,
|
searchFilter: TextFieldValue,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
) {
|
) {
|
||||||
@ -1022,6 +1061,7 @@ fun EntriesHeader(
|
|||||||
searchFilter = searchFilter,
|
searchFilter = searchFilter,
|
||||||
onSearchFilterChanged = onSearchFilterChanged,
|
onSearchFilterChanged = onSearchFilterChanged,
|
||||||
searchFocusRequester = searchFocusRequester,
|
searchFocusRequester = searchFocusRequester,
|
||||||
|
onSearchFocused = onSearchFocused,
|
||||||
onClose = { onSearchFilterToggled(false) },
|
onClose = { onSearchFilterToggled(false) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable
|
|||||||
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.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.KeyEventType
|
||||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||||
import androidx.compose.ui.input.key.type
|
import androidx.compose.ui.input.key.type
|
||||||
@ -28,20 +29,14 @@ import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
|||||||
fun SearchTextField(
|
fun SearchTextField(
|
||||||
searchFilter: TextFieldValue,
|
searchFilter: TextFieldValue,
|
||||||
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
onSearchFilterChanged: (TextFieldValue) -> Unit,
|
||||||
|
onSearchFocused: () -> Unit,
|
||||||
searchFocusRequester: FocusRequester,
|
searchFocusRequester: FocusRequester,
|
||||||
onClose: () -> Unit,
|
onClose: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(MaterialTheme.colors.background)
|
.background(MaterialTheme.colors.background)
|
||||||
.padding(horizontal = 4.dp, vertical = 4.dp)
|
.padding(horizontal = 4.dp, vertical = 4.dp),
|
||||||
.onPreviewKeyEvent { keyEvent ->
|
|
||||||
if (keyEvent.matchesBinding(KeybindingOption.EXIT) && keyEvent.type == KeyEventType.KeyDown) {
|
|
||||||
onClose()
|
|
||||||
true
|
|
||||||
} else
|
|
||||||
false
|
|
||||||
},
|
|
||||||
) {
|
) {
|
||||||
AdjustableOutlinedTextField(
|
AdjustableOutlinedTextField(
|
||||||
value = searchFilter,
|
value = searchFilter,
|
||||||
@ -51,7 +46,8 @@ fun SearchTextField(
|
|||||||
hint = "Search files by name or path",
|
hint = "Search files by name or path",
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
.focusable()
|
.focusable()
|
||||||
.focusRequester(searchFocusRequester),
|
.focusRequester(searchFocusRequester)
|
||||||
|
.onFocusChanged { if (it.isFocused) onSearchFocused() },
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onClose,
|
onClick = onClose,
|
||||||
|
@ -24,9 +24,6 @@ import androidx.compose.ui.focus.onFocusChanged
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
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.PointerEventType
|
||||||
import androidx.compose.ui.input.pointer.onPointerEvent
|
import androidx.compose.ui.input.pointer.onPointerEvent
|
||||||
import androidx.compose.ui.res.loadImageBitmap
|
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.diff.LineType
|
||||||
import com.jetpackduba.gitnuro.git.workspace.StatusEntry
|
import com.jetpackduba.gitnuro.git.workspace.StatusEntry
|
||||||
import com.jetpackduba.gitnuro.git.workspace.StatusType
|
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.theme.*
|
||||||
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
||||||
import com.jetpackduba.gitnuro.ui.components.ScrollableLazyColumn
|
import com.jetpackduba.gitnuro.ui.components.ScrollableLazyColumn
|
||||||
@ -113,13 +108,6 @@ fun Diff(
|
|||||||
diffViewModel.addToCloseables()
|
diffViewModel.addToCloseables()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onPreviewKeyEvent { keyEvent ->
|
|
||||||
if (keyEvent.matchesBinding(KeybindingOption.EXIT) && keyEvent.type == KeyEventType.KeyDown) {
|
|
||||||
onCloseDiffView()
|
|
||||||
true
|
|
||||||
} else
|
|
||||||
false
|
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
when (viewDiffResult) {
|
when (viewDiffResult) {
|
||||||
ViewDiffResult.DiffNotFound -> {
|
ViewDiffResult.DiffNotFound -> {
|
||||||
|
@ -403,11 +403,6 @@ fun SearchFilter(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
keyEvent.matchesBinding(KeybindingOption.EXIT) -> {
|
|
||||||
logViewModel.closeSearch()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7,6 +7,7 @@ import com.jetpackduba.gitnuro.extensions.delayedStateChange
|
|||||||
import com.jetpackduba.gitnuro.extensions.filePath
|
import com.jetpackduba.gitnuro.extensions.filePath
|
||||||
import com.jetpackduba.gitnuro.extensions.fullData
|
import com.jetpackduba.gitnuro.extensions.fullData
|
||||||
import com.jetpackduba.gitnuro.extensions.lowercaseContains
|
import com.jetpackduba.gitnuro.extensions.lowercaseContains
|
||||||
|
import com.jetpackduba.gitnuro.git.CloseableView
|
||||||
import com.jetpackduba.gitnuro.git.RefreshType
|
import com.jetpackduba.gitnuro.git.RefreshType
|
||||||
import com.jetpackduba.gitnuro.git.TabState
|
import com.jetpackduba.gitnuro.git.TabState
|
||||||
import com.jetpackduba.gitnuro.git.diff.GetCommitDiffEntriesUseCase
|
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 com.jetpackduba.gitnuro.ui.tree_files.entriesToTreeEntry
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.eclipse.jgit.diff.DiffEntry
|
import org.eclipse.jgit.diff.DiffEntry
|
||||||
import org.eclipse.jgit.revwalk.RevCommit
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -25,7 +27,7 @@ class CommitChangesViewModel @Inject constructor(
|
|||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val getCommitDiffEntriesUseCase: GetCommitDiffEntriesUseCase,
|
private val getCommitDiffEntriesUseCase: GetCommitDiffEntriesUseCase,
|
||||||
private val appSettingsRepository: AppSettingsRepository,
|
private val appSettingsRepository: AppSettingsRepository,
|
||||||
tabScope: CoroutineScope,
|
private val tabScope: CoroutineScope,
|
||||||
) {
|
) {
|
||||||
private val _showSearch = MutableStateFlow(false)
|
private val _showSearch = MutableStateFlow(false)
|
||||||
val showSearch: StateFlow<Boolean> = _showSearch
|
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(
|
fun loadChanges(commit: RevCommit) = tabState.runOperation(
|
||||||
refreshType = RefreshType.NONE,
|
refreshType = RefreshType.NONE,
|
||||||
) { git ->
|
) { git ->
|
||||||
@ -153,6 +175,14 @@ class CommitChangesViewModel @Inject constructor(
|
|||||||
fun onSearchFilterChanged(filter: TextFieldValue) {
|
fun onSearchFilterChanged(filter: TextFieldValue) {
|
||||||
_searchFilter.value = filter
|
_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 {
|
private sealed interface CommitChangesState {
|
||||||
@ -167,6 +197,7 @@ sealed interface CommitChangesStateUi {
|
|||||||
sealed interface Loaded : CommitChangesStateUi {
|
sealed interface Loaded : CommitChangesStateUi {
|
||||||
val commit: RevCommit
|
val commit: RevCommit
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ListLoaded(override val commit: RevCommit, val changes: List<DiffEntry>) :
|
data class ListLoaded(override val commit: RevCommit, val changes: List<DiffEntry>) :
|
||||||
Loaded
|
Loaded
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class DiffViewModel @Inject constructor(
|
|||||||
private val generateSplitHunkFromDiffResultUseCase: GenerateSplitHunkFromDiffResultUseCase,
|
private val generateSplitHunkFromDiffResultUseCase: GenerateSplitHunkFromDiffResultUseCase,
|
||||||
private val discardUnstagedHunkLineUseCase: DiscardUnstagedHunkLineUseCase,
|
private val discardUnstagedHunkLineUseCase: DiscardUnstagedHunkLineUseCase,
|
||||||
private val tabsManager: TabsManager,
|
private val tabsManager: TabsManager,
|
||||||
tabScope: CoroutineScope,
|
private val tabScope: CoroutineScope,
|
||||||
) : AutoCloseable {
|
) : AutoCloseable {
|
||||||
private val _diffResult = MutableStateFlow<ViewDiffResult>(ViewDiffResult.Loading(""))
|
private val _diffResult = MutableStateFlow<ViewDiffResult>(ViewDiffResult.Loading(""))
|
||||||
val diffResult: StateFlow<ViewDiffResult?> = _diffResult
|
val diffResult: StateFlow<ViewDiffResult?> = _diffResult
|
||||||
@ -229,11 +229,11 @@ class DiffViewModel @Inject constructor(
|
|||||||
tabsManager.addNewTabFromPath("${git.repository.workTree}/$path", true)
|
tabsManager.addNewTabFromPath("${git.repository.workTree}/$path", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addToCloseables() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
|
fun addToCloseables() = tabScope.launch {
|
||||||
tabState.addCloseableView(CloseableView.DIFF)
|
tabState.addCloseableView(CloseableView.DIFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeFromCloseables() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
|
private fun removeFromCloseables() = tabScope.launch {
|
||||||
tabState.removeCloseableView(CloseableView.DIFF)
|
tabState.removeCloseableView(CloseableView.DIFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class LogViewModel @Inject constructor(
|
|||||||
private val startRebaseInteractiveUseCase: StartRebaseInteractiveUseCase,
|
private val startRebaseInteractiveUseCase: StartRebaseInteractiveUseCase,
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val appSettingsRepository: AppSettingsRepository,
|
private val appSettingsRepository: AppSettingsRepository,
|
||||||
tabScope: CoroutineScope,
|
private val tabScope: CoroutineScope,
|
||||||
sharedStashViewModel: SharedStashViewModel,
|
sharedStashViewModel: SharedStashViewModel,
|
||||||
sharedBranchesViewModel: SharedBranchesViewModel,
|
sharedBranchesViewModel: SharedBranchesViewModel,
|
||||||
sharedRemotesViewModel: SharedRemotesViewModel,
|
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)
|
_logSearchFilterResults.value = LogSearch.SearchResults(matchingCommits, startingUiIndex)
|
||||||
addSearchToCloseableView()
|
|
||||||
} else {
|
} else {
|
||||||
_logSearchFilterResults.value = LogSearch.SearchResults(emptyList(), NONE_MATCHING_INDEX)
|
_logSearchFilterResults.value = LogSearch.SearchResults(emptyList(), NONE_MATCHING_INDEX)
|
||||||
addSearchToCloseableView()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +366,6 @@ class LogViewModel @Inject constructor(
|
|||||||
|
|
||||||
_logSearchFilterResults.value = logSearchFilterResultsValue.copy(index = newIndex)
|
_logSearchFilterResults.value = logSearchFilterResultsValue.copy(index = newIndex)
|
||||||
_focusCommit.emit(newCommitToSelect)
|
_focusCommit.emit(newCommitToSelect)
|
||||||
addSearchToCloseableView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun selectNextFilterCommit() {
|
suspend fun selectNextFilterCommit() {
|
||||||
@ -382,7 +388,6 @@ class LogViewModel @Inject constructor(
|
|||||||
|
|
||||||
_logSearchFilterResults.value = logSearchFilterResultsValue.copy(index = newIndex)
|
_logSearchFilterResults.value = logSearchFilterResultsValue.copy(index = newIndex)
|
||||||
_focusCommit.emit(newCommitToSelect)
|
_focusCommit.emit(newCommitToSelect)
|
||||||
addSearchToCloseableView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showDialog(dialog: LogDialog) {
|
fun showDialog(dialog: LogDialog) {
|
||||||
@ -391,14 +396,13 @@ class LogViewModel @Inject constructor(
|
|||||||
|
|
||||||
fun closeSearch() {
|
fun closeSearch() {
|
||||||
_logSearchFilterResults.value = LogSearch.NotSearching
|
_logSearchFilterResults.value = LogSearch.NotSearching
|
||||||
removeSearchFromCloseableView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addSearchToCloseableView() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
|
fun addSearchToCloseableView() = tabScope.launch {
|
||||||
tabState.addCloseableView(CloseableView.LOG_SEARCH)
|
tabState.addCloseableView(CloseableView.LOG_SEARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSearchFromCloseableView() = tabState.runOperation(refreshType = RefreshType.NONE) { _ ->
|
private fun removeSearchFromCloseableView() = tabScope.launch {
|
||||||
tabState.removeCloseableView(CloseableView.LOG_SEARCH)
|
tabState.removeCloseableView(CloseableView.LOG_SEARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import androidx.compose.ui.text.input.TextFieldValue
|
|||||||
import com.jetpackduba.gitnuro.SharedRepositoryStateManager
|
import com.jetpackduba.gitnuro.SharedRepositoryStateManager
|
||||||
import com.jetpackduba.gitnuro.TaskType
|
import com.jetpackduba.gitnuro.TaskType
|
||||||
import com.jetpackduba.gitnuro.extensions.*
|
import com.jetpackduba.gitnuro.extensions.*
|
||||||
|
import com.jetpackduba.gitnuro.git.CloseableView
|
||||||
import com.jetpackduba.gitnuro.git.RefreshType
|
import com.jetpackduba.gitnuro.git.RefreshType
|
||||||
import com.jetpackduba.gitnuro.git.TabState
|
import com.jetpackduba.gitnuro.git.TabState
|
||||||
import com.jetpackduba.gitnuro.git.author.LoadAuthorUseCase
|
import com.jetpackduba.gitnuro.git.author.LoadAuthorUseCase
|
||||||
@ -59,7 +60,7 @@ class StatusViewModel @Inject constructor(
|
|||||||
private val sharedRepositoryStateManager: SharedRepositoryStateManager,
|
private val sharedRepositoryStateManager: SharedRepositoryStateManager,
|
||||||
private val getSpecificCommitMessageUseCase: GetSpecificCommitMessageUseCase,
|
private val getSpecificCommitMessageUseCase: GetSpecificCommitMessageUseCase,
|
||||||
private val appSettingsRepository: AppSettingsRepository,
|
private val appSettingsRepository: AppSettingsRepository,
|
||||||
tabScope: CoroutineScope,
|
private val tabScope: CoroutineScope,
|
||||||
) {
|
) {
|
||||||
private val _showSearchUnstaged = MutableStateFlow(false)
|
private val _showSearchUnstaged = MutableStateFlow(false)
|
||||||
val showSearchUnstaged: StateFlow<Boolean> = _showSearchUnstaged
|
val showSearchUnstaged: StateFlow<Boolean> = _showSearchUnstaged
|
||||||
@ -182,6 +183,36 @@ class StatusViewModel @Inject constructor(
|
|||||||
refresh(tabState.git)
|
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(
|
private fun persistMessage() = tabState.runOperation(
|
||||||
@ -547,6 +578,30 @@ class StatusViewModel @Inject constructor(
|
|||||||
) { git ->
|
) { git ->
|
||||||
unstageByDirectoryUseCase(git, dir)
|
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 {
|
sealed interface StageState {
|
||||||
|
@ -75,9 +75,8 @@ class TabViewModel @Inject constructor(
|
|||||||
val errorsManager: ErrorsManager = tabState.errorsManager
|
val errorsManager: ErrorsManager = tabState.errorsManager
|
||||||
val selectedItem: StateFlow<SelectedItem> = tabState.selectedItem
|
val selectedItem: StateFlow<SelectedItem> = tabState.selectedItem
|
||||||
|
|
||||||
val repositoryOpenViewModel: RepositoryOpenViewModel by lazy {
|
val repositoryOpenViewModel: RepositoryOpenViewModel = repositoryOpenViewModelProvider.get()
|
||||||
repositoryOpenViewModelProvider.get()
|
|
||||||
}
|
|
||||||
private val _repositorySelectionStatus = MutableStateFlow<RepositorySelectionStatus>(RepositorySelectionStatus.None)
|
private val _repositorySelectionStatus = MutableStateFlow<RepositorySelectionStatus>(RepositorySelectionStatus.None)
|
||||||
val repositorySelectionStatus: StateFlow<RepositorySelectionStatus>
|
val repositorySelectionStatus: StateFlow<RepositorySelectionStatus>
|
||||||
get() = _repositorySelectionStatus
|
get() = _repositorySelectionStatus
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package com.jetpackduba.gitnuro.viewmodels.sidepanel
|
package com.jetpackduba.gitnuro.viewmodels.sidepanel
|
||||||
|
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import com.jetpackduba.gitnuro.di.factories.*
|
import com.jetpackduba.gitnuro.di.factories.*
|
||||||
|
import com.jetpackduba.gitnuro.git.CloseableView
|
||||||
import com.jetpackduba.gitnuro.git.TabState
|
import com.jetpackduba.gitnuro.git.TabState
|
||||||
import com.jetpackduba.gitnuro.ui.SelectedItem
|
import com.jetpackduba.gitnuro.ui.SelectedItem
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SidePanelViewModel @Inject constructor(
|
class SidePanelViewModel @Inject constructor(
|
||||||
@ -13,7 +16,8 @@ class SidePanelViewModel @Inject constructor(
|
|||||||
tagsViewModelFactory: TagsViewModelFactory,
|
tagsViewModelFactory: TagsViewModelFactory,
|
||||||
stashesViewModelFactory: StashesViewModelFactory,
|
stashesViewModelFactory: StashesViewModelFactory,
|
||||||
submodulesViewModelFactory: SubmodulesViewModelFactory,
|
submodulesViewModelFactory: SubmodulesViewModelFactory,
|
||||||
tabState: TabState,
|
private val tabState: TabState,
|
||||||
|
private val tabScope: CoroutineScope,
|
||||||
) {
|
) {
|
||||||
private val _filter = MutableStateFlow("")
|
private val _filter = MutableStateFlow("")
|
||||||
val filter: StateFlow<String> = _filter
|
val filter: StateFlow<String> = _filter
|
||||||
@ -25,7 +29,29 @@ class SidePanelViewModel @Inject constructor(
|
|||||||
val stashesViewModel: StashesViewModel = stashesViewModelFactory.create(filter)
|
val stashesViewModel: StashesViewModel = stashesViewModelFactory.create(filter)
|
||||||
val submodulesViewModel: SubmodulesViewModel = submodulesViewModelFactory.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) {
|
fun newFilter(newValue: String) {
|
||||||
_filter.value = newValue
|
_filter.value = newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addSidePanelSearchToCloseables() = tabScope.launch {
|
||||||
|
tabState.addCloseableView(CloseableView.SIDE_PANEL_SEARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeSidePanelSearchFromCloseables() = tabScope.launch {
|
||||||
|
tabState.removeCloseableView(CloseableView.SIDE_PANEL_SEARCH)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user