From 27b94165988dd1a1bbbdcfb7a759a57cb7add9c2 Mon Sep 17 00:00:00 2001 From: Abdelilah El Aissaoui Date: Sun, 23 Oct 2022 01:41:04 +0200 Subject: [PATCH] Replaced side bar --- .../com/jetpackduba/gitnuro/ui/AppTab.kt | 33 ++- .../jetpackduba/gitnuro/ui/RepositoryOpen.kt | 226 +++++++----------- .../com/jetpackduba/gitnuro/ui/WelcomePage.kt | 22 +- .../gitnuro/ui/components/ScrollableColumn.kt | 3 +- .../com/jetpackduba/gitnuro/ui/log/Log.kt | 2 +- 5 files changed, 126 insertions(+), 160 deletions(-) diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/AppTab.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/AppTab.kt index f4e4e73..310046e 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/AppTab.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/AppTab.kt @@ -22,8 +22,10 @@ import androidx.compose.ui.unit.sp import com.jetpackduba.gitnuro.LoadingRepository import com.jetpackduba.gitnuro.LocalTabScope import com.jetpackduba.gitnuro.credentials.CredentialsState +import com.jetpackduba.gitnuro.ui.dialogs.CloneDialog import com.jetpackduba.gitnuro.ui.dialogs.PasswordDialog import com.jetpackduba.gitnuro.ui.dialogs.UserPasswordDialog +import com.jetpackduba.gitnuro.ui.dialogs.settings.SettingsDialog import com.jetpackduba.gitnuro.viewmodels.RepositorySelectionStatus import com.jetpackduba.gitnuro.viewmodels.TabViewModel import kotlinx.coroutines.delay @@ -58,11 +60,34 @@ fun AppTab( CredentialsDialog(tabViewModel) + var showSettingsDialog by remember { mutableStateOf(false) } + if (showSettingsDialog) { + SettingsDialog( + onDismiss = { showSettingsDialog = false } + ) + } + + var showCloneDialog by remember { mutableStateOf(false) } + + if (showCloneDialog) { + CloneDialog( + onClose = { + showCloneDialog = false + }, + onOpenRepository = { dir -> + tabViewModel.openRepository(dir) + }, + ) + } + Box(modifier = Modifier.fillMaxSize()) { Crossfade(targetState = repositorySelectionStatus) { when (repositorySelectionStatusValue) { RepositorySelectionStatus.None -> { - WelcomePage(tabViewModel = tabViewModel) + WelcomePage( + tabViewModel = tabViewModel, + onShowCloneDialog = { showSettingsDialog = true } + ) } is RepositorySelectionStatus.Opening -> { @@ -70,7 +95,11 @@ fun AppTab( } is RepositorySelectionStatus.Open -> { - RepositoryOpenPage(tabViewModel = tabViewModel) + RepositoryOpenPage( + tabViewModel = tabViewModel, + onShowSettingsDialog = { showSettingsDialog = true }, + onShowCloneDialog = { showCloneDialog = true }, + ) } } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt index 41785b2..3106285 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt @@ -2,43 +2,35 @@ package com.jetpackduba.gitnuro.ui +import androidx.compose.foundation.ScrollState 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.foundation.rememberScrollState 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.layout.onGloballyPositioned -import androidx.compose.ui.layout.positionInRoot +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow 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.secondarySurface +import com.jetpackduba.gitnuro.theme.onBackgroundSecondary import com.jetpackduba.gitnuro.ui.components.ScrollableColumn import com.jetpackduba.gitnuro.ui.dialogs.* -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 @@ -52,7 +44,11 @@ import org.jetbrains.compose.splitpane.rememberSplitPaneState import java.awt.Cursor @Composable -fun RepositoryOpenPage(tabViewModel: TabViewModel) { +fun RepositoryOpenPage( + tabViewModel: TabViewModel, + onShowSettingsDialog: () -> Unit, + onShowCloneDialog: () -> Unit, +) { val repositoryState by tabViewModel.repositoryState.collectAsState() val diffSelected by tabViewModel.diffSelected.collectAsState() val selectedItem by tabViewModel.selectedItem.collectAsState() @@ -101,7 +97,7 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) { showQuickActionsDialog = false when (it) { QuickActionType.OPEN_DIR_IN_FILE_MANAGER -> tabViewModel.openFolderInFileExplorer() - QuickActionType.CLONE -> TODO() + QuickActionType.CLONE -> onShowCloneDialog() } }, ) @@ -114,8 +110,6 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) { } Column { Row(modifier = Modifier.weight(1f)) { - SideBar(tabViewModel) - Column( modifier = Modifier .focusRequester(focusRequester) @@ -148,7 +142,15 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) { onQuickActions = { showQuickActionsDialog = true } ) - RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState, blameState, showHistory) + RepoContent( + tabViewModel = tabViewModel, + diffSelected = diffSelected, + selectedItem = selectedItem, + repositoryState = repositoryState, + blameState = blameState, + showHistory = showHistory, + onShowSettingsDialog = onShowSettingsDialog + ) } } } @@ -165,51 +167,6 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) { } } -@Composable -fun SideBar(tabViewModel: TabViewModel) { - var showSettingsDialog by remember { mutableStateOf(false) } - if (showSettingsDialog) { - SettingsDialog( - 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) - } - ) - - Spacer(modifier = Modifier.weight(1f)) - - - SideBarButton( - modifier = Modifier.padding(bottom = 16.dp), - painterName = "refresh.svg", - label = "Refresh repository information", - onClick = { - tabViewModel.refreshAll() - } - ) - - SideBarButton( - painterName = "settings.svg", - label = "Settings", - onClick = { showSettingsDialog = true } - ) - } -} - @Composable private fun BottomInfoBar(tabViewModel: TabViewModel) { val userInfo by tabViewModel.authorInfoSimple.collectAsState() @@ -237,70 +194,6 @@ private fun BottomInfoBar(tabViewModel: TabViewModel) { } } -@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 - .clip(RoundedCornerShape(4.dp)) - .background(MaterialTheme.colors.background) - ) { - Text( - 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.onBackground, - ) - } -} - @Composable fun RepoContent( tabViewModel: TabViewModel, @@ -309,6 +202,7 @@ fun RepoContent( repositoryState: RepositoryState, blameState: BlameState, showHistory: Boolean, + onShowSettingsDialog: () -> Unit, ) { if (showHistory) { val historyViewModel = tabViewModel.historyViewModel @@ -328,10 +222,42 @@ fun RepoContent( selectedItem, repositoryState, blameState, + onShowSettingsDialog, ) } +} +@Composable +fun SidePanelOption(title: String, icon: String, onClick: () -> Unit) { + Row( + modifier = Modifier + .height(36.dp) + .fillMaxWidth() + .handMouseClickable(onClick) + .padding(start = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + painter = painterResource(icon), + contentDescription = null, + tint = MaterialTheme.colors.onBackground, + modifier = Modifier + .size(16.dp), + ) + + Text( + text = title, + modifier = Modifier + .padding(horizontal = 8.dp) + .weight(1f), + maxLines = 1, + style = MaterialTheme.typography.body2, + fontWeight = FontWeight.Medium, + color = MaterialTheme.colors.onBackground, + overflow = TextOverflow.Ellipsis, + ) + } } @OptIn(ExperimentalSplitPaneApi::class) @@ -341,18 +267,48 @@ fun MainContentView( diffSelected: DiffEntryType?, selectedItem: SelectedItem, repositoryState: RepositoryState, - blameState: BlameState -) { + blameState: BlameState, + onShowSettingsDialog: () -> Unit, + + ) { HorizontalSplitPane( splitPaneState = rememberSplitPaneState(initialPositionPercentage = 0.20f) ) { first(minSize = 180.dp) { - ScrollableColumn(modifier = Modifier.fillMaxHeight()) { - Branches() - Remotes() - Tags() - Stashes() + Column { + val state: ScrollState = rememberScrollState() + + val canBeScrolled by remember { + derivedStateOf { + state.maxValue > 0 + } + } + + ScrollableColumn( + state = state, + modifier = Modifier + .weight(1f), + ) { + Branches() + Remotes() + Tags() + Stashes() // TODO: Enable on 1.2.0 when fully implemented Submodules() + } + + Column { + if (canBeScrolled) { + Box( + Modifier + .fillMaxWidth() + .height(2.dp) + .background(MaterialTheme.colors.onBackgroundSecondary.copy(alpha = 0.2f)) + ) + } + SidePanelOption("Open repository", "open.svg") { openRepositoryDialog(tabViewModel = tabViewModel) } + SidePanelOption("Refresh", "refresh.svg") { tabViewModel.refreshAll() } + SidePanelOption("Settings", "settings.svg", onShowSettingsDialog) + } } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt index e1f4f33..27c5962 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt @@ -31,13 +31,12 @@ import com.jetpackduba.gitnuro.updates.Update import com.jetpackduba.gitnuro.viewmodels.TabViewModel -@OptIn(ExperimentalMaterialApi::class) @Composable fun WelcomePage( tabViewModel: TabViewModel, + onShowCloneDialog: () -> Unit, ) { val appStateManager = tabViewModel.appStateManager - var showCloneView by remember { mutableStateOf(false) } var showAdditionalInfo by remember { mutableStateOf(false) } var newUpdate by remember { mutableStateOf(null) } @@ -62,7 +61,7 @@ fun WelcomePage( HomeButtons( newUpdate = newUpdate, tabViewModel = tabViewModel, - onShowCloneView = { showCloneView = true }, + onShowCloneView = onShowCloneDialog, onShowAdditionalInfo = { showAdditionalInfo = true }, ) @@ -79,24 +78,7 @@ fun WelcomePage( ) } - LaunchedEffect(showCloneView) { - if (showCloneView) { -// tabViewModel.cloneViewModel.reset() // Reset dialog before showing it - } - } - if (showCloneView) { - CloneDialog( -// tabViewModel.cloneViewModel, - onClose = { - showCloneView = false -// tabViewModel.cloneViewModel.reset() - }, - onOpenRepository = { dir -> - tabViewModel.openRepository(dir) - }, - ) - } if (showAdditionalInfo) { AppInfoDialog( diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/ScrollableColumn.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/ScrollableColumn.kt index 62e3267..5d23235 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/ScrollableColumn.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/ScrollableColumn.kt @@ -13,10 +13,9 @@ import com.jetpackduba.gitnuro.theme.scrollbarNormal @Composable fun ScrollableColumn( modifier: Modifier, - state: ScrollState = rememberScrollState(0), + state: ScrollState = rememberScrollState(), content: @Composable ColumnScope.() -> Unit ) { - Box( modifier = modifier, ) { 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 a01104f..9ef2309 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt @@ -116,7 +116,7 @@ fun Log( // the proper scroll position verticalScrollState.observeScrollChanges() - LaunchedEffect(verticalScrollState) { + LaunchedEffect(verticalScrollState, commitList) { launch { logViewModel.focusCommit.collect { commit -> scrollToCommit(verticalScrollState, commitList, commit)