diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt index 4013e26a..d24467c2 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt @@ -7,12 +7,14 @@ import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory import com.jetbrains.packagesearch.plugin.ui.LocalComponentManager import com.jetbrains.packagesearch.plugin.ui.PackageSearchToolwindow -import com.jetbrains.packagesearch.plugin.ui.panels.packages.packageSearchGlobalColors -import com.jetbrains.packagesearch.plugin.ui.panels.packages.packageSearchTabStyle +import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchTabStyle +import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchTreeStyle +import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchGlobalColors import com.jetbrains.packagesearch.plugin.utils.installActions import org.jetbrains.jewel.bridge.addComposeTab import org.jetbrains.jewel.foundation.LocalGlobalColors import org.jetbrains.jewel.ui.component.styling.LocalDefaultTabStyle +import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle class PackageSearchToolWindowFactory : ToolWindowFactory, DumbAware { override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { @@ -20,8 +22,9 @@ class PackageSearchToolWindowFactory : ToolWindowFactory, DumbAware { toolWindow.addComposeTab(PackageSearchBundle.message("packagesearch.title.tab")) { CompositionLocalProvider( LocalComponentManager provides project, - LocalGlobalColors provides packageSearchGlobalColors(), - LocalDefaultTabStyle provides packageSearchTabStyle() + LocalGlobalColors provides PackageSearchGlobalColors(), + LocalDefaultTabStyle provides PackageSearchTabStyle(), + LocalLazyTreeStyle provides PackageSearchTreeStyle() ) { PackageSearchToolwindow() } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt index 3ae971c9..66d65787 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt @@ -1,10 +1,24 @@ package com.jetbrains.packagesearch.plugin.ui import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import org.jetbrains.jewel.foundation.theme.JewelTheme +import org.jetbrains.jewel.ui.theme.scrollbarStyle object PackageSearchMetrics { + + val scrollbarWidth: Dp + @Composable + get() { + val metrics = JewelTheme.scrollbarStyle.metrics + return metrics.thumbThickness + + metrics.trackPadding.calculateEndPadding(LocalLayoutDirection.current) + } + object Popups { val minWidth: Dp = 50.dp @@ -14,9 +28,9 @@ object PackageSearchMetrics { val maxHeight: Dp = 250.dp } - object PackageList{ - object Item{ - val height= 24.dp + object PackageList { + object Item { + val height = 24.dp val padding = 8.dp } } @@ -24,7 +38,7 @@ object PackageSearchMetrics { val searchBarHeight = 36.dp val treeActionsHeight = searchBarHeight - object Dropdown{ + object Dropdown { val maxHeight = 100.dp } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt index 7b7165c2..871f01f2 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt @@ -1,15 +1,12 @@ package com.jetbrains.packagesearch.plugin.ui import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule -import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchCentralPanel import com.jetbrains.packagesearch.plugin.ui.panels.side.PackageSearchInfoPanel import com.jetbrains.packagesearch.plugin.ui.panels.tree.PackageSearchModulesTree -import org.jetbrains.jewel.foundation.lazy.SelectableLazyListState import org.jetbrains.jewel.ui.component.HorizontalSplitLayout @Composable @@ -17,7 +14,7 @@ fun PackageSearchPackagePanel( onSelectionModulesSelectionChanged: (Set) -> Unit, isInfoPanelOpen: Boolean, onLinkClick: (String) -> Unit, - onPackageEvent:(PackageListItemEvent) -> Unit, + onPackageEvent: (PackageListItemEvent) -> Unit, ) { HorizontalSplitLayout( first = { PackageSearchModulesTree(it, onSelectionModulesSelectionChanged) }, @@ -25,12 +22,13 @@ fun PackageSearchPackagePanel( if (isInfoPanelOpen) { HorizontalSplitLayout( modifier = it, - initialDividerPosition = 700.dp, + initialDividerPosition = 900.dp, first = { PackageSearchCentralPanel(it, onLinkClick) }, - second = { PackageSearchInfoPanel(it, onLinkClick, onPackageEvent) } + second = { PackageSearchInfoPanel(it, onLinkClick, onPackageEvent) }, + maxRatio = 0.8f ) } else PackageSearchCentralPanel(it, onLinkClick) - } + }, + minRatio = 0.1f, ) } - diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt index b1815893..c07d5ec4 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt @@ -31,7 +31,8 @@ internal class TreeViewModel( } .stateIn(viewModelScope, SharingStarted.Lazily, emptyTree()) - val treeState = TreeState(SelectableLazyListState(LazyListState())) + internal val lazyListState = LazyListState() + internal val treeState = TreeState(SelectableLazyListState(lazyListState)) val isOnline get() = IntelliJApplication.PackageSearchApplicationCachesService diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt index fbd9ee59..2493715e 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt @@ -2,16 +2,20 @@ package com.jetbrains.packagesearch.plugin.ui.panels.packages import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListViewModel import com.jetbrains.packagesearch.plugin.ui.viewModel import org.jetbrains.jewel.ui.Orientation import org.jetbrains.jewel.ui.component.Divider import org.jetbrains.jewel.ui.component.IndeterminateHorizontalProgressBar +import org.jetbrains.jewel.ui.component.VerticalScrollbar @Composable fun PackageSearchCentralPanel( @@ -39,6 +43,10 @@ fun PackageSearchCentralPanel( selectableLazyListState = viewModel.selectableLazyListState, onPackageEvent = viewModel::onPackageListItemEvent, ) + VerticalScrollbar( + adapter = rememberScrollbarAdapter(scrollState = viewModel.selectableLazyListState.lazyListState), + modifier = Modifier.fillMaxHeight().align(Alignment.CenterEnd), + ) } } val isLoading by viewModel.isLoadingFlow.collectAsState() diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt index 7660a4d3..c1cd2916 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt @@ -46,7 +46,7 @@ import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemE import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.OnPackageAction.GoToSource import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.OnPackageAction.Install import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.OnPackageAction.Remove -import com.jetbrains.packagesearch.plugin.ui.panels.packages.items.PackageListItem +import com.jetbrains.packagesearch.plugin.ui.panels.packages.items.PackageListHeader import org.jetbrains.jewel.foundation.lazy.SelectableLazyColumn import org.jetbrains.jewel.foundation.lazy.SelectableLazyItemScope import org.jetbrains.jewel.foundation.lazy.SelectableLazyListState @@ -60,6 +60,7 @@ import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle @Composable fun PackageSearchPackageList( + modifier: Modifier = Modifier, packagesList: List, isCompact: Boolean, selectableLazyListState: SelectableLazyListState, @@ -67,6 +68,7 @@ fun PackageSearchPackageList( ) { var openPopupId by remember { mutableStateOf(null) } SelectableLazyColumn( + modifier = modifier, selectionMode = SelectionMode.Single, state = selectableLazyListState, onSelectedIndexesChanged = { @@ -80,12 +82,17 @@ fun PackageSearchPackageList( ) { packagesList.forEachIndexed { index, item -> when (item) { - is PackageListItem.Header -> stickyHeader(item.id, "header") { - PackageListItem(item, onPackageEvent) + is PackageListItem.Header -> stickyHeader(key = item.id, contentType = "header") { + PackageListHeader( + additionalContentModifier = Modifier.padding(end = PackageSearchMetrics.scrollbarWidth), + content = item, + onEvent = onPackageEvent + ) } - is PackageListItem.Package -> item(item.id, contentType = item.contentType()) { + is PackageListItem.Package -> item(key = item.id, contentType = item.contentType()) { PackageListItem( + modifier = Modifier.padding(end = PackageSearchMetrics.scrollbarWidth), content = item, packagesList = packagesList, index = index, @@ -103,6 +110,7 @@ fun PackageSearchPackageList( @Composable private fun SelectableLazyItemScope.PackageListItem( + modifier: Modifier = Modifier, content: PackageListItem.Package, packagesList: List, index: Int, @@ -117,7 +125,7 @@ private fun SelectableLazyItemScope.PackageListItem( isLastItem = packagesList.getOrNull(index + 1) !is PackageListItem.Package ) Box( - modifier = Modifier + modifier = modifier .padding(itemPaddings) .onClick( interactionSource = remember { MutableInteractionSource() }, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt index 5dd1f894..3379b748 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt @@ -1,7 +1,9 @@ package com.jetbrains.packagesearch.plugin.ui.panels.packages import androidx.compose.animation.Crossfade +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -10,6 +12,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.dp import com.intellij.icons.AllIcons import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message @@ -21,7 +24,10 @@ import org.jetbrains.jewel.ui.component.Icon import org.jetbrains.jewel.ui.component.IconButton import org.jetbrains.jewel.ui.component.Text import org.jetbrains.jewel.ui.component.TextField +import org.jetbrains.jewel.ui.component.styling.LazyTreeMetrics +import org.jetbrains.jewel.ui.component.styling.LazyTreeStyle import org.jetbrains.jewel.ui.component.styling.LocalDefaultTabStyle +import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle import org.jetbrains.jewel.ui.component.styling.LocalTextFieldStyle import org.jetbrains.jewel.ui.component.styling.TabMetrics import org.jetbrains.jewel.ui.component.styling.TabStyle @@ -82,7 +88,7 @@ fun PackageSearchSearchBar( } @Composable -internal fun packageSearchTabStyle(): TabStyle { +internal fun PackageSearchTabStyle(): TabStyle { val current = LocalDefaultTabStyle.current return TabStyle( colors = current.colors, @@ -99,7 +105,7 @@ internal fun packageSearchTabStyle(): TabStyle { @Composable -fun packageSearchGlobalColors(): GlobalColors { +fun PackageSearchGlobalColors(): GlobalColors { val colors = LocalGlobalColors.current return remember(colors) { @@ -118,3 +124,28 @@ fun packageSearchGlobalColors(): GlobalColors { } } + +@Composable +internal fun PackageSearchTreeStyle(): LazyTreeStyle { + val currentStyle = LocalLazyTreeStyle.current + val paddings = currentStyle.metrics.elementPadding + return LazyTreeStyle( + currentStyle.colors, + metrics = LazyTreeMetrics( + indentSize = currentStyle.metrics.indentSize, + elementPadding = PaddingValues( + top = paddings.calculateTopPadding(), + bottom = paddings.calculateBottomPadding(), + start = paddings.calculateStartPadding(LocalLayoutDirection.current), + end = 0.dp + ), + elementContentPadding = currentStyle.metrics.elementContentPadding, + elementMinHeight = currentStyle.metrics.elementMinHeight, + chevronContentGap = currentStyle.metrics.chevronContentGap, + elementBackgroundCornerSize = currentStyle.metrics.elementBackgroundCornerSize, + ), + currentStyle.icons, + ) +} + + diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt index 86175c3b..01bb324b 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt @@ -32,7 +32,8 @@ import org.jetbrains.jewel.ui.component.Link import org.jetbrains.jewel.ui.component.Text @Composable -fun PackageListItem( +fun PackageListHeader( + additionalContentModifier: Modifier = Modifier, content: PackageListItem.Header, onEvent: (PackageListItemEvent) -> Unit, ) { @@ -107,17 +108,22 @@ fun PackageListItem( } } if (content.additionalContent != null) { - when (content.additionalContent) { - is PackageListItem.Header.AdditionalContent.VariantsText -> - LabelInfo( - text = content.additionalContent.text, - maxLines = 1 - ) + Box( + modifier = additionalContentModifier, + ) { + + when (content.additionalContent) { + is PackageListItem.Header.AdditionalContent.VariantsText -> + LabelInfo( + text = content.additionalContent.text, + maxLines = 1 + ) - is PackageListItem.Header.AdditionalContent.UpdatesAvailableCount -> - UpdateAllLink(content.additionalContent, content, onEvent) + is PackageListItem.Header.AdditionalContent.UpdatesAvailableCount -> + UpdateAllLink(content.additionalContent, content, onEvent) - PackageListItem.Header.AdditionalContent.Loading -> CircularProgressIndicator() + PackageListItem.Header.AdditionalContent.Loading -> CircularProgressIndicator() + } } } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt index dedaf526..8436175e 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.jetbrains.packagesearch.plugin.PackageSearchBundle +import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics import com.jetbrains.packagesearch.plugin.ui.bridge.LabelInfo import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelContent import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelViewModel @@ -56,7 +57,7 @@ fun PackageSearchInfoPanel( Box(modifier = Modifier.fillMaxWidth()) { Column( modifier = Modifier - .padding(start = 4.dp, top = 4.dp, end = 16.dp, bottom = 12.dp) + .padding(start = 4.dp, end = PackageSearchMetrics.scrollbarWidth) .verticalScroll(viewModel.scrollState) ) { val tab = activeTab @@ -83,7 +84,10 @@ private fun NoTabsAvailable() { Modifier.fillMaxSize(), contentAlignment = Alignment.Center, ) { - LabelInfo(PackageSearchBundle.message("packagesearch.ui.toolwindow.packages.details.noItemSelected"), textAlign = TextAlign.Center) + LabelInfo( + PackageSearchBundle.message("packagesearch.ui.toolwindow.packages.details.noItemSelected"), + textAlign = TextAlign.Center + ) } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt index 93fcf62c..3e2aadfb 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt @@ -3,14 +3,17 @@ package com.jetbrains.packagesearch.plugin.ui.panels.tree import androidx.compose.animation.Crossfade import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -38,6 +41,7 @@ import org.jetbrains.jewel.ui.component.IconButton import org.jetbrains.jewel.ui.component.LazyTree import org.jetbrains.jewel.ui.component.Text import org.jetbrains.jewel.ui.component.Tooltip +import org.jetbrains.jewel.ui.component.VerticalScrollbar @Composable fun PackageSearchModulesTree( @@ -76,21 +80,28 @@ fun PackageSearchModulesTree( .toSet() } } - - LazyTree( - modifier = Modifier.padding(top = 4.dp), - tree = tree, - treeState = viewModel.treeState, - onSelectionChange = { - onSelectionChanged( - it.map { it.id } - .filterIsInstance() - .toSet() - ) - }, - ) { item -> - TreeItem(item) + Box { + LazyTree( + modifier = Modifier.padding(top = 4.dp, end = PackageSearchMetrics.scrollbarWidth), + tree = tree, + treeState = viewModel.treeState, + onSelectionChange = { + onSelectionChanged( + it.map { it.id } + .filterIsInstance() + .toSet() + ) + }, + ) { item -> + TreeItem(item) + } + VerticalScrollbar( + adapter = rememberScrollbarAdapter(scrollState = viewModel.lazyListState), + modifier = Modifier.fillMaxHeight().align(Alignment.CenterEnd), + ) } + + } @Composable @@ -181,7 +192,7 @@ private fun TreeItem(element: Tree.Element) { } if (element.data.hasUpdates) { Icon( - modifier = Modifier.padding(end = 20.dp), + modifier = Modifier.padding(end = 12.dp), resource = "icons/intui/upgradableMark.svg", iconClass = IconProvider::class.java, contentDescription = ""