Implemented context menu in side panel branches/tags

This commit is contained in:
Abdelilah El Aissaoui 2021-12-12 06:04:19 +01:00
parent e068ac42de
commit 2d32b77a69
8 changed files with 167 additions and 87 deletions

View File

@ -0,0 +1,3 @@
package app
const val MAX_SIDE_PANEL_ITEMS_HEIGHT = 300

View File

@ -1,5 +1,7 @@
package app.ui package app.ui
import androidx.compose.foundation.ContextMenuArea
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@ -7,9 +9,7 @@ import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -18,6 +18,8 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
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 app.MAX_SIDE_PANEL_ITEMS_HEIGHT
import app.extensions.isLocal
import app.ui.components.ScrollableLazyColumn import app.ui.components.ScrollableLazyColumn
import app.extensions.simpleName import app.extensions.simpleName
import app.git.GitManager import app.git.GitManager
@ -26,38 +28,69 @@ import app.theme.headerBackground
import app.theme.headerText import app.theme.headerText
import app.ui.components.SideMenuEntry import app.ui.components.SideMenuEntry
import app.ui.components.SideMenuSubentry import app.ui.components.SideMenuSubentry
import app.ui.components.entryHeight
import app.ui.context_menu.branchContextMenuItems
import app.ui.dialogs.MergeDialog
@Composable @Composable
fun Branches(gitManager: GitManager) { fun Branches(gitManager: GitManager) {
val branches by gitManager.branches.collectAsState() val branches by gitManager.branches.collectAsState()
val currentBranch by gitManager.currentBranch.collectAsState() val currentBranch by gitManager.currentBranch.collectAsState()
val (mergeBranch, setMergeBranch) = remember { mutableStateOf<Ref?>(null) }
Column { Column {
SideMenuEntry("Local branches") SideMenuEntry("Local branches")
val branchesHeight = branches.count() * 40 val branchesHeight = branches.count() * entryHeight
val maxHeight = if(branchesHeight < 300) val maxHeight = if (branchesHeight < MAX_SIDE_PANEL_ITEMS_HEIGHT)
branchesHeight branchesHeight
else else
300 MAX_SIDE_PANEL_ITEMS_HEIGHT
Box(modifier = Modifier.heightIn(max = maxHeight.dp)) { Box(modifier = Modifier.heightIn(max = maxHeight.dp)) {
ScrollableLazyColumn(modifier = Modifier.fillMaxWidth()) { ScrollableLazyColumn(modifier = Modifier.fillMaxWidth()) {
itemsIndexed(branches) { _, branch -> itemsIndexed(branches) { _, branch ->
BranchRow( BranchRow(
branch = branch, branch = branch,
isCurrentBranch = currentBranch == branch.name isCurrentBranch = currentBranch == branch.name,
onCheckoutBranch = { gitManager.checkoutRef(branch) },
onMergeBranch = { setMergeBranch(branch) },
onDeleteBranch = { gitManager.deleteBranch(branch) },
) )
} }
} }
} }
} }
if(mergeBranch != null) {
MergeDialog(
currentBranch,
mergeBranchName = mergeBranch.name,
onReject = { setMergeBranch(null) },
onAccept = { ff -> gitManager.mergeBranch(mergeBranch, ff) }
)
}
} }
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
private fun BranchRow( private fun BranchRow(
branch: Ref, branch: Ref,
isCurrentBranch: Boolean isCurrentBranch: Boolean,
onCheckoutBranch: () -> Unit,
onMergeBranch: () -> Unit,
onDeleteBranch: () -> Unit,
) {
ContextMenuArea(
items = {
branchContextMenuItems(
isCurrentBranch = isCurrentBranch,
isLocal = branch.isLocal,
onCheckoutBranch = onCheckoutBranch,
onMergeBranch = onMergeBranch,
onDeleteBranch = onDeleteBranch,
)
}
) { ) {
SideMenuSubentry( SideMenuSubentry(
text = branch.simpleName, text = branch.simpleName,
@ -74,3 +107,4 @@ private fun BranchRow(
} }
} }
} }
}

View File

@ -7,12 +7,14 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import app.MAX_SIDE_PANEL_ITEMS_HEIGHT
import app.ui.components.ScrollableLazyColumn import app.ui.components.ScrollableLazyColumn
import app.extensions.simpleVisibleName import app.extensions.simpleVisibleName
import app.git.GitManager import app.git.GitManager
import app.git.RemoteInfo import app.git.RemoteInfo
import app.ui.components.SideMenuEntry import app.ui.components.SideMenuEntry
import app.ui.components.SideMenuSubentry import app.ui.components.SideMenuSubentry
import app.ui.components.entryHeight
@Composable @Composable
fun Remotes(gitManager: GitManager) { fun Remotes(gitManager: GitManager) {
@ -22,11 +24,11 @@ fun Remotes(gitManager: GitManager) {
SideMenuEntry("Remotes") SideMenuEntry("Remotes")
val allBranches = remotes.map { it.branchesList }.flatten() val allBranches = remotes.map { it.branchesList }.flatten()
val remotesHeight = (allBranches.count() + remotes.count()) * 40 val remotesHeight = (allBranches.count() + remotes.count()) * entryHeight
val maxHeight = if(remotesHeight < 300) val maxHeight = if(remotesHeight < MAX_SIDE_PANEL_ITEMS_HEIGHT)
remotesHeight remotesHeight
else else
300 MAX_SIDE_PANEL_ITEMS_HEIGHT
Box(modifier = Modifier.heightIn(max = maxHeight.dp)) { Box(modifier = Modifier.heightIn(max = maxHeight.dp)) {
ScrollableLazyColumn(modifier = Modifier.fillMaxWidth()) { ScrollableLazyColumn(modifier = Modifier.fillMaxWidth()) {

View File

@ -1,29 +1,21 @@
package app.ui package app.ui
import androidx.compose.foundation.background import androidx.compose.foundation.ContextMenuArea
import androidx.compose.foundation.clickable import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import app.MAX_SIDE_PANEL_ITEMS_HEIGHT
import app.extensions.simpleName import app.extensions.simpleName
import app.ui.components.ScrollableLazyColumn import app.ui.components.ScrollableLazyColumn
import app.git.GitManager import app.git.GitManager
import app.git.StashStatus
import org.eclipse.jgit.revwalk.RevCommit
import app.theme.headerBackground
import app.theme.headerText
import app.ui.components.SideMenuEntry import app.ui.components.SideMenuEntry
import app.ui.components.SideMenuSubentry import app.ui.components.SideMenuSubentry
import app.ui.components.entryHeight
import app.ui.context_menu.tagContextMenuItems
import org.eclipse.jgit.lib.Ref import org.eclipse.jgit.lib.Ref
@Composable @Composable
@ -31,25 +23,25 @@ fun Tags(gitManager: GitManager) {
val tagsState = gitManager.tags.collectAsState() val tagsState = gitManager.tags.collectAsState()
val tags = tagsState.value val tags = tagsState.value
Column { Column {
SideMenuEntry( SideMenuEntry(
text = "Tags", text = "Tags",
) )
val branchesHeight = tags.count() * 40 val tagsHeight = tags.count() * entryHeight
val maxHeight = if (branchesHeight < 300) val maxHeight = if (tagsHeight < MAX_SIDE_PANEL_ITEMS_HEIGHT)
branchesHeight tagsHeight
else else
300 MAX_SIDE_PANEL_ITEMS_HEIGHT
Box(modifier = Modifier.heightIn(max = maxHeight.dp)) { Box(modifier = Modifier.heightIn(max = maxHeight.dp)) {
ScrollableLazyColumn(modifier = Modifier.fillMaxWidth()) { ScrollableLazyColumn(modifier = Modifier.fillMaxWidth()) {
items(items = tags) { tag -> items(items = tags) { tag ->
TagRow( TagRow(
tag = tag, tag = tag,
onCheckoutTag = { gitManager.checkoutRef(tag) },
onDeleteTag = { gitManager.deleteTag(tag) }
) )
} }
} }
} }
@ -57,10 +49,24 @@ fun Tags(gitManager: GitManager) {
} }
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
private fun TagRow(tag: Ref) { private fun TagRow(
tag: Ref,
onCheckoutTag: () -> Unit,
onDeleteTag: () -> Unit,
) {
ContextMenuArea(
items = {
tagContextMenuItems(
onCheckoutTag = onCheckoutTag,
onDeleteTag = onDeleteTag,
)
}
) {
SideMenuSubentry( SideMenuSubentry(
text = tag.simpleName, text = tag.simpleName,
iconResourcePath = "tag.svg", iconResourcePath = "tag.svg",
) )
} }
}

View File

@ -19,6 +19,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import app.theme.primaryTextColor import app.theme.primaryTextColor
const val entryHeight = 40
@Composable @Composable
fun SideMenuSubentry( fun SideMenuSubentry(
text: String, text: String,
@ -30,7 +32,7 @@ fun SideMenuSubentry(
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.height(40.dp) .height(entryHeight.dp)
.fillMaxWidth() .fillMaxWidth()
.clickable(onClick = onClick) .clickable(onClick = onClick)
.padding(start = extraPadding), .padding(start = extraPadding),

View File

@ -0,0 +1,38 @@
package app.ui.context_menu
import androidx.compose.foundation.ContextMenuItem
import androidx.compose.foundation.ExperimentalFoundationApi
@OptIn(ExperimentalFoundationApi::class)
fun branchContextMenuItems(
isCurrentBranch: Boolean,
isLocal: Boolean,
onCheckoutBranch: () -> Unit,
onMergeBranch: () -> Unit,
onDeleteBranch: () -> Unit,
): List<ContextMenuItem> {
return mutableListOf(
ContextMenuItem(
label = "Checkout branch",
onClick = onCheckoutBranch
),
).apply {
if (!isCurrentBranch) {
add(
ContextMenuItem(
label = "Merge branch",
onClick = onMergeBranch
)
)
}
if (isLocal && !isCurrentBranch) {
add(
ContextMenuItem(
label = "Delete branch",
onClick = onDeleteBranch
)
)
}
}
}

View File

@ -0,0 +1,22 @@
package app.ui.context_menu
import androidx.compose.foundation.ContextMenuItem
import androidx.compose.foundation.ExperimentalFoundationApi
import app.extensions.isLocal
@OptIn(ExperimentalFoundationApi::class)
fun tagContextMenuItems(
onCheckoutTag: () -> Unit,
onDeleteTag: () -> Unit,
): List<ContextMenuItem> {
return mutableListOf(
ContextMenuItem(
label = "Checkout tag",
onClick = onCheckoutTag
),
ContextMenuItem(
label = "Delete tag",
onClick = onDeleteTag
)
)
}

View File

@ -15,7 +15,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material.contentColorFor
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
@ -41,6 +40,8 @@ import app.images.rememberNetworkImage
import app.theme.* import app.theme.*
import app.ui.SelectedItem import app.ui.SelectedItem
import app.ui.components.ScrollableLazyColumn import app.ui.components.ScrollableLazyColumn
import app.ui.context_menu.branchContextMenuItems
import app.ui.context_menu.tagContextMenuItems
import app.ui.dialogs.MergeDialog import app.ui.dialogs.MergeDialog
import app.ui.dialogs.NewBranchDialog import app.ui.dialogs.NewBranchDialog
import app.ui.dialogs.NewTagDialog import app.ui.dialogs.NewTagDialog
@ -626,30 +627,13 @@ fun BranchChip(
color: Color, color: Color,
) { ) {
val contextMenuItemsList = { val contextMenuItemsList = {
mutableListOf( branchContextMenuItems(
ContextMenuItem( isCurrentBranch = isCurrentBranch,
label = "Checkout branch", isLocal = ref.isLocal,
onClick = onCheckoutBranch onCheckoutBranch = onCheckoutBranch,
), onMergeBranch = onMergeBranch,
onDeleteBranch = onDeleteBranch,
).apply {
if (!isCurrentBranch) {
add(
ContextMenuItem(
label = "Merge branch",
onClick = onMergeBranch
) )
)
}
if (ref.isLocal && !isCurrentBranch) {
add(
ContextMenuItem(
label = "Delete branch",
onClick = onDeleteBranch
)
)
}
}
} }
var endingContent: @Composable () -> Unit = {} var endingContent: @Composable () -> Unit = {}
@ -685,21 +669,10 @@ fun TagChip(
color: Color, color: Color,
) { ) {
val contextMenuItemsList = { val contextMenuItemsList = {
mutableListOf( tagContextMenuItems(
ContextMenuItem( onCheckoutTag = onCheckoutTag,
label = "Checkout tag", onDeleteTag = onDeleteTag,
onClick = onCheckoutTag
) )
).apply {
if (ref.isLocal) {
add(
ContextMenuItem(
label = "Delete tag",
onClick = onDeleteTag
)
)
}
}
} }
RefChip( RefChip(