From 2ffb8d9038db0a9e4f5ebb8cc9b1604437daef75 Mon Sep 17 00:00:00 2001 From: Abdelilah El Aissaoui Date: Wed, 5 Oct 2022 18:55:53 +0200 Subject: [PATCH] Added new side bar --- .../kotlin/com/jetpackduba/gitnuro/App.kt | 45 +--- .../jetpackduba/gitnuro/di/AppComponent.kt | 2 + .../gitnuro/extensions/ModifierExtensions.kt | 8 +- .../com/jetpackduba/gitnuro/theme/Color.kt | 8 +- .../com/jetpackduba/gitnuro/ui/Blame.kt | 5 +- .../com/jetpackduba/gitnuro/ui/FileHistory.kt | 3 +- .../kotlin/com/jetpackduba/gitnuro/ui/Menu.kt | 78 +++--- .../com/jetpackduba/gitnuro/ui/Remotes.kt | 4 +- .../jetpackduba/gitnuro/ui/RepositoryOpen.kt | 223 ++++++++++++++---- .../ui/components/RepositoriesTabPanel.kt | 3 +- .../RepositoryAdditionalOptionsMenu.kt | 6 - .../gitnuro/ui/dialogs/EditRemotesDialog.kt | 8 +- .../com/jetpackduba/gitnuro/ui/diff/Diff.kt | 6 +- .../com/jetpackduba/gitnuro/ui/log/Log.kt | 10 +- .../gitnuro/viewmodels/MenuViewModel.kt | 6 - .../gitnuro/viewmodels/TabViewModel.kt | 1 + src/main/resources/settings.svg | 8 +- 17 files changed, 252 insertions(+), 172 deletions(-) diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/App.kt b/src/main/kotlin/com/jetpackduba/gitnuro/App.kt index 8847779..1859ab9 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/App.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/App.kt @@ -4,16 +4,12 @@ package com.jetpackduba.gitnuro import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.material.Icon -import androidx.compose.material.IconButton 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.input.pointer.PointerIconDefaults -import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.Density @@ -35,8 +31,6 @@ import com.jetpackduba.gitnuro.theme.secondaryTextColor import com.jetpackduba.gitnuro.ui.AppTab import com.jetpackduba.gitnuro.ui.components.RepositoriesTabPanel import com.jetpackduba.gitnuro.ui.components.TabInformation -import com.jetpackduba.gitnuro.ui.dialogs.settings.SettingsDialog -import com.jetpackduba.gitnuro.viewmodels.SettingsViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch @@ -53,9 +47,6 @@ class App { @Inject lateinit var appSettings: AppSettings - @Inject - lateinit var settingsViewModel: SettingsViewModel - init { appComponent.inject(this) } @@ -107,25 +98,12 @@ class App { emptyArray() CompositionLocalProvider(values = density) { - var showSettingsDialog by remember { mutableStateOf(false) } - AppTheme( selectedTheme = theme, customTheme = customTheme, ) { Box(modifier = Modifier.background(MaterialTheme.colors.background)) { - AppTabs( - onOpenSettings = { - showSettingsDialog = true - } - ) - } - - if (showSettingsDialog) { - SettingsDialog( - settingsViewModel = settingsViewModel, - onDismiss = { showSettingsDialog = false } - ) + AppTabs() } } } @@ -160,9 +138,7 @@ class App { @Composable - fun AppTabs( - onOpenSettings: () -> Unit, - ) { + fun AppTabs() { val tabs by tabsFlow.collectAsState() val tabsInformationList = tabs.sortedBy { it.key } val selectedTabKey = remember { mutableStateOf(0) } @@ -173,7 +149,6 @@ class App { Tabs( tabsInformationList = tabsInformationList, selectedTabKey = selectedTabKey, - onOpenSettings = onOpenSettings, onAddedTab = { tabInfo -> addTab(tabInfo) }, @@ -203,11 +178,9 @@ class App { tabsFlow.value = tabsFlow.value.toMutableList().apply { add(tabInformation) } } - @OptIn(ExperimentalComposeUiApi::class) @Composable fun Tabs( selectedTabKey: MutableState, - onOpenSettings: () -> Unit, tabsInformationList: List, onAddedTab: (TabInformation) -> Unit, onRemoveTab: (Int) -> Unit, @@ -237,20 +210,6 @@ class App { }, onTabClosed = onRemoveTab ) - IconButton( - modifier = Modifier - .padding(horizontal = 8.dp) - .size(24.dp) - .pointerHoverIcon(PointerIconDefaults.Hand), - onClick = onOpenSettings - ) { - Icon( - painter = painterResource("settings.svg"), - contentDescription = null, - modifier = Modifier.fillMaxSize(), - tint = MaterialTheme.colors.primaryVariant, - ) - } } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/di/AppComponent.kt b/src/main/kotlin/com/jetpackduba/gitnuro/di/AppComponent.kt index 89d009c..64b4cfe 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/di/AppComponent.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/di/AppComponent.kt @@ -3,6 +3,7 @@ package com.jetpackduba.gitnuro.di import com.jetpackduba.gitnuro.App import com.jetpackduba.gitnuro.AppStateManager import com.jetpackduba.gitnuro.preferences.AppSettings +import com.jetpackduba.gitnuro.viewmodels.SettingsViewModel import dagger.Component import javax.inject.Singleton @@ -11,6 +12,7 @@ import javax.inject.Singleton interface AppComponent { fun inject(main: App) fun appStateManager(): AppStateManager + fun settingsViewModel(): SettingsViewModel fun appPreferences(): AppSettings } \ No newline at end of file diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/extensions/ModifierExtensions.kt b/src/main/kotlin/com/jetpackduba/gitnuro/extensions/ModifierExtensions.kt index c0bec1f..8bb732d 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/extensions/ModifierExtensions.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/extensions/ModifierExtensions.kt @@ -17,11 +17,10 @@ fun Modifier.backgroundIf(condition: Boolean, color: Color): Modifier { } } -@OptIn(ExperimentalComposeUiApi::class) fun Modifier.handMouseClickable(onClick: () -> Unit): Modifier { return this .clickable { onClick() } - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() } /** @@ -30,4 +29,9 @@ fun Modifier.handMouseClickable(onClick: () -> Unit): Modifier { */ fun Modifier.ignoreKeyEvents(): Modifier { return this.onPreviewKeyEvent { true } +} + +@OptIn(ExperimentalComposeUiApi::class) +fun Modifier.handOnHover(): Modifier { + return this.pointerHoverIcon(PointerIconDefaults.Hand) } \ No newline at end of file diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/theme/Color.kt b/src/main/kotlin/com/jetpackduba/gitnuro/theme/Color.kt index 1526ff6..d8b75b9 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/theme/Color.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/theme/Color.kt @@ -31,7 +31,7 @@ val lightTheme = ColorsScheme( val darkBlueTheme = ColorsScheme( - primary = Color(0xFF014F97), + primary = Color(0xFF1074BC), primaryVariant = Color(0xFF9FD1FF), onPrimary = Color(0xFFFFFFFFF), secondary = Color(0xFFe9c754), @@ -39,10 +39,10 @@ val darkBlueTheme = ColorsScheme( secondaryText = Color(0xFFCCCBCB), error = Color(0xFFc93838), onError = Color(0xFFFFFFFF), - background = Color(0xFF0E1621), + background = Color(0xFF16181F), backgroundSelected = Color(0xFF2f3640), - surface = Color(0xFF15212d), - secondarySurface = Color(0xFF1a2c40), + surface = Color(0xFF202538), + secondarySurface = Color(0xFF122C46), headerBackground = Color(0xFF0a335c), borderColor = Color(0xFF989898), addFile = Color(0xFF32A852), diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/Blame.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/Blame.kt index 307ba29..4c67b4d 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/Blame.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/Blame.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import com.jetpackduba.gitnuro.extensions.handMouseClickable +import com.jetpackduba.gitnuro.extensions.handOnHover import com.jetpackduba.gitnuro.extensions.lineAt import com.jetpackduba.gitnuro.extensions.toStringWithSpaces import com.jetpackduba.gitnuro.keybindings.KeybindingOption @@ -187,7 +188,7 @@ fun MinimizedBlame( onClick = onClose, modifier = Modifier .padding(horizontal = 16.dp) - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() ) { Image( painter = painterResource("close.svg"), @@ -222,7 +223,7 @@ private fun Header( IconButton( onClick = onClose, modifier = Modifier - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() ) { Image( painter = painterResource("close.svg"), diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/FileHistory.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/FileHistory.kt index 6e1b8d8..4fe16a1 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/FileHistory.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/FileHistory.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.jetpackduba.gitnuro.extensions.handMouseClickable +import com.jetpackduba.gitnuro.extensions.handOnHover import com.jetpackduba.gitnuro.extensions.toSmartSystemString import com.jetpackduba.gitnuro.git.diff.DiffResult import com.jetpackduba.gitnuro.keybindings.KeybindingOption @@ -102,7 +103,7 @@ private fun Header( IconButton( onClick = onClose, modifier = Modifier - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() ) { Image( painter = painterResource("close.svg"), diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt index 734330c..f316360 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown @@ -13,6 +14,8 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.painter.Painter @@ -22,6 +25,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.jetpackduba.gitnuro.extensions.handMouseClickable +import com.jetpackduba.gitnuro.extensions.handOnHover import com.jetpackduba.gitnuro.extensions.ignoreKeyEvents import com.jetpackduba.gitnuro.theme.primaryTextColor import com.jetpackduba.gitnuro.ui.context_menu.* @@ -32,7 +36,6 @@ import com.jetpackduba.gitnuro.viewmodels.MenuViewModel fun Menu( modifier: Modifier, menuViewModel: MenuViewModel, - onRepositoryOpen: () -> Unit, onCreateBranch: () -> Unit, onStashWithMessage: () -> Unit, ) { @@ -43,15 +46,6 @@ fun Menu( horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, ) { - MenuButton( - modifier = Modifier.padding(start = 8.dp), - title = "Open", - icon = painterResource("open.svg"), - onClick = { - onRepositoryOpen() - } - ) - Spacer(modifier = Modifier.weight(1f)) ExtendedMenuButton( @@ -129,7 +123,6 @@ fun Menu( val menuOptions = remember { repositoryAdditionalOptionsMenu( onOpenRepositoryOnFileExplorer = { menuViewModel.openFolderInFileExplorer() }, - onForceRepositoryRefresh = { menuViewModel.refresh() }, ) } for (item in menuOptions) { @@ -153,34 +146,31 @@ fun MenuButton( icon: Painter, onClick: () -> Unit ) { - val iconColor = if (enabled) { - MaterialTheme.colors.primaryVariant - } else { - MaterialTheme.colors.secondaryVariant //todo this color isn't specified anywhere - } - - Column( + Row( modifier = modifier .ignoreKeyEvents() + .clip(RoundedCornerShape(4.dp)) + .background(MaterialTheme.colors.primary) .handMouseClickable { if (enabled) onClick() } - .padding(vertical = 4.dp, horizontal = 16.dp) - .width(48.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, + .width(100.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, ) { - Image( + Icon( painter = icon, contentDescription = title, modifier = Modifier .padding(vertical = 2.dp) .size(24.dp), - colorFilter = ColorFilter.tint(iconColor), + tint = MaterialTheme.colors.onPrimary, ) Text( text = title, style = MaterialTheme.typography.body2, + modifier = Modifier.padding(start = 2.dp, top = 8.dp, bottom = 8.dp), maxLines = 1, textAlign = TextAlign.Center, + color = MaterialTheme.colors.onPrimary, ) } } @@ -194,44 +184,40 @@ fun ExtendedMenuButton( onClick: () -> Unit, extendedListItems: List, ) { - val iconColor = if (enabled) { - MaterialTheme.colors.primaryVariant - } else { - MaterialTheme.colors.secondaryVariant - } - var showDropDownMenu by remember { mutableStateOf(false) } Row( modifier = modifier .height(IntrinsicSize.Min) .ignoreKeyEvents() - .handMouseClickable { if (enabled) onClick() } + .clip(RoundedCornerShape(4.dp)) + .background(MaterialTheme.colors.primary) ) { - Column( + Row( modifier = Modifier - .padding(top = 4.dp, bottom = 4.dp, start = 16.dp, end = 4.dp) - .width(40.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, + .width(92.dp) + .handMouseClickable { if (enabled) onClick() }, + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, ) { - Image( + Icon( painter = icon, contentDescription = title, modifier = Modifier - .padding(vertical = 2.dp) .size(24.dp), - colorFilter = ColorFilter.tint(iconColor), + tint = MaterialTheme.colors.onPrimary, ) Text( text = title, + modifier = Modifier.padding(start = 2.dp, top = 8.dp, bottom = 8.dp), style = MaterialTheme.typography.body2, + color = MaterialTheme.colors.onPrimary, ) } Box( modifier = Modifier - .width(20.dp) + .width(24.dp) .fillMaxHeight() .ignoreKeyEvents() .handMouseClickable { @@ -239,10 +225,18 @@ fun ExtendedMenuButton( }, contentAlignment = Alignment.Center, ) { + Box( + modifier = Modifier + .fillMaxHeight() + .background(MaterialTheme.colors.onPrimary.copy(alpha = 0.5f)) + .width(1.dp) + .align(Alignment.CenterStart) + ) + Icon( Icons.Default.ArrowDropDown, contentDescription = null, - tint = MaterialTheme.colors.primaryTextColor, + tint = MaterialTheme.colors.onPrimary, ) DropdownMenu( @@ -275,7 +269,7 @@ fun IconMenuButton( IconButton( modifier = modifier - .pointerHoverIcon(PointerIconDefaults.Hand), + .handOnHover(), enabled = enabled, onClick = onClick, ) { diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/Remotes.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/Remotes.kt index 23e4857..9ea8c0a 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/Remotes.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/Remotes.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.input.pointer.PointerIconDefaults import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp +import com.jetpackduba.gitnuro.extensions.handOnHover import com.jetpackduba.gitnuro.extensions.simpleName import com.jetpackduba.gitnuro.theme.primaryTextColor import com.jetpackduba.gitnuro.ui.components.SideMenuPanel @@ -29,7 +30,6 @@ 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, @@ -62,7 +62,7 @@ fun Remotes( modifier = Modifier .padding(end = 16.dp) .size(16.dp) - .pointerHoverIcon(PointerIconDefaults.Hand), + .handOnHover(), ) { Icon( painter = painterResource("settings.svg"), diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt index 54cd53c..aded278 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt @@ -4,27 +4,44 @@ package com.jetpackduba.gitnuro.ui 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.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment 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.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.input.pointer.PointerIcon import androidx.compose.ui.input.pointer.pointerHoverIcon -import androidx.compose.ui.unit.dp +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.positionInRoot +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.* +import androidx.compose.ui.window.Popup +import androidx.compose.ui.window.PopupPositionProvider import com.jetpackduba.gitnuro.extensions.handMouseClickable +import com.jetpackduba.gitnuro.extensions.handOnHover import com.jetpackduba.gitnuro.git.DiffEntryType import com.jetpackduba.gitnuro.keybindings.KeybindingOption import com.jetpackduba.gitnuro.keybindings.matchesBinding +import com.jetpackduba.gitnuro.theme.primaryTextColor +import com.jetpackduba.gitnuro.theme.secondarySurface import com.jetpackduba.gitnuro.ui.components.ScrollableColumn import com.jetpackduba.gitnuro.ui.dialogs.AuthorDialog import com.jetpackduba.gitnuro.ui.dialogs.NewBranchDialog import com.jetpackduba.gitnuro.ui.dialogs.StashWithMessageDialog +import com.jetpackduba.gitnuro.ui.dialogs.settings.SettingsDialog import com.jetpackduba.gitnuro.ui.diff.Diff import com.jetpackduba.gitnuro.ui.log.Log import com.jetpackduba.gitnuro.viewmodels.BlameState @@ -44,7 +61,6 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) { val selectedItem by tabViewModel.selectedItem.collectAsState() val blameState by tabViewModel.blameState.collectAsState() val showHistory by tabViewModel.showHistory.collectAsState() - val userInfo by tabViewModel.authorInfoSimple.collectAsState() val showAuthorInfo by tabViewModel.showAuthorInfo.collectAsState() var showNewBranchDialog by remember { mutableStateOf(false) } @@ -87,40 +103,45 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) { LaunchedEffect(selectedItem) { focusRequester.requestFocus() } + Column { + Row(modifier = Modifier.weight(1f)) { + SideBar(tabViewModel) - Column( - modifier = Modifier - .focusRequester(focusRequester) - .focusable() - .onKeyEvent { keyEvent -> - if (keyEvent.matchesBinding(KeybindingOption.REFRESH)) { - tabViewModel.refreshAll() - true + Column( + modifier = Modifier + .focusRequester(focusRequester) + .focusable() + .onKeyEvent { keyEvent -> + if (keyEvent.matchesBinding(KeybindingOption.REFRESH)) { + tabViewModel.refreshAll() + true + } else { + false + } + } + ) { + val rebaseInteractiveViewModel = tabViewModel.rebaseInteractiveViewModel + + if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) { + RebaseInteractive(rebaseInteractiveViewModel) } else { - false + Column(modifier = Modifier.weight(1f)) { + Menu( + modifier = Modifier + .padding( + top = 12.dp, + bottom = 16.dp + ) // Linear progress bar already take 4 additional dp for top + .fillMaxWidth(), + menuViewModel = tabViewModel.menuViewModel, + onCreateBranch = { showNewBranchDialog = true }, + onStashWithMessage = { showStashWithMessageDialog = true }, + ) + + RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState, blameState, showHistory) + } } } - ) { - val rebaseInteractiveViewModel = tabViewModel.rebaseInteractiveViewModel - - if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) { - RebaseInteractive(rebaseInteractiveViewModel) - } else { - Column(modifier = Modifier.weight(1f)) { - Menu( - modifier = Modifier - .padding(top = 4.dp, bottom = 8.dp) // Linear progress bar already take 4 additional dp for top - .fillMaxWidth(), - menuViewModel = tabViewModel.menuViewModel, - onRepositoryOpen = { - openRepositoryDialog(tabViewModel = tabViewModel) - }, - onCreateBranch = { showNewBranchDialog = true }, - onStashWithMessage = { showStashWithMessageDialog = true }, - ) - - RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState, blameState, showHistory) - } } Spacer( @@ -129,27 +150,142 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) { .fillMaxWidth() .background(MaterialTheme.colors.primaryVariant.copy(alpha = 0.2f)) ) - Row( + + BottomInfoBar(tabViewModel) + } +} + +@Composable +fun SideBar(tabViewModel: TabViewModel) { + var showSettingsDialog by remember { mutableStateOf(false) } + if (showSettingsDialog) { + SettingsDialog( + settingsViewModel = tabViewModel.settingsViewModel, + onDismiss = { showSettingsDialog = false } + ) + } + + Column( + modifier = Modifier + .fillMaxHeight() + .width(48.dp) + .background(MaterialTheme.colors.secondarySurface) + .padding(vertical = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + SideBarButton( + painterName = "open.svg", + label = "Open a new repository", + onClick = { + openRepositoryDialog(tabViewModel = tabViewModel) + } + ) + SideBarButton( + modifier = Modifier.padding(top = 16.dp), + painterName = "refresh.svg", + label = "Refresh repository information", + onClick = { + tabViewModel.refreshAll() + } + ) + + Spacer(modifier = Modifier.weight(1f)) + + SideBarButton( + painterName = "settings.svg", + label = "Settings", + onClick = { showSettingsDialog = true } + ) + } +} + +@Composable +private fun BottomInfoBar(tabViewModel: TabViewModel) { + val userInfo by tabViewModel.authorInfoSimple.collectAsState() + + Row( + modifier = Modifier + .fillMaxWidth() + .height(32.dp) + .background(MaterialTheme.colors.surface) + .padding(horizontal = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Box( modifier = Modifier - .fillMaxWidth() - .height(32.dp) - .background(MaterialTheme.colors.surface) - .padding(horizontal = 16.dp), - verticalAlignment = Alignment.CenterVertically, + .fillMaxHeight() + .handMouseClickable { tabViewModel.showAuthorInfoDialog() }, + contentAlignment = Alignment.Center, + ) { + Text( + text = "${userInfo.name ?: "Name not set"} <${userInfo.email ?: "Email not set"}>", + style = MaterialTheme.typography.body2, + ) + } + } +} + +@Composable +fun SideBarButton( + modifier: Modifier = Modifier, + painterName: String, + label: String, + onClick: () -> Unit +) { + val hoverInteraction = remember { MutableInteractionSource() } + val isHovered by hoverInteraction.collectIsHoveredAsState() + + val (buttonCoordinates, setButtonCoordinates) = remember { mutableStateOf?>(null) } + + if (isHovered && buttonCoordinates != null) { + Popup( + popupPositionProvider = object : PopupPositionProvider { + override fun calculatePosition( + anchorBounds: IntRect, + windowSize: IntSize, + layoutDirection: LayoutDirection, + popupContentSize: IntSize + ): IntOffset { + val position = buttonCoordinates.first + val size = buttonCoordinates.second + val x = position.x + size.width + 8 + val y = position.y + (size.height / 2) - (popupContentSize.height / 2) + + return IntOffset(x.toInt(), y.toInt()) + } + + } ) { Box( modifier = Modifier - .fillMaxHeight() - .handMouseClickable { tabViewModel.showAuthorInfoDialog() }, - contentAlignment = Alignment.Center, + .clip(RoundedCornerShape(4.dp)) + .background(MaterialTheme.colors.background) ) { Text( - text = "${userInfo.name ?: "Name not set"} <${userInfo.email ?: "Email not set"}>", - style = MaterialTheme.typography.body2, + text = label, + color = MaterialTheme.colors.onBackground, + modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp) ) } } + } + IconButton( + onClick = onClick, + modifier = modifier + .handOnHover() + .hoverable(hoverInteraction) + .size(24.dp) + .onGloballyPositioned { layoutCoordinates -> + setButtonCoordinates(layoutCoordinates.positionInRoot() to layoutCoordinates.size) + } + ) { + Icon( + painter = painterResource(painterName), + contentDescription = null, + modifier = Modifier, + tint = MaterialTheme.colors.primaryTextColor, + ) } } @@ -246,6 +382,7 @@ fun MainContentView( repositoryState = repositoryState, ) } + else -> { val diffViewModel = tabViewModel.diffViewModel diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/RepositoriesTabPanel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/RepositoriesTabPanel.kt index f713d0c..8d6f2e1 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/RepositoriesTabPanel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/RepositoriesTabPanel.kt @@ -29,6 +29,7 @@ import com.jetpackduba.gitnuro.AppStateManager import com.jetpackduba.gitnuro.di.AppComponent import com.jetpackduba.gitnuro.di.DaggerTabComponent import com.jetpackduba.gitnuro.extensions.handMouseClickable +import com.jetpackduba.gitnuro.extensions.handOnHover import com.jetpackduba.gitnuro.theme.primaryTextColor import com.jetpackduba.gitnuro.viewmodels.TabViewModel import javax.inject.Inject @@ -117,7 +118,7 @@ fun TabPanel( onClick = onNewTabClicked, modifier = Modifier .size(36.dp) - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() .align(Alignment.CenterStart), ) { Icon( diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/RepositoryAdditionalOptionsMenu.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/RepositoryAdditionalOptionsMenu.kt index dd837a3..bae4795 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/RepositoryAdditionalOptionsMenu.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/RepositoryAdditionalOptionsMenu.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi @OptIn(ExperimentalFoundationApi::class) fun repositoryAdditionalOptionsMenu( onOpenRepositoryOnFileExplorer: () -> Unit, - onForceRepositoryRefresh: () -> Unit, ): List { return mutableListOf( DropDownContentData( @@ -13,10 +12,5 @@ fun repositoryAdditionalOptionsMenu( icon = "source.svg", onClick = onOpenRepositoryOnFileExplorer, ), - DropDownContentData( - label = "Refresh repository", - icon = "refresh.svg", - onClick = onForceRepositoryRefresh, - ), ) } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/dialogs/EditRemotesDialog.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/dialogs/EditRemotesDialog.kt index 3d33190..a1d60db 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/dialogs/EditRemotesDialog.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/dialogs/EditRemotesDialog.kt @@ -16,13 +16,13 @@ import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.jetpackduba.gitnuro.extensions.handMouseClickable +import com.jetpackduba.gitnuro.extensions.handOnHover import com.jetpackduba.gitnuro.theme.* import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField import com.jetpackduba.gitnuro.ui.components.PrimaryButton import com.jetpackduba.gitnuro.viewmodels.RemotesViewModel import org.eclipse.jgit.transport.RemoteConfig -@OptIn(ExperimentalComposeUiApi::class) @Composable fun EditRemotesDialog( remotesViewModel: RemotesViewModel, @@ -90,7 +90,7 @@ fun EditRemotesDialog( IconButton( onClick = onDismiss, modifier = Modifier - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() ) { Icon( imageVector = Icons.Default.Clear, @@ -153,7 +153,7 @@ fun EditRemotesDialog( IconButton( modifier = Modifier .size(36.dp) - .pointerHoverIcon(PointerIconDefaults.Hand), + .handOnHover(), onClick = { val remotesWithNew = remotesEditorData.listRemotes.toMutableList() val newRemote = RemoteWrapper( @@ -182,7 +182,7 @@ fun EditRemotesDialog( IconButton( modifier = Modifier .size(36.dp) - .pointerHoverIcon(PointerIconDefaults.Hand), + .handOnHover(), enabled = selectedRemote != null, onClick = { if (selectedRemote != null) diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/diff/Diff.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/diff/Diff.kt index 61501fc..47543f4 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/diff/Diff.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/diff/Diff.kt @@ -550,7 +550,6 @@ fun HunkHeader( } } -@OptIn(ExperimentalComposeUiApi::class) @Composable private fun DiffHeader( diffEntryType: DiffEntryType, @@ -598,7 +597,7 @@ private fun DiffHeader( IconButton( onClick = onCloseDiffView, modifier = Modifier - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() ) { Image( painter = painterResource("close.svg"), @@ -677,7 +676,6 @@ fun UncommitedDiffFileHeaderButtons( ) } -@OptIn(ExperimentalComposeUiApi::class) @Composable private fun PathOnlyDiffHeader( filePath: String, @@ -703,7 +701,7 @@ private fun PathOnlyDiffHeader( IconButton( onClick = onCloseDiffView, modifier = Modifier - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() ) { Image( painter = painterResource("close.svg"), diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt index bf29ece..4c90478 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt @@ -333,7 +333,7 @@ fun SearchFilter( IconButton( modifier = Modifier - .pointerHoverIcon(PointerIconDefaults.Hand), + .handOnHover(), onClick = { scope.launch { logViewModel.selectPreviousFilterCommit() } } @@ -343,7 +343,7 @@ fun SearchFilter( IconButton( modifier = Modifier - .pointerHoverIcon(PointerIconDefaults.Hand), + .handOnHover(), onClick = { scope.launch { logViewModel.selectNextFilterCommit() } } @@ -353,7 +353,7 @@ fun SearchFilter( IconButton( modifier = Modifier - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() .padding(end = 4.dp), onClick = { logViewModel.closeSearch() } ) { @@ -613,7 +613,7 @@ fun GraphHeader( IconButton( modifier = Modifier .padding(end = 8.dp) - .pointerHoverIcon(PointerIconDefaults.Hand), + .handOnHover(), onClick = onShowSearch ) { Icon( @@ -1135,7 +1135,7 @@ fun RefChip( .clip(RoundedCornerShape(16.dp)) .border(width = 2.dp, color = color, shape = RoundedCornerShape(16.dp)) .combinedClickable(onDoubleClick = onCheckoutRef, onClick = {}) - .pointerHoverIcon(PointerIconDefaults.Hand) + .handOnHover() ) { ContextMenu( items = contextMenuItemsList diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/MenuViewModel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/MenuViewModel.kt index c8e0c76..8a02cb2 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/MenuViewModel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/MenuViewModel.kt @@ -68,10 +68,4 @@ class MenuViewModel @Inject constructor( ) { git -> Desktop.getDesktop().open(git.repository.directory.parentFile) } - - fun refresh() = tabState.safeProcessing( - refreshType = RefreshType.ALL_DATA, - ) { - // Nothing to do here - } } \ No newline at end of file diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt index a426d2c..eee0a54 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt @@ -55,6 +55,7 @@ class TabViewModel @Inject constructor( private val authorViewModelProvider: Provider, private val tabState: TabState, val appStateManager: AppStateManager, + val settingsViewModel: SettingsViewModel, private val fileChangesWatcher: FileChangesWatcher, private val updatesRepository: UpdatesRepository, ) { diff --git a/src/main/resources/settings.svg b/src/main/resources/settings.svg index b6e0b4b..4165162 100644 --- a/src/main/resources/settings.svg +++ b/src/main/resources/settings.svg @@ -1,7 +1 @@ - - - - - - \ No newline at end of file + \ No newline at end of file