diff --git a/src/main/kotlin/app/git/RemoteOperationsManager.kt b/src/main/kotlin/app/git/RemoteOperationsManager.kt index 5aeddfe..e31c4dd 100644 --- a/src/main/kotlin/app/git/RemoteOperationsManager.kt +++ b/src/main/kotlin/app/git/RemoteOperationsManager.kt @@ -20,7 +20,7 @@ class RemoteOperationsManager @Inject constructor( val cloneStatus: StateFlow get() = _cloneStatus - suspend fun pull(git: Git) = withContext(Dispatchers.IO) { + suspend fun pull(git: Git, rebase: Boolean) = withContext(Dispatchers.IO) { git .pull() .setTransportConfigCallback { @@ -30,6 +30,7 @@ class RemoteOperationsManager @Inject constructor( it.credentialsProvider = HttpCredentialsProvider() } } + .setRebase(rebase) .setCredentialsProvider(CredentialsProvider.getDefault()) .call() } diff --git a/src/main/kotlin/app/ui/Menu.kt b/src/main/kotlin/app/ui/Menu.kt index 1729240..fb1909b 100644 --- a/src/main/kotlin/app/ui/Menu.kt +++ b/src/main/kotlin/app/ui/Menu.kt @@ -1,13 +1,14 @@ -@file:OptIn(ExperimentalComposeUiApi::class) +@file:OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class) package app.ui -import androidx.compose.foundation.Image +import androidx.compose.foundation.* import androidx.compose.foundation.layout.* -import androidx.compose.material.MaterialTheme -import androidx.compose.material.OutlinedButton -import androidx.compose.material.Text -import androidx.compose.runtime.Composable +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -17,7 +18,12 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import app.theme.primaryTextColor +import app.ui.context_menu.pullContextMenuItems import app.viewmodels.MenuViewModel +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import app.ui.context_menu.DropDownContent +import app.ui.context_menu.DropDownContentData // TODO Add tooltips to all the buttons @Composable @@ -43,10 +49,15 @@ fun Menu( Spacer(modifier = Modifier.weight(1f)) - MenuButton( + ExtendedMenuButton( title = "Pull", icon = painterResource("download.svg"), onClick = { menuViewModel.pull() }, + extendedListItems = pullContextMenuItems( + onPullRebase = { + menuViewModel.pull(true) + } + ) ) MenuButton( @@ -65,7 +76,6 @@ fun Menu( }, ) - Spacer(modifier = Modifier.width(16.dp)) MenuButton( @@ -103,11 +113,12 @@ fun MenuButton( MaterialTheme.colors.secondaryVariant } - OutlinedButton( + Box( modifier = modifier - .padding(horizontal = 2.dp), - enabled = enabled, - onClick = onClick, + .padding(horizontal = 2.dp) + .clickable { if (enabled) onClick() } + .border(ButtonDefaults.outlinedBorder, RoundedCornerShape(3.dp)) + .padding(vertical = 8.dp, horizontal = 16.dp), ) { Row( horizontalArrangement = Arrangement.Center, @@ -127,7 +138,82 @@ fun MenuButton( color = MaterialTheme.colors.primaryTextColor ) } + } +} +@Composable +fun ExtendedMenuButton( + modifier: Modifier = Modifier, + enabled: Boolean = true, + title: String, + icon: Painter, + onClick: () -> Unit, + extendedListItems: List, +) { + val iconColor = if (enabled) { + MaterialTheme.colors.primary + } else { + MaterialTheme.colors.secondaryVariant + } + + var showDropDownMenu by remember { mutableStateOf(false) } + + Row(modifier = Modifier.height(IntrinsicSize.Min)) { + Box( + modifier = modifier + .clickable { if (enabled) onClick() } + .border(ButtonDefaults.outlinedBorder, RoundedCornerShape(topStart = 3.dp, bottomStart = 3.dp)) + .padding(vertical = 8.dp, horizontal = 16.dp), + ) { + Row( + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + painter = icon, + contentDescription = title, + modifier = Modifier + .padding(horizontal = 4.dp) + .size(24.dp), + colorFilter = ColorFilter.tint(iconColor), + ) + Text( + text = title, + fontSize = 12.sp, + color = MaterialTheme.colors.primaryTextColor + ) + } + } + + Box( + modifier = modifier + .padding(end = 8.dp) + .width(20.dp) + .fillMaxHeight() + .border(ButtonDefaults.outlinedBorder, RoundedCornerShape(topEnd = 3.dp, bottomEnd = 3.dp)) + .clickable { + showDropDownMenu = true + }, + contentAlignment = Alignment.Center, + ) { + Icon( + Icons.Default.ArrowDropDown, + contentDescription = null, + tint = MaterialTheme.colors.primaryTextColor, + ) + + DropdownMenu( + onDismissRequest = { + showDropDownMenu = false + }, + content = { + for (item in extendedListItems) { + DropDownContent(item, onDismiss = { showDropDownMenu = false }) + } + }, + expanded = showDropDownMenu, + ) + } } } diff --git a/src/main/kotlin/app/ui/context_menu/DropDownContent.kt b/src/main/kotlin/app/ui/context_menu/DropDownContent.kt new file mode 100644 index 0000000..211cb7d --- /dev/null +++ b/src/main/kotlin/app/ui/context_menu/DropDownContent.kt @@ -0,0 +1,26 @@ +package app.ui.context_menu + +import androidx.compose.foundation.layout.Row +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.sp + +@Composable +fun DropDownContent(dropDownContentData: DropDownContentData, onDismiss: () -> Unit) { + DropdownMenuItem( + onClick = { + dropDownContentData.onClick() + onDismiss() + } + ) { + Row { + if (dropDownContentData.icon != null) { + Icon(imageVector = dropDownContentData.icon, contentDescription = null) + } + + Text(dropDownContentData.label, fontSize = 14.sp) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/ui/context_menu/DropDownContentData.kt b/src/main/kotlin/app/ui/context_menu/DropDownContentData.kt new file mode 100644 index 0000000..8c9a82d --- /dev/null +++ b/src/main/kotlin/app/ui/context_menu/DropDownContentData.kt @@ -0,0 +1,9 @@ +package app.ui.context_menu + +import androidx.compose.ui.graphics.vector.ImageVector + +data class DropDownContentData( + val label: String, + val icon: ImageVector? = null, + val onClick: () -> Unit, +) diff --git a/src/main/kotlin/app/ui/context_menu/PullContextMenu.kt b/src/main/kotlin/app/ui/context_menu/PullContextMenu.kt new file mode 100644 index 0000000..d992900 --- /dev/null +++ b/src/main/kotlin/app/ui/context_menu/PullContextMenu.kt @@ -0,0 +1,15 @@ +package app.ui.context_menu + +import androidx.compose.foundation.ExperimentalFoundationApi + +@OptIn(ExperimentalFoundationApi::class) +fun pullContextMenuItems( + onPullRebase: () -> Unit, +): List { + return mutableListOf( + DropDownContentData( + label = "Pull with rebase", + onClick = onPullRebase, + ), + ) +} diff --git a/src/main/kotlin/app/viewmodels/MenuViewModel.kt b/src/main/kotlin/app/viewmodels/MenuViewModel.kt index db222e0..782a53d 100644 --- a/src/main/kotlin/app/viewmodels/MenuViewModel.kt +++ b/src/main/kotlin/app/viewmodels/MenuViewModel.kt @@ -12,8 +12,8 @@ class MenuViewModel @Inject constructor( private val remoteOperationsManager: RemoteOperationsManager, private val stashManager: StashManager, ) { - fun pull() = tabState.safeProcessing { git -> - remoteOperationsManager.pull(git) + fun pull(rebase: Boolean = false) = tabState.safeProcessing { git -> + remoteOperationsManager.pull(git, rebase) return@safeProcessing RefreshType.ONLY_LOG }