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 {
|
||||
DIFF,
|
||||
LOG_SEARCH,
|
||||
SIDE_PANEL_SEARCH,
|
||||
COMMIT_CHANGES_SEARCH,
|
||||
STAGED_CHANGES_SEARCH,
|
||||
UNSTAGED_CHANGES_SEARCH,
|
||||
}
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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) },
|
||||
)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 -> {
|
||||
|
@ -403,11 +403,6 @@ fun SearchFilter(
|
||||
true
|
||||
}
|
||||
|
||||
keyEvent.matchesBinding(KeybindingOption.EXIT) -> {
|
||||
logViewModel.closeSearch()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
},
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user