Added dynamic size tabs with a label to show the full repository path
Fixes #56
This commit is contained in:
parent
025f93320a
commit
0bfa91d2a7
@ -184,8 +184,7 @@ class App {
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(40.dp),
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
RepositoriesTabPanel(
|
||||
@ -195,7 +194,8 @@ class App {
|
||||
tabsManager.selectTab(selectedTab)
|
||||
},
|
||||
onTabClosed = onCloseTab,
|
||||
onAddNewTab = onAddedTab
|
||||
onAddNewTab = onAddedTab,
|
||||
tabsHeight = 40.dp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,9 @@ val Colors.diffLineAdded: Color
|
||||
val Colors.diffLineRemoved: Color
|
||||
get() = appTheme.diffLineRemoved
|
||||
|
||||
val Colors.isDark: Boolean
|
||||
get() = !this.isLight
|
||||
|
||||
|
||||
enum class Theme(val displayName: String) : DropDownOption {
|
||||
LIGHT("Light"),
|
||||
|
@ -20,6 +20,7 @@ import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
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.dp
|
||||
import com.jetpackduba.gitnuro.AppConstants
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
@ -221,14 +222,20 @@ fun RecentRepositories(appStateManager: AppStateManager, tabViewModel: TabViewMo
|
||||
maxLines = 1,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colors.primaryVariant,
|
||||
modifier = Modifier.padding(8.dp)
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.widthIn(max = 600.dp),
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = repoDirPath,
|
||||
style = MaterialTheme.typography.body1,
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.padding(start = 4.dp)
|
||||
.widthIn(max = 600.dp),
|
||||
maxLines = 1,
|
||||
color = MaterialTheme.colors.onBackgroundSecondary
|
||||
)
|
||||
|
@ -10,18 +10,22 @@ import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.foundation.v2.maxScrollOffset
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
import com.jetpackduba.gitnuro.AppStateManager
|
||||
import com.jetpackduba.gitnuro.LocalTabScope
|
||||
import com.jetpackduba.gitnuro.di.AppComponent
|
||||
@ -31,6 +35,8 @@ import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModel
|
||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModelsHolder
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.name
|
||||
@ -39,19 +45,15 @@ import kotlin.io.path.name
|
||||
fun RepositoriesTabPanel(
|
||||
tabs: List<TabInformation>,
|
||||
currentTab: TabInformation?,
|
||||
tabsHeight: Dp,
|
||||
onTabSelected: (TabInformation) -> Unit,
|
||||
onTabClosed: (TabInformation) -> Unit,
|
||||
onAddNewTab: () -> Unit,
|
||||
) {
|
||||
val stateHorizontal = rememberLazyListState()
|
||||
|
||||
// LaunchedEffect(selectedTabKey) {
|
||||
// val index = tabs.indexOfFirst { it.key == selectedTabKey }
|
||||
// // todo sometimes it scrolls to (index - 1) for some weird reason
|
||||
// if (index > -1) {
|
||||
// stateHorizontal.scrollToItem(index)
|
||||
// }
|
||||
// }
|
||||
val scrollAdapter = rememberScrollbarAdapter(stateHorizontal)
|
||||
val scope = rememberCoroutineScope()
|
||||
var latestTabCount by remember { mutableStateOf(tabs.count()) }
|
||||
|
||||
val canBeScrolled by remember {
|
||||
derivedStateOf {
|
||||
@ -73,18 +75,28 @@ fun RepositoriesTabPanel(
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
if (canBeScrolled) {
|
||||
Tooltip(
|
||||
"\"Shift + Mouse wheel\" to scroll"
|
||||
) {
|
||||
HorizontalScrollbar(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
adapter = scrollAdapter
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f, false)
|
||||
) {
|
||||
LazyRow(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight(),
|
||||
.height(tabsHeight)
|
||||
.weight(1f, false),
|
||||
state = stateHorizontal,
|
||||
) {
|
||||
items(items = tabs) { tab ->
|
||||
Tooltip(tab.path) {
|
||||
Tab(
|
||||
title = tab.tabName,
|
||||
isSelected = currentTab == tab,
|
||||
@ -97,19 +109,6 @@ fun RepositoriesTabPanel(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (canBeScrolled) {
|
||||
Tooltip(
|
||||
"\"Shift + Mouse wheel\" to scroll"
|
||||
) {
|
||||
HorizontalScrollbar(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.width((tabs.count() * 180).dp),
|
||||
adapter = rememberScrollbarAdapter(stateHorizontal)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(
|
||||
@ -128,11 +127,23 @@ fun RepositoriesTabPanel(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(tabs.count()) {
|
||||
// Scroll to the end if a new tab has been added & it's empty (so it's not a new submodule tab)
|
||||
if (latestTabCount < tabs.count() && currentTab?.path == null) {
|
||||
scope.launch {
|
||||
delay(50) // add small delay to wait until [scrollAdapter.maxScrollOffset] is recalculated. Seems more like a hack of some kind...
|
||||
scrollAdapter.scrollTo(scrollAdapter.maxScrollOffset)
|
||||
}
|
||||
}
|
||||
|
||||
latestTabCount = tabs.count()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Tab(title: MutableState<String>, isSelected: Boolean, onClick: () -> Unit, onCloseTab: () -> Unit) {
|
||||
Box {
|
||||
val backgroundColor = if (isSelected)
|
||||
MaterialTheme.colors.surface
|
||||
else
|
||||
@ -143,7 +154,8 @@ fun Tab(title: MutableState<String>, isSelected: Boolean, onClick: () -> Unit, o
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(180.dp)
|
||||
.widthIn(min = 200.dp)
|
||||
.width(IntrinsicSize.Min)
|
||||
.fillMaxHeight()
|
||||
.hoverable(hoverInteraction)
|
||||
.handMouseClickable { onClick() }
|
||||
@ -151,36 +163,38 @@ fun Tab(title: MutableState<String>, isSelected: Boolean, onClick: () -> Unit, o
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.CenterStart),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = title.value,
|
||||
text = title.value.replace(" ", "-"), // TODO This replace is a workaround for https://issuetracker.google.com/issues/278044455
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 8.dp)
|
||||
.weight(1f),
|
||||
overflow = TextOverflow.Visible,
|
||||
.padding(start = 16.dp)
|
||||
.weight(1f)
|
||||
.widthIn(max = 720.dp),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.body2,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
)
|
||||
|
||||
if (isHovered || isSelected) {
|
||||
IconButton(
|
||||
onClick = onCloseTab,
|
||||
enabled = isHovered || isSelected,
|
||||
modifier = Modifier
|
||||
.alpha(if (isHovered || isSelected) 1f else 0f)
|
||||
.padding(horizontal = 8.dp)
|
||||
.size(14.dp)
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Close,
|
||||
painterResource(AppIcons.CLOSE),
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colors.onBackground
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
Box(
|
||||
@ -192,7 +206,6 @@ fun Tab(title: MutableState<String>, isSelected: Boolean, onClick: () -> Unit, o
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TabInformation(
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jetpackduba.gitnuro.ui.components
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.TooltipArea
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@ -9,14 +10,23 @@ import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.theme.isDark
|
||||
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun Tooltip(text: String, content: @Composable () -> Unit) {
|
||||
fun Tooltip(text: String?, content: @Composable () -> Unit) {
|
||||
TooltipArea(
|
||||
tooltip = {
|
||||
if (text != null) {
|
||||
val border = if (MaterialTheme.colors.isDark) {
|
||||
BorderStroke(2.dp, MaterialTheme.colors.onBackgroundSecondary.copy(alpha = 0.4f))
|
||||
} else
|
||||
null
|
||||
|
||||
Card(
|
||||
backgroundColor = MaterialTheme.colors.background,
|
||||
border = border,
|
||||
elevation = 10.dp,
|
||||
) {
|
||||
Text(
|
||||
@ -24,6 +34,7 @@ fun Tooltip(text: String, content: @Composable () -> Unit) {
|
||||
modifier = Modifier.padding(8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
) {
|
||||
content()
|
||||
|
Loading…
Reference in New Issue
Block a user