Selecting a branch, tag or stash in side panel highlights it

This commit is contained in:
Abdelilah El Aissaoui 2023-11-11 16:42:28 +01:00
parent 81c37043ca
commit fbdf5a4da8
No known key found for this signature in database
GPG Key ID: 7587FC860F594869
9 changed files with 48 additions and 25 deletions

View File

@ -11,6 +11,7 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import org.eclipse.jgit.api.Git import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.ObjectId import org.eclipse.jgit.lib.ObjectId
import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.revwalk.RevCommit import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject import javax.inject.Inject
@ -242,7 +243,7 @@ class TabState @Inject constructor(
} }
suspend fun newSelectedStash(stash: RevCommit) { suspend fun newSelectedStash(stash: RevCommit) {
newSelectedItem(SelectedItem.Stash(stash)) newSelectedItem(SelectedItem.Stash(stash), true)
} }
suspend fun noneSelected() { suspend fun noneSelected() {
@ -260,7 +261,7 @@ class TabState @Inject constructor(
} }
} }
fun newSelectedRef(objectId: ObjectId?) = runOperation( fun newSelectedRef(ref: Ref, objectId: ObjectId?) = runOperation(
refreshType = RefreshType.NONE, refreshType = RefreshType.NONE,
) { git -> ) { git ->
if (objectId == null) { if (objectId == null) {
@ -271,7 +272,7 @@ class TabState @Inject constructor(
if (commit == null) { if (commit == null) {
newSelectedItem(SelectedItem.None) newSelectedItem(SelectedItem.None)
} else { } else {
val newSelectedItem = SelectedItem.Ref(commit) val newSelectedItem = SelectedItem.Ref(ref, commit)
newSelectedItem(newSelectedItem) newSelectedItem(newSelectedItem)
_taskEvent.emit(TaskEvent.ScrollToGraphItem(newSelectedItem)) _taskEvent.emit(TaskEvent.ScrollToGraphItem(newSelectedItem))
} }

View File

@ -20,6 +20,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.jetpackduba.gitnuro.AppIcons import com.jetpackduba.gitnuro.AppIcons
import com.jetpackduba.gitnuro.extensions.backgroundIf
import com.jetpackduba.gitnuro.theme.backgroundSelected import com.jetpackduba.gitnuro.theme.backgroundSelected
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
@ -179,13 +180,7 @@ fun RebaseCommit(
.clickable { .clickable {
onFocusLine() onFocusLine()
} }
.run { .backgroundIf(isSelected, MaterialTheme.colors.backgroundSelected)
if (isSelected) {
background(MaterialTheme.colors.backgroundSelected)
} else {
this
}
}
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {

View File

@ -30,6 +30,7 @@ import com.jetpackduba.gitnuro.ui.diff.Diff
import com.jetpackduba.gitnuro.ui.log.Log import com.jetpackduba.gitnuro.ui.log.Log
import com.jetpackduba.gitnuro.viewmodels.BlameState import com.jetpackduba.gitnuro.viewmodels.BlameState
import com.jetpackduba.gitnuro.viewmodels.TabViewModel import com.jetpackduba.gitnuro.viewmodels.TabViewModel
import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.lib.RepositoryState import org.eclipse.jgit.lib.RepositoryState
import org.eclipse.jgit.revwalk.RevCommit import org.eclipse.jgit.revwalk.RevCommit
import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi
@ -413,7 +414,7 @@ sealed class SelectedItem {
object None : SelectedItem() object None : SelectedItem()
object UncommitedChanges : SelectedItem() object UncommitedChanges : SelectedItem()
sealed class CommitBasedItem(val revCommit: RevCommit) : SelectedItem() sealed class CommitBasedItem(val revCommit: RevCommit) : SelectedItem()
class Ref(revCommit: RevCommit) : CommitBasedItem(revCommit) class Ref(val ref: org.eclipse.jgit.lib.Ref, revCommit: RevCommit) : CommitBasedItem(revCommit)
class Commit(revCommit: RevCommit) : CommitBasedItem(revCommit) class Commit(revCommit: RevCommit) : CommitBasedItem(revCommit)
class Stash(revCommit: RevCommit) : CommitBasedItem(revCommit) class Stash(revCommit: RevCommit) : CommitBasedItem(revCommit)
} }

View File

@ -37,6 +37,7 @@ fun SidePanel(
submodulesViewModel: SubmodulesViewModel = sidePanelViewModel.submodulesViewModel, submodulesViewModel: SubmodulesViewModel = sidePanelViewModel.submodulesViewModel,
) { ) {
var filter by remember(sidePanelViewModel) { mutableStateOf(sidePanelViewModel.filter.value) } var filter by remember(sidePanelViewModel) { mutableStateOf(sidePanelViewModel.filter.value) }
val selectedItem by sidePanelViewModel.selectedItem.collectAsState()
val branchesState by branchesViewModel.branchesState.collectAsState() val branchesState by branchesViewModel.branchesState.collectAsState()
val remotesState by remotesViewModel.remoteState.collectAsState() val remotesState by remotesViewModel.remoteState.collectAsState()
@ -66,6 +67,7 @@ fun SidePanel(
) { ) {
localBranches( localBranches(
branchesState = branchesState, branchesState = branchesState,
selectedItem = selectedItem,
branchesViewModel = branchesViewModel, branchesViewModel = branchesViewModel,
onChangeDefaultUpstreamBranch = { setBranchToChangeUpstream(it) } onChangeDefaultUpstreamBranch = { setBranchToChangeUpstream(it) }
) )
@ -78,11 +80,13 @@ fun SidePanel(
tags( tags(
tagsState = tagsState, tagsState = tagsState,
selectedItem = selectedItem,
tagsViewModel = tagsViewModel, tagsViewModel = tagsViewModel,
) )
stashes( stashes(
stashesState = stashesState, stashesState = stashesState,
selectedItem = selectedItem,
stashesViewModel = stashesViewModel, stashesViewModel = stashesViewModel,
) )
@ -165,6 +169,7 @@ fun FilterTextField(value: String, onValueChange: (String) -> Unit, modifier: Mo
fun LazyListScope.localBranches( fun LazyListScope.localBranches(
branchesState: BranchesState, branchesState: BranchesState,
selectedItem: SelectedItem,
branchesViewModel: BranchesViewModel, branchesViewModel: BranchesViewModel,
onChangeDefaultUpstreamBranch: (Ref) -> Unit, onChangeDefaultUpstreamBranch: (Ref) -> Unit,
) { ) {
@ -191,18 +196,17 @@ fun LazyListScope.localBranches(
items(branches, key = { it.name }) { branch -> items(branches, key = { it.name }) { branch ->
Branch( Branch(
branch = branch, branch = branch,
isSelectedItem = selectedItem is SelectedItem.Ref && selectedItem.ref == branch,
currentBranch = currentBranch, currentBranch = currentBranch,
isCurrentBranch = currentBranch?.name == branch.name,
onBranchClicked = { branchesViewModel.selectBranch(branch) }, onBranchClicked = { branchesViewModel.selectBranch(branch) },
onBranchDoubleClicked = { branchesViewModel.checkoutRef(branch) }, onBranchDoubleClicked = { branchesViewModel.checkoutRef(branch) },
onCheckoutBranch = { branchesViewModel.checkoutRef(branch) }, onCheckoutBranch = { branchesViewModel.checkoutRef(branch) },
onMergeBranch = { branchesViewModel.mergeBranch(branch) }, onMergeBranch = { branchesViewModel.mergeBranch(branch) },
onDeleteBranch = { branchesViewModel.deleteBranch(branch) },
onRebaseBranch = { branchesViewModel.rebaseBranch(branch) }, onRebaseBranch = { branchesViewModel.rebaseBranch(branch) },
onDeleteBranch = { branchesViewModel.deleteBranch(branch) },
onPushToRemoteBranch = { branchesViewModel.pushToRemoteBranch(branch) }, onPushToRemoteBranch = { branchesViewModel.pushToRemoteBranch(branch) },
onPullFromRemoteBranch = { branchesViewModel.pullFromRemoteBranch(branch) }, onPullFromRemoteBranch = { branchesViewModel.pullFromRemoteBranch(branch) }
onChangeDefaultUpstreamBranch = { onChangeDefaultUpstreamBranch(branch) } ) { onChangeDefaultUpstreamBranch(branch) }
)
} }
} }
} }
@ -272,6 +276,7 @@ fun LazyListScope.remotes(
fun LazyListScope.tags( fun LazyListScope.tags(
tagsState: TagsState, tagsState: TagsState,
tagsViewModel: TagsViewModel, tagsViewModel: TagsViewModel,
selectedItem: SelectedItem,
) { ) {
val isExpanded = tagsState.isExpanded val isExpanded = tagsState.isExpanded
val tags = tagsState.tags val tags = tagsState.tags
@ -295,6 +300,7 @@ fun LazyListScope.tags(
items(tags, key = { it.name }) { tag -> items(tags, key = { it.name }) { tag ->
Tag( Tag(
tag, tag,
isSelected = selectedItem is SelectedItem.Ref && selectedItem.ref == tag,
onTagClicked = { tagsViewModel.selectTag(tag) }, onTagClicked = { tagsViewModel.selectTag(tag) },
onCheckoutTag = { tagsViewModel.checkoutRef(tag) }, onCheckoutTag = { tagsViewModel.checkoutRef(tag) },
onDeleteTag = { tagsViewModel.deleteTag(tag) } onDeleteTag = { tagsViewModel.deleteTag(tag) }
@ -306,6 +312,7 @@ fun LazyListScope.tags(
fun LazyListScope.stashes( fun LazyListScope.stashes(
stashesState: StashesState, stashesState: StashesState,
stashesViewModel: StashesViewModel, stashesViewModel: StashesViewModel,
selectedItem: SelectedItem,
) { ) {
val isExpanded = stashesState.isExpanded val isExpanded = stashesState.isExpanded
val stashes = stashesState.stashes val stashes = stashesState.stashes
@ -329,6 +336,7 @@ fun LazyListScope.stashes(
items(stashes, key = { it.name }) { stash -> items(stashes, key = { it.name }) { stash ->
Stash( Stash(
stash, stash,
isSelected = selectedItem is SelectedItem.Stash && selectedItem.revCommit == stash,
onClick = { stashesViewModel.selectStash(stash) }, onClick = { stashesViewModel.selectStash(stash) },
onApply = { stashesViewModel.applyStash(stash) }, onApply = { stashesViewModel.applyStash(stash) },
onPop = { stashesViewModel.popStash(stash) }, onPop = { stashesViewModel.popStash(stash) },
@ -396,7 +404,7 @@ fun LazyListScope.submodules(
private fun Branch( private fun Branch(
branch: Ref, branch: Ref,
currentBranch: Ref?, currentBranch: Ref?,
isCurrentBranch: Boolean, isSelectedItem: Boolean,
onBranchClicked: () -> Unit, onBranchClicked: () -> Unit,
onBranchDoubleClicked: () -> Unit, onBranchDoubleClicked: () -> Unit,
onCheckoutBranch: () -> Unit, onCheckoutBranch: () -> Unit,
@ -407,6 +415,8 @@ private fun Branch(
onPullFromRemoteBranch: () -> Unit, onPullFromRemoteBranch: () -> Unit,
onChangeDefaultUpstreamBranch: () -> Unit, onChangeDefaultUpstreamBranch: () -> Unit,
) { ) {
val isCurrentBranch = currentBranch?.name == branch.name
ContextMenu( ContextMenu(
items = { items = {
branchContextMenuItems( branchContextMenuItems(
@ -427,6 +437,7 @@ private fun Branch(
SideMenuSubentry( SideMenuSubentry(
text = branch.simpleName, text = branch.simpleName,
iconResourcePath = AppIcons.BRANCH, iconResourcePath = AppIcons.BRANCH,
isSelected = isSelectedItem,
onClick = onBranchClicked, onClick = onBranchClicked,
onDoubleClick = onBranchDoubleClicked, onDoubleClick = onBranchDoubleClicked,
) { ) {
@ -451,7 +462,8 @@ private fun Remote(
SideMenuSubentry( SideMenuSubentry(
text = remote.remoteInfo.remoteConfig.name, text = remote.remoteInfo.remoteConfig.name,
iconResourcePath = AppIcons.CLOUD, iconResourcePath = AppIcons.CLOUD,
onClick = onRemoteClicked onClick = onRemoteClicked,
isSelected = false,
) )
} }
@ -487,6 +499,7 @@ private fun RemoteBranches(
SideMenuSubentry( SideMenuSubentry(
text = remoteBranch.simpleName, text = remoteBranch.simpleName,
extraPadding = 24.dp, extraPadding = 24.dp,
isSelected = false,
iconResourcePath = AppIcons.BRANCH, iconResourcePath = AppIcons.BRANCH,
onClick = onBranchClicked, onClick = onBranchClicked,
onDoubleClick = onCheckoutBranch, onDoubleClick = onCheckoutBranch,
@ -497,6 +510,7 @@ private fun RemoteBranches(
@Composable @Composable
private fun Tag( private fun Tag(
tag: Ref, tag: Ref,
isSelected: Boolean,
onTagClicked: () -> Unit, onTagClicked: () -> Unit,
onCheckoutTag: () -> Unit, onCheckoutTag: () -> Unit,
onDeleteTag: () -> Unit, onDeleteTag: () -> Unit,
@ -511,6 +525,7 @@ private fun Tag(
) { ) {
SideMenuSubentry( SideMenuSubentry(
text = tag.simpleName, text = tag.simpleName,
isSelected = isSelected,
iconResourcePath = AppIcons.TAG, iconResourcePath = AppIcons.TAG,
onClick = onTagClicked, onClick = onTagClicked,
) )
@ -521,6 +536,7 @@ private fun Tag(
@Composable @Composable
private fun Stash( private fun Stash(
stash: RevCommit, stash: RevCommit,
isSelected: Boolean,
onClick: () -> Unit, onClick: () -> Unit,
onApply: () -> Unit, onApply: () -> Unit,
onPop: () -> Unit, onPop: () -> Unit,
@ -537,6 +553,7 @@ private fun Stash(
) { ) {
SideMenuSubentry( SideMenuSubentry(
text = stash.shortMessage, text = stash.shortMessage,
isSelected = isSelected,
iconResourcePath = AppIcons.STASH, iconResourcePath = AppIcons.STASH,
onClick = onClick, onClick = onClick,
) )
@ -569,6 +586,7 @@ private fun Submodule(
SideMenuSubentry( SideMenuSubentry(
text = submodule.first, text = submodule.first,
iconResourcePath = AppIcons.TOPIC, iconResourcePath = AppIcons.TOPIC,
isSelected = false,
onClick = { onClick = {
if (submodule.second.type.isValid()) { if (submodule.second.type.isValid()) {
onOpenSubmoduleInTab() onOpenSubmoduleInTab()

View File

@ -3,6 +3,7 @@
package com.jetpackduba.gitnuro.ui.components package com.jetpackduba.gitnuro.ui.components
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -15,6 +16,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.jetpackduba.gitnuro.extensions.backgroundIf
import com.jetpackduba.gitnuro.theme.backgroundSelected
const val ENTRY_HEIGHT = 36 const val ENTRY_HEIGHT = 36
@ -24,6 +27,7 @@ const val ENTRY_HEIGHT = 36
fun SideMenuSubentry( fun SideMenuSubentry(
text: String, text: String,
iconResourcePath: String, iconResourcePath: String,
isSelected: Boolean,
extraPadding: Dp = 0.dp, extraPadding: Dp = 0.dp,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
onDoubleClick: (() -> Unit)? = null, onDoubleClick: (() -> Unit)? = null,
@ -39,8 +43,8 @@ fun SideMenuSubentry(
else else
this this
} }
.padding(start = extraPadding), .padding(start = extraPadding)
// .background(background), .backgroundIf(isSelected, MaterialTheme.colors.backgroundSelected),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Icon( Icon(

View File

@ -9,6 +9,7 @@ import com.jetpackduba.gitnuro.git.rebase.RebaseBranchUseCase
import com.jetpackduba.gitnuro.git.remote_operations.PullFromSpecificBranchUseCase import com.jetpackduba.gitnuro.git.remote_operations.PullFromSpecificBranchUseCase
import com.jetpackduba.gitnuro.git.remote_operations.PushToSpecificBranchUseCase import com.jetpackduba.gitnuro.git.remote_operations.PushToSpecificBranchUseCase
import com.jetpackduba.gitnuro.preferences.AppSettings import com.jetpackduba.gitnuro.preferences.AppSettings
import com.jetpackduba.gitnuro.ui.SelectedItem
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -53,8 +54,7 @@ class BranchesViewModel @AssistedInject constructor(
init { init {
tabScope.launch { tabScope.launch {
tabState.refreshFlowFiltered(RefreshType.ALL_DATA) tabState.refreshFlowFiltered(RefreshType.ALL_DATA) {
{
refresh(tabState.git) refresh(tabState.git)
} }
} }
@ -105,7 +105,7 @@ class BranchesViewModel @AssistedInject constructor(
} }
fun selectBranch(ref: Ref) { fun selectBranch(ref: Ref) {
tabState.newSelectedRef(ref.objectId) tabState.newSelectedRef(ref, ref.objectId)
} }
fun pushToRemoteBranch(branch: Ref) = tabState.safeProcessing( fun pushToRemoteBranch(branch: Ref) = tabState.safeProcessing(

View File

@ -120,7 +120,7 @@ class RemotesViewModel @AssistedInject constructor(
} }
fun selectBranch(ref: Ref) { fun selectBranch(ref: Ref) {
tabState.newSelectedRef(ref.objectId) tabState.newSelectedRef(ref, ref.objectId)
} }
fun deleteRemote(remoteName: String, isNew: Boolean) = tabState.safeProcessing( fun deleteRemote(remoteName: String, isNew: Boolean) = tabState.safeProcessing(

View File

@ -1,6 +1,8 @@
package com.jetpackduba.gitnuro.viewmodels.sidepanel package com.jetpackduba.gitnuro.viewmodels.sidepanel
import com.jetpackduba.gitnuro.di.factories.* import com.jetpackduba.gitnuro.di.factories.*
import com.jetpackduba.gitnuro.git.TabState
import com.jetpackduba.gitnuro.ui.SelectedItem
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject import javax.inject.Inject
@ -11,9 +13,11 @@ class SidePanelViewModel @Inject constructor(
tagsViewModelFactory: TagsViewModelFactory, tagsViewModelFactory: TagsViewModelFactory,
stashesViewModelFactory: StashesViewModelFactory, stashesViewModelFactory: StashesViewModelFactory,
submodulesViewModelFactory: SubmodulesViewModelFactory, submodulesViewModelFactory: SubmodulesViewModelFactory,
tabState: TabState,
) { ) {
private val _filter = MutableStateFlow("") private val _filter = MutableStateFlow("")
val filter: StateFlow<String> = _filter val filter: StateFlow<String> = _filter
val selectedItem: StateFlow<SelectedItem> = tabState.selectedItem
val branchesViewModel: BranchesViewModel = branchesViewModelFactory.create(filter) val branchesViewModel: BranchesViewModel = branchesViewModelFactory.create(filter)
val remotesViewModel: RemotesViewModel = remotesViewModelFactory.create(filter) val remotesViewModel: RemotesViewModel = remotesViewModelFactory.create(filter)

View File

@ -67,7 +67,7 @@ class TagsViewModel @AssistedInject constructor(
} }
fun selectTag(tag: Ref) { fun selectTag(tag: Ref) {
tabState.newSelectedRef(tag.objectId) tabState.newSelectedRef(tag, tag.objectId)
} }
suspend fun refresh(git: Git) { suspend fun refresh(git: Git) {