Created custom implementation of context menu and added new icons
@ -27,6 +27,7 @@ dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
|
||||
implementation(compose.desktop.components.splitPane)
|
||||
implementation(compose("org.jetbrains.compose.ui:ui-util"))
|
||||
implementation("org.eclipse.jgit:org.eclipse.jgit:6.2.0.202206071550-r")
|
||||
implementation("org.apache.sshd:sshd-core:2.9.0")
|
||||
implementation("com.google.dagger:dagger:2.43.2")
|
||||
@ -56,7 +57,7 @@ tasks.withType<KotlinCompile> {
|
||||
|
||||
compose.desktop {
|
||||
application {
|
||||
mainClass = "MainKt"
|
||||
mainClass = "com.jetpackduba.gitnuro.MainKt"
|
||||
|
||||
nativeDistributions {
|
||||
includeAllModules = true
|
||||
|
@ -63,7 +63,7 @@ fun rememberNetworkImageOrNull(url: String, placeHolderImageRes: String? = null)
|
||||
val cacheImageUsed = remember { ValueHolder(false) }
|
||||
|
||||
var image by remember(url) {
|
||||
val cachedImage = NetworkImageLoader.loadCachedImage(url)
|
||||
val cachedImage = networkImageLoader.loadCachedImage(url)
|
||||
|
||||
val image: ImageBitmap? = when {
|
||||
cachedImage != null -> {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import com.jetpackduba.gitnuro.App
|
||||
package com.jetpackduba.gitnuro
|
||||
|
||||
fun main() {
|
||||
val main = App()
|
||||
|
@ -27,6 +27,7 @@ val lightTheme = ColorsScheme(
|
||||
hoverScrollbar = Color(0xFF0070D8),
|
||||
diffLineAdded = Color(0xFFd7ebd0),
|
||||
diffLineRemoved = Color(0xFFf0d4d4),
|
||||
isLight = true,
|
||||
)
|
||||
|
||||
|
||||
@ -55,7 +56,7 @@ val darkBlueTheme = ColorsScheme(
|
||||
hoverScrollbar = Color(0xFFCCCCCC),
|
||||
diffLineAdded = Color(0xFF566f5a),
|
||||
diffLineRemoved = Color(0xFF6f585e),
|
||||
|
||||
isLight = false,
|
||||
)
|
||||
|
||||
val darkGrayTheme = ColorsScheme(
|
||||
@ -83,4 +84,5 @@ val darkGrayTheme = ColorsScheme(
|
||||
hoverScrollbar = Color(0xFFCCCCCC),
|
||||
diffLineAdded = Color(0xFF5b7059),
|
||||
diffLineRemoved = Color(0xFF74595c),
|
||||
isLight = false,
|
||||
)
|
@ -14,7 +14,6 @@ import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
|
||||
// TODO Add line added + removed colors, graph colors and icons color for added/modified/removed files.
|
||||
@Serializable
|
||||
data class ColorsScheme(
|
||||
val primary: Color,
|
||||
@ -42,6 +41,7 @@ data class ColorsScheme(
|
||||
val hoverScrollbar: Color,
|
||||
val diffLineAdded: Color,
|
||||
val diffLineRemoved: Color,
|
||||
val isLight: Boolean,
|
||||
) {
|
||||
fun toComposeColors(): Colors {
|
||||
return Colors(
|
||||
@ -57,7 +57,7 @@ data class ColorsScheme(
|
||||
onBackground = this.primaryText,
|
||||
onSurface = this.primaryText,
|
||||
onError = this.onError,
|
||||
isLight = true, // property specific for some colors, we don't care about this as all our components are customized
|
||||
isLight = isLight,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ fun typography() = Typography(
|
||||
body2 = TextStyle(
|
||||
fontSize = 13.sp,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
fontWeight = FontWeight.Normal,
|
||||
letterSpacing = LETTER_SPACING.sp,
|
||||
),
|
||||
caption = TextStyle(
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.jetpackduba.gitnuro.ui
|
||||
|
||||
import androidx.compose.foundation.ContextMenuArea
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.MaterialTheme
|
||||
@ -16,11 +15,11 @@ import com.jetpackduba.gitnuro.extensions.simpleName
|
||||
import com.jetpackduba.gitnuro.theme.secondaryTextColor
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuPanel
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuSubentry
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.branchContextMenuItems
|
||||
import com.jetpackduba.gitnuro.viewmodels.BranchesViewModel
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun Branches(
|
||||
branchesViewModel: BranchesViewModel,
|
||||
@ -69,7 +68,7 @@ private fun BranchLineEntry(
|
||||
onPushToRemoteBranch: () -> Unit,
|
||||
onPullFromRemoteBranch: () -> Unit,
|
||||
) {
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = {
|
||||
branchContextMenuItems(
|
||||
branch = branch,
|
||||
|
@ -21,6 +21,7 @@ import com.jetpackduba.gitnuro.viewmodels.CommitChangesStatus
|
||||
import com.jetpackduba.gitnuro.viewmodels.CommitChangesViewModel
|
||||
import com.jetpackduba.gitnuro.extensions.*
|
||||
import com.jetpackduba.gitnuro.theme.*
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenu
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.eclipse.jgit.diff.DiffEntry
|
||||
@ -228,7 +229,7 @@ fun CommitLogChanges(
|
||||
.fillMaxSize()
|
||||
) {
|
||||
items(items = diffEntries) { diffEntry ->
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = {
|
||||
commitedChangesEntriesContextMenuItems(
|
||||
diffEntry,
|
||||
|
@ -1,9 +1,7 @@
|
||||
@file:OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
|
||||
@file:OptIn(ExperimentalComposeUiApi::class)
|
||||
|
||||
package com.jetpackduba.gitnuro.ui
|
||||
|
||||
import androidx.compose.foundation.ContextMenuArea
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@ -23,6 +21,7 @@ import com.jetpackduba.gitnuro.theme.primaryTextColor
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuPanel
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuSubentry
|
||||
import com.jetpackduba.gitnuro.ui.components.VerticalExpandable
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.remoteBranchesContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.remoteContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.EditRemotesDialog
|
||||
@ -30,6 +29,7 @@ import com.jetpackduba.gitnuro.viewmodels.RemoteView
|
||||
import com.jetpackduba.gitnuro.viewmodels.RemotesViewModel
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun Remotes(
|
||||
remotesViewModel: RemotesViewModel,
|
||||
@ -85,7 +85,6 @@ fun Remotes(
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun RemoteRow(
|
||||
remote: RemoteView,
|
||||
@ -106,7 +105,7 @@ private fun RemoteRow(
|
||||
val branches = remote.remoteInfo.branchesList
|
||||
Column {
|
||||
branches.forEach { branch ->
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = {
|
||||
remoteBranchesContextMenu(
|
||||
onDeleteBranch = { onDeleteBranch(branch) }
|
||||
|
@ -1,9 +1,5 @@
|
||||
@file:OptIn(ExperimentalFoundationApi::class)
|
||||
|
||||
package com.jetpackduba.gitnuro.ui
|
||||
|
||||
import androidx.compose.foundation.ContextMenuArea
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@ -11,6 +7,8 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuPanel
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuSubentry
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenuElement
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.stashesContextMenuItems
|
||||
import com.jetpackduba.gitnuro.viewmodels.StashStatus
|
||||
import com.jetpackduba.gitnuro.viewmodels.StashesViewModel
|
||||
@ -58,9 +56,9 @@ fun Stashes(
|
||||
private fun StashRow(
|
||||
stash: RevCommit,
|
||||
onClick: () -> Unit,
|
||||
contextItems: List<ContextMenuItem>,
|
||||
contextItems: List<ContextMenuElement>,
|
||||
) {
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = { contextItems }
|
||||
) {
|
||||
SideMenuSubentry(
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.jetpackduba.gitnuro.ui
|
||||
|
||||
import androidx.compose.foundation.ContextMenuArea
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
@ -15,11 +13,11 @@ import com.jetpackduba.gitnuro.theme.secondaryTextColor
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuPanel
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuSubentry
|
||||
import com.jetpackduba.gitnuro.ui.components.Tooltip
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.submoduleContextMenuItems
|
||||
import com.jetpackduba.gitnuro.viewmodels.SubmodulesViewModel
|
||||
import org.eclipse.jgit.submodule.SubmoduleStatus
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun Submodules(
|
||||
submodulesViewModel: SubmodulesViewModel,
|
||||
@ -42,13 +40,12 @@ fun Submodules(
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun SubmoduleLineEntry(
|
||||
submodulePair: Pair<String, SubmoduleStatus>,
|
||||
onInitializeModule: () -> Unit,
|
||||
) {
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = {
|
||||
submoduleContextMenuItems(
|
||||
submodulePair.second,
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.jetpackduba.gitnuro.ui
|
||||
|
||||
import androidx.compose.foundation.ContextMenuArea
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@ -9,6 +8,7 @@ import androidx.compose.ui.res.painterResource
|
||||
import com.jetpackduba.gitnuro.extensions.simpleName
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuPanel
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuSubentry
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.tagContextMenuItems
|
||||
import com.jetpackduba.gitnuro.viewmodels.TagsViewModel
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
@ -47,7 +47,7 @@ private fun TagRow(
|
||||
onCheckoutTag: () -> Unit,
|
||||
onDeleteTag: () -> Unit,
|
||||
) {
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = {
|
||||
tagContextMenuItems(
|
||||
onCheckoutTag = onCheckoutTag,
|
||||
|
@ -35,14 +35,11 @@ import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
||||
import com.jetpackduba.gitnuro.ui.components.ScrollableLazyColumn
|
||||
import com.jetpackduba.gitnuro.ui.components.SecondaryButton
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.DropDownContent
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.DropDownContentData
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.EntryType
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.statusEntriesContextMenuItems
|
||||
import com.jetpackduba.gitnuro.viewmodels.StageStatus
|
||||
import com.jetpackduba.gitnuro.viewmodels.StatusViewModel
|
||||
import com.jetpackduba.gitnuro.extensions.*
|
||||
import com.jetpackduba.gitnuro.theme.*
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.*
|
||||
import org.eclipse.jgit.lib.RepositoryState
|
||||
|
||||
@Composable
|
||||
@ -496,7 +493,7 @@ private fun EntriesList(
|
||||
lazyListState: LazyListState,
|
||||
onDiffEntrySelected: (StatusEntry) -> Unit,
|
||||
onDiffEntryOptionSelected: (StatusEntry) -> Unit,
|
||||
onGenerateContextMenu: (StatusEntry) -> List<ContextMenuItem>,
|
||||
onGenerateContextMenu: (StatusEntry) -> List<ContextMenuElement>,
|
||||
onAllAction: () -> Unit,
|
||||
allActionTitle: String,
|
||||
selectedEntryType: DiffEntryType?,
|
||||
@ -571,7 +568,7 @@ private fun FileEntry(
|
||||
actionColor: Color,
|
||||
onClick: () -> Unit,
|
||||
onButtonClick: () -> Unit,
|
||||
onGenerateContextMenu: (StatusEntry) -> List<ContextMenuItem>,
|
||||
onGenerateContextMenu: (StatusEntry) -> List<ContextMenuElement>,
|
||||
) {
|
||||
val hoverInteraction = remember { MutableInteractionSource() }
|
||||
val isHovered by hoverInteraction.collectIsHoveredAsState()
|
||||
@ -582,7 +579,7 @@ private fun FileEntry(
|
||||
.fillMaxWidth()
|
||||
.hoverable(hoverInteraction)
|
||||
) {
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = {
|
||||
onGenerateContextMenu(statusEntry)
|
||||
},
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.jetpackduba.gitnuro.ui.components
|
||||
|
||||
import androidx.compose.foundation.ContextMenuArea
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@ -10,6 +8,8 @@ import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenuElement
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
@ -21,13 +21,13 @@ fun <T> SideMenuPanel(
|
||||
onExpand: () -> Unit,
|
||||
itemContent: @Composable (T) -> Unit,
|
||||
headerHoverIcon: @Composable (() -> Unit)? = null,
|
||||
contextItems: () -> List<ContextMenuItem> = { emptyList() },
|
||||
contextItems: () -> List<ContextMenuElement> = { emptyList() },
|
||||
) {
|
||||
VerticalExpandable(
|
||||
isExpanded = isExpanded,
|
||||
onExpand = onExpand,
|
||||
header = {
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = contextItems
|
||||
) {
|
||||
SideMenuEntry(
|
||||
|
@ -1,12 +1,10 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.jetpackduba.gitnuro.extensions.isHead
|
||||
import com.jetpackduba.gitnuro.extensions.simpleLogName
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun branchContextMenuItems(
|
||||
branch: Ref,
|
||||
isCurrentBranch: Boolean,
|
||||
@ -19,47 +17,51 @@ fun branchContextMenuItems(
|
||||
onDeleteRemoteBranch: () -> Unit = {},
|
||||
onPushToRemoteBranch: () -> Unit,
|
||||
onPullFromRemoteBranch: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf<ContextMenuItem>().apply {
|
||||
): List<ContextMenuElement> {
|
||||
return mutableListOf<ContextMenuElement>().apply {
|
||||
if (!isCurrentBranch) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Checkout branch",
|
||||
icon = { painterResource("start.svg") },
|
||||
onClick = onCheckoutBranch
|
||||
)
|
||||
)
|
||||
if (currentBranch != null && !currentBranch.isHead) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Merge branch",
|
||||
onClick = onMergeBranch
|
||||
)
|
||||
)
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Rebase branch",
|
||||
onClick = onRebaseBranch
|
||||
)
|
||||
)
|
||||
|
||||
add(ContextMenuElement.ContextSeparator)
|
||||
}
|
||||
}
|
||||
if (isLocal && !isCurrentBranch) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Delete branch",
|
||||
icon = { painterResource("delete.svg") },
|
||||
onClick = onDeleteBranch
|
||||
)
|
||||
)
|
||||
}
|
||||
if (!isLocal && currentBranch != null && !currentBranch.isHead) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Push ${currentBranch.simpleLogName} to ${branch.simpleLogName}",
|
||||
onClick = onPushToRemoteBranch
|
||||
)
|
||||
)
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Pull ${branch.simpleLogName} to ${currentBranch.simpleLogName}",
|
||||
onClick = onPullFromRemoteBranch
|
||||
)
|
||||
@ -67,11 +69,16 @@ fun branchContextMenuItems(
|
||||
}
|
||||
if (!isLocal) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Delete remote branch",
|
||||
icon = { painterResource("delete.svg") },
|
||||
onClick = onDeleteRemoteBranch
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if(lastOrNull() == ContextMenuElement.ContextSeparator) {
|
||||
removeLast()
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import org.eclipse.jgit.diff.DiffEntry
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@ -9,19 +10,20 @@ fun commitedChangesEntriesContextMenuItems(
|
||||
diffEntry: DiffEntry,
|
||||
onBlame: () -> Unit,
|
||||
onHistory: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf<ContextMenuItem>().apply {
|
||||
): List<ContextMenuElement> {
|
||||
return mutableListOf<ContextMenuElement>().apply {
|
||||
if (diffEntry.changeType != DiffEntry.ChangeType.ADD ||
|
||||
diffEntry.changeType != DiffEntry.ChangeType.DELETE
|
||||
) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Blame file",
|
||||
icon = { painterResource("blame.svg") },
|
||||
onClick = onBlame,
|
||||
)
|
||||
)
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "File history",
|
||||
onClick = onHistory,
|
||||
)
|
||||
|
@ -0,0 +1,226 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.awt.awtEventOrNull
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||
import androidx.compose.ui.input.pointer.*
|
||||
import androidx.compose.ui.unit.*
|
||||
import androidx.compose.ui.util.fastAll
|
||||
import androidx.compose.ui.window.Popup
|
||||
import androidx.compose.ui.window.PopupPositionProvider
|
||||
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
||||
import com.jetpackduba.gitnuro.theme.primaryTextColor
|
||||
import com.jetpackduba.gitnuro.theme.secondaryTextColor
|
||||
import java.awt.event.MouseEvent
|
||||
import kotlin.math.abs
|
||||
|
||||
private var lastCheck: Long = 0
|
||||
private const val MIN_TIME_BETWEEN_POPUPS = 20
|
||||
|
||||
@Composable
|
||||
fun ContextMenu(items: () -> List<ContextMenuElement>, function: @Composable () -> Unit) {
|
||||
Box(modifier = Modifier.contextMenu(items), propagateMinConstraints = true) {
|
||||
function()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
private fun Modifier.contextMenu(items: () -> List<ContextMenuElement>): Modifier {
|
||||
var lastMouseEventState by remember { mutableStateOf<MouseEvent?>(null) }
|
||||
val mod = this.pointerInput(Unit) {
|
||||
|
||||
while (true) {
|
||||
val lastMouseEvent = awaitPointerEventScope { awaitEventFirstDown() }
|
||||
val mouseEvent = lastMouseEvent.awtEventOrNull
|
||||
|
||||
if (mouseEvent != null) {
|
||||
if (!lastMouseEvent.toString().contains("MOUSE_MOVED"))
|
||||
println(lastMouseEvent.toString())
|
||||
|
||||
if (lastMouseEvent.button.isSecondary) {
|
||||
val currentCheck = System.currentTimeMillis()
|
||||
if (lastCheck != 0L && currentCheck - lastCheck < MIN_TIME_BETWEEN_POPUPS) {
|
||||
println("IGNORE POPUP TRIGGERED!")
|
||||
} else {
|
||||
println("POPUP TRIGGERED!")
|
||||
println("X: ${mouseEvent.x}\nY: ${mouseEvent.y}")
|
||||
lastCheck = currentCheck
|
||||
|
||||
lastMouseEventState = mouseEvent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastMouseEventState != null) {
|
||||
showPopup(
|
||||
lastMouseEventState!!.x,
|
||||
lastMouseEventState!!.y,
|
||||
items(),
|
||||
onDismissRequest = { lastMouseEventState = null })
|
||||
}
|
||||
|
||||
return mod
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun showPopup(x: Int, y: Int, contextMenuElements: List<ContextMenuElement>, onDismissRequest: () -> Unit) {
|
||||
LaunchedEffect(contextMenuElements) {
|
||||
println("Items count ${contextMenuElements.count()}")
|
||||
}
|
||||
Popup(
|
||||
focusable = true,
|
||||
popupPositionProvider = object : PopupPositionProvider {
|
||||
override fun calculatePosition(
|
||||
anchorBounds: IntRect,
|
||||
windowSize: IntSize,
|
||||
layoutDirection: LayoutDirection,
|
||||
popupContentSize: IntSize
|
||||
): IntOffset {
|
||||
val resultY = if (popupContentSize.height > windowSize.height) {
|
||||
0 // If the popup is taller than the window itself
|
||||
} else if (y + popupContentSize.height > windowSize.height) {
|
||||
// If the end of the popup would go out of bounds.
|
||||
// Move the Y a bit to the top to make it fit
|
||||
y - abs(windowSize.height - (y + popupContentSize.height))
|
||||
} else {
|
||||
y
|
||||
}
|
||||
|
||||
val resultX = if (x + popupContentSize.width > windowSize.width && popupContentSize.width < x) {
|
||||
// If the end of the popup would go out of bounds.
|
||||
// Move the X a bit to the left to make it fit
|
||||
x - abs(windowSize.width - (x + popupContentSize.width))
|
||||
} else {
|
||||
x
|
||||
}
|
||||
|
||||
return IntOffset(resultX, resultY)
|
||||
}
|
||||
},
|
||||
onDismissRequest = onDismissRequest
|
||||
) {
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.shadow(4.dp)
|
||||
.width(300.dp)
|
||||
.background(MaterialTheme.colors.background)
|
||||
.run {
|
||||
return@run if (!MaterialTheme.colors.isLight) {
|
||||
this.border(1.dp, MaterialTheme.colors.primaryTextColor.copy(alpha = 0.2f))
|
||||
} else
|
||||
this
|
||||
}
|
||||
.focusRequester(focusRequester)
|
||||
.focusable()
|
||||
.onPreviewKeyEvent { keyEvent ->
|
||||
if (keyEvent.matchesBinding(KeybindingOption.EXIT)) {
|
||||
onDismissRequest()
|
||||
true
|
||||
} else
|
||||
false
|
||||
},
|
||||
) {
|
||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
||||
for (item in contextMenuElements) {
|
||||
when (item) {
|
||||
is ContextMenuElement.ContextTextEntry -> TextEntry(item, onDismissRequest = onDismissRequest)
|
||||
ContextMenuElement.ContextSeparator -> Separator()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Separator() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth()
|
||||
.height(1.dp)
|
||||
.background(MaterialTheme.colors.primaryTextColor.copy(alpha = 0.4f))
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun focusRequesterAndModifier(): Pair<FocusRequester, Modifier> {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
return focusRequester to Modifier.focusRequester(focusRequester)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TextEntry(contextTextEntry: ContextMenuElement.ContextTextEntry, onDismissRequest: () -> Unit) {
|
||||
val icon = contextTextEntry.icon
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
onDismissRequest()
|
||||
contextTextEntry.onClick()
|
||||
}
|
||||
.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Box(modifier = Modifier.size(24.dp).padding(end = 8.dp)) {
|
||||
if (icon != null) {
|
||||
Icon(
|
||||
painter = icon(),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
tint = (MaterialTheme.colors.secondaryTextColor.copy(alpha = 0.8f))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
contextTextEntry.label,
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface ContextMenuElement {
|
||||
data class ContextTextEntry(
|
||||
val label: String,
|
||||
val icon: @Composable (() -> Painter)? = null,
|
||||
val onClick: () -> Unit = {}
|
||||
) : ContextMenuElement
|
||||
|
||||
object ContextSeparator : ContextMenuElement
|
||||
}
|
||||
|
||||
private suspend fun AwaitPointerEventScope.awaitEventFirstDown(): PointerEvent {
|
||||
var event: PointerEvent
|
||||
do {
|
||||
event = awaitPointerEvent()
|
||||
} while (
|
||||
!event.changes.fastAll { it.changedToDown() }
|
||||
)
|
||||
return event
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
||||
fun logContextMenu(
|
||||
onCheckoutCommit: () -> Unit,
|
||||
@ -12,32 +11,38 @@ fun logContextMenu(
|
||||
onResetBranch: () -> Unit,
|
||||
onRebaseInteractive: () -> Unit,
|
||||
) = listOf(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Checkout commit",
|
||||
icon = { painterResource("start.svg") },
|
||||
onClick = onCheckoutCommit
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Create branch",
|
||||
icon = { painterResource("branch.svg") },
|
||||
onClick = onCreateNewBranch
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Create tag",
|
||||
icon = { painterResource("tag.svg") },
|
||||
onClick = onCreateNewTag
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextSeparator,
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Rebase interactive",
|
||||
onClick = onRebaseInteractive
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Revert commit",
|
||||
icon = { painterResource("revert.svg") },
|
||||
onClick = onRevertCommit
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Cherry-pick commit",
|
||||
onClick = onCherryPickCommit
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Reset current branch to this commit",
|
||||
icon = { painterResource("undo.svg") },
|
||||
onClick = onResetBranch
|
||||
),
|
||||
)
|
@ -4,13 +4,15 @@ package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
||||
fun remoteBranchesContextMenu(
|
||||
onDeleteBranch: () -> Unit
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf(
|
||||
ContextMenuItem(
|
||||
): List<ContextMenuElement> {
|
||||
return listOf(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Delete remote branch",
|
||||
icon = { painterResource("delete.svg") },
|
||||
onClick = onDeleteBranch
|
||||
),
|
||||
)
|
||||
|
@ -1,13 +1,9 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun remoteContextMenu(
|
||||
onEditRemotes: () -> Unit,
|
||||
) = listOf(
|
||||
ContextMenuItem(
|
||||
): List<ContextMenuElement> = listOf(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Edit remotes",
|
||||
onClick = onEditRemotes
|
||||
),
|
||||
|
@ -1,23 +0,0 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import com.jetpackduba.gitnuro.git.workspace.StatusEntry
|
||||
import com.jetpackduba.gitnuro.git.workspace.StatusType
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun stagedEntriesContextMenuItems(
|
||||
diffEntry: StatusEntry,
|
||||
onReset: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf<ContextMenuItem>().apply {
|
||||
if (diffEntry.statusType != StatusType.ADDED) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
label = "Reset",
|
||||
onClick = onReset,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +1,26 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun stashesContextMenuItems(
|
||||
onApply: () -> Unit,
|
||||
onPop: () -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf(
|
||||
ContextMenuItem(
|
||||
): List<ContextMenuElement> {
|
||||
return listOf(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Apply stash",
|
||||
icon = { painterResource("apply_stash.svg") },
|
||||
onClick = onApply
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Pop stash",
|
||||
icon = { painterResource("apply_stash.svg") },
|
||||
onClick = onPop
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Drop stash",
|
||||
icon = { painterResource("delete.svg") },
|
||||
onClick = onDelete
|
||||
),
|
||||
)
|
||||
|
@ -1,11 +1,9 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.jetpackduba.gitnuro.git.workspace.StatusEntry
|
||||
import com.jetpackduba.gitnuro.git.workspace.StatusType
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun statusEntriesContextMenuItems(
|
||||
statusEntry: StatusEntry,
|
||||
entryType: EntryType,
|
||||
@ -13,26 +11,28 @@ fun statusEntriesContextMenuItems(
|
||||
onDelete: () -> Unit = {},
|
||||
onBlame: () -> Unit,
|
||||
onHistory: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf<ContextMenuItem>().apply {
|
||||
): List<ContextMenuElement> {
|
||||
return mutableListOf<ContextMenuElement>().apply {
|
||||
if (statusEntry.statusType != StatusType.ADDED) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Reset",
|
||||
icon = { painterResource("undo.svg") },
|
||||
onClick = onReset,
|
||||
)
|
||||
)
|
||||
|
||||
if (statusEntry.statusType != StatusType.REMOVED) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Blame file",
|
||||
icon = { painterResource("blame.svg") },
|
||||
onClick = onBlame,
|
||||
)
|
||||
)
|
||||
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "File history",
|
||||
onClick = onHistory,
|
||||
)
|
||||
@ -45,8 +45,9 @@ fun statusEntriesContextMenuItems(
|
||||
statusEntry.statusType != StatusType.REMOVED
|
||||
) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Delete file",
|
||||
icon = { painterResource("delete.svg") },
|
||||
onClick = onDelete,
|
||||
)
|
||||
)
|
||||
|
@ -1,19 +1,16 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import org.eclipse.jgit.submodule.SubmoduleStatus
|
||||
import org.eclipse.jgit.submodule.SubmoduleStatusType
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun submoduleContextMenuItems(
|
||||
submoduleStatus: SubmoduleStatus,
|
||||
onInitializeModule: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf<ContextMenuItem>().apply {
|
||||
): List<ContextMenuElement> {
|
||||
return mutableListOf<ContextMenuElement>().apply {
|
||||
if (submoduleStatus.type == SubmoduleStatusType.UNINITIALIZED) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Initialize submodule",
|
||||
onClick = onInitializeModule
|
||||
)
|
||||
|
@ -1,20 +1,21 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun tagContextMenuItems(
|
||||
onCheckoutTag: () -> Unit,
|
||||
onDeleteTag: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
): List<ContextMenuElement> {
|
||||
return mutableListOf(
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Checkout tag",
|
||||
icon = { painterResource("start.svg") },
|
||||
onClick = onCheckoutTag
|
||||
),
|
||||
ContextMenuItem(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Delete tag",
|
||||
icon = { painterResource("delete.svg") },
|
||||
onClick = onDeleteTag
|
||||
)
|
||||
)
|
||||
|
@ -38,19 +38,14 @@ import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.app.extensions.*
|
||||
import com.jetpackduba.gitnuro.git.workspace.StatusSummary
|
||||
import com.jetpackduba.gitnuro.git.graph.GraphCommitList
|
||||
import com.jetpackduba.gitnuro.git.graph.GraphNode
|
||||
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
||||
import com.jetpackduba.gitnuro.app.theme.*
|
||||
import com.jetpackduba.gitnuro.ui.SelectedItem
|
||||
import com.jetpackduba.gitnuro.ui.components.AvatarImage
|
||||
import com.jetpackduba.gitnuro.ui.components.ScrollableLazyColumn
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.branchContextMenuItems
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.logContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.tagContextMenuItems
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.NewBranchDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.NewTagDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.ResetBranchDialog
|
||||
@ -59,6 +54,7 @@ import com.jetpackduba.gitnuro.viewmodels.LogStatus
|
||||
import com.jetpackduba.gitnuro.viewmodels.LogViewModel
|
||||
import com.jetpackduba.gitnuro.extensions.*
|
||||
import com.jetpackduba.gitnuro.theme.*
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.*
|
||||
import kotlinx.coroutines.launch
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
import org.eclipse.jgit.lib.RepositoryState
|
||||
@ -750,7 +746,7 @@ fun CommitLine(
|
||||
onRevCommitSelected: () -> Unit,
|
||||
onRebaseInteractive: () -> Unit,
|
||||
) {
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = {
|
||||
logContextMenu(
|
||||
onCheckoutCommit = { logViewModel.checkoutCommit(graphNode) },
|
||||
@ -1122,7 +1118,7 @@ fun TagChip(
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun RefChip(
|
||||
modifier: Modifier = Modifier,
|
||||
@ -1130,7 +1126,7 @@ fun RefChip(
|
||||
icon: String,
|
||||
color: Color,
|
||||
onCheckoutRef: () -> Unit,
|
||||
contextMenuItemsList: () -> List<ContextMenuItem>,
|
||||
contextMenuItemsList: () -> List<ContextMenuElement>,
|
||||
endingContent: @Composable () -> Unit = {},
|
||||
) {
|
||||
Box(
|
||||
@ -1141,7 +1137,7 @@ fun RefChip(
|
||||
.combinedClickable(onDoubleClick = onCheckoutRef, onClick = {})
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
) {
|
||||
ContextMenuArea(
|
||||
ContextMenu(
|
||||
items = contextMenuItemsList
|
||||
) {
|
||||
Row(
|
||||
|
1
src/main/resources/blame.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><path d="M7,9H2V7h5V9z M7,12H2v2h5V12z M20.59,19l-3.83-3.83C15.96,15.69,15.02,16,14,16c-2.76,0-5-2.24-5-5s2.24-5,5-5s5,2.24,5,5 c0,1.02-0.31,1.96-0.83,2.75L22,17.59L20.59,19z M17,11c0-1.65-1.35-3-3-3s-3,1.35-3,3s1.35,3,3,3S17,12.65,17,11z M2,19h10v-2H2 V19z"/></g></svg>
|
After Width: | Height: | Size: 455 B |
@ -1,4 +1,7 @@
|
||||
<?xml version="1.0" ?>
|
||||
<svg height="1024" width="640" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M512 192c-70.625 0-128 57.344-128 128 0 47.219 25.875 88.062 64 110.281V448c0 0 0 128-128 128-53.062 0-94.656 11.375-128 28.812V302.28099999999995c38.156-22.219 64-63.062 64-110.281 0-70.656-57.344-128-128-128S0 121.34400000000005 0 192c0 47.219 25.844 88.062 64 110.281V721.75C25.844 743.938 0 784.75 0 832c0 70.625 57.344 128 128 128s128-57.375 128-128c0-33.5-13.188-63.75-34.25-86.625C240.375 722.5 270.656 704 320 704c254 0 256-256 256-256v-17.719c38.125-22.219 64-63.062 64-110.281C640 249.34400000000005 582.625 192 512 192zM128 128c35.406 0 64 28.594 64 64s-28.594 64-64 64-64-28.594-64-64S92.594 128 128 128zM128 896c-35.406 0-64-28.625-64-64 0-35.312 28.594-64 64-64s64 28.688 64 64C192 867.375 163.406 896 128 896zM512 384c-35.375 0-64-28.594-64-64s28.625-64 64-64 64 28.594 64 64S547.375 384 512 384z"/>
|
||||
<svg width="54" height="54" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="14" y1="15" x2="14" y2="40" stroke="black" stroke-width="4"/>
|
||||
<circle cx="14" cy="8" r="6" stroke="black" stroke-width="4"/>
|
||||
<path d="M46 19C46 22.3137 43.3137 25 40 25C36.6863 25 34 22.3137 34 19C34 15.6863 36.6863 13 40 13C43.3137 13 46 15.6863 46 19Z" stroke="black" stroke-width="4"/>
|
||||
<circle cx="14" cy="46" r="6" stroke="black" stroke-width="4"/>
|
||||
<path d="M13.8484 38.636L15.9135 36.8638C18.4322 34.7022 21.6179 33.4731 24.9357 33.3828L31.5028 33.204C35.676 33.0904 39 29.6747 39 25.5V25.5" stroke="black" stroke-width="4"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 924 B After Width: | Height: | Size: 644 B |
@ -1,4 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6m0-2C9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96C18.67 6.59 15.64 4 12 4z"/></svg>
|
Before Width: | Height: | Size: 320 B After Width: | Height: | Size: 480 B |
1
src/main/resources/delete.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z"/></svg>
|
After Width: | Height: | Size: 252 B |
1
src/main/resources/revert.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M14 12c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm-2-9c-4.97 0-9 4.03-9 9H0l4 4 4-4H5c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.51 0-2.91-.49-4.06-1.3l-1.42 1.44C8.04 20.3 9.94 21 12 21c4.97 0 9-4.03 9-9s-4.03-9-9-9z"/></svg>
|
After Width: | Height: | Size: 377 B |
1
src/main/resources/start.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><rect fill="none" height="24" width="24"/><path d="M14.59,7.41L18.17,11H6v2h12.17l-3.59,3.59L16,18l6-6l-6-6L14.59,7.41z M2,6v12h2V6H2z"/></svg>
|
After Width: | Height: | Size: 279 B |
@ -1,4 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58s1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41s-.23-1.06-.59-1.42zM13 20.01L4 11V4h7v-.01l9 9-7 7.02z"/><circle cx="6.5" cy="6.5" r="1.5"/></svg>
|
Before Width: | Height: | Size: 417 B After Width: | Height: | Size: 402 B |
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/><path d="M20,6h-8l-2-2H4C2.9,4,2.01,4.9,2.01,6L2,18c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M14,16H6v-2h8V16z M18,12H6v-2h12V12z"/></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/><path d="M20,6h-8l-2-2H4C2.9,4,2.01,4.9,2.01,6L2,18c0,1.1,0.9,2,2,2h16.77c0.68,0,1.23-0.56,1.23-1.23V8C22,6.9,21.1,6,20,6z M20,18L4,18V6h5.17l2,2H20V18z M18,12H6v-2h12V12z M14,16H6v-2h8V16z"/></g></svg>
|
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 383 B |
1
src/main/resources/undo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z"/></svg>
|
After Width: | Height: | Size: 301 B |