package app.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* 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.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import app.AppStateManager import app.di.AppComponent import app.di.DaggerTabComponent import app.theme.primaryTextColor import app.viewmodels.TabViewModel import app.theme.tabColorActive import app.theme.tabColorInactive import app.ui.AppTab import javax.inject.Inject import kotlin.io.path.Path import kotlin.io.path.name @Composable fun RepositoriesTabPanel( modifier: Modifier = Modifier, tabs: List, selectedTabKey: Int, onTabSelected: (Int) -> Unit, onTabClosed: (Int) -> Unit, newTabContent: (key: Int) -> TabInformation, ) { var tabsIdentifier by remember { mutableStateOf(tabs.count()) } TabPanel( modifier = modifier, onNewTabClicked = { tabsIdentifier++ newTabContent(tabsIdentifier) onTabSelected(tabsIdentifier) } ) { items(items = tabs) { tab -> Tab( title = tab.tabName, selected = tab.key == selectedTabKey, onClick = { onTabSelected(tab.key) }, onCloseTab = { val isTabSelected = selectedTabKey == tab.key val index = tabs.indexOf(tab) val nextIndex = if (index == 0 && tabs.count() >= 2) { 1 // If the first tab is selected, select the next one } else if (index == tabs.count() -1 && tabs.count() >= 2) index - 1 // If the last tab is selected, select the previous one else if (tabs.count() >= 2) index + 1 // If any in between tab is selected, select the next one else -1 // If there aren't any additional tabs once we remove this one val nextKey = if (nextIndex >= 0) tabs[nextIndex].key else -1 if (isTabSelected) { if (nextKey >= 0) { onTabSelected(nextKey) } else { tabsIdentifier++ // Create a new tab if the tabs list is empty after removing the current one newTabContent(tabsIdentifier) onTabSelected(tabsIdentifier) } } onTabClosed(tab.key) } ) } } } @Composable fun TabPanel( modifier: Modifier = Modifier, onNewTabClicked: () -> Unit, tabs: LazyListScope.() -> Unit ) { LazyRow( modifier = modifier, ) { this.tabs() item { IconButton( onClick = onNewTabClicked, modifier = Modifier .size(36.dp), ) { Icon( imageVector = Icons.Default.Add, contentDescription = null, tint = MaterialTheme.colors.primary ) } } } } @Composable fun Tab(title: MutableState, selected: Boolean, onClick: () -> Unit, onCloseTab: () -> Unit) { val elevation = if(selected) { 3.dp } else 0.dp Box { val backgroundColor = if (selected) MaterialTheme.colors.tabColorActive else MaterialTheme.colors.tabColorInactive Box( modifier = Modifier .width(180.dp) .shadow(elevation = elevation) .padding(start = 2.dp, end = 2.dp, top = 2.dp) .clip(RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp)) .clickable { onClick() } .background(backgroundColor), ) { Text( text = title.value, modifier = Modifier .padding(vertical = 8.dp, horizontal = 16.dp), color = contentColorFor(backgroundColor), ) IconButton( onClick = onCloseTab, modifier = Modifier .align(Alignment.CenterEnd) .padding(horizontal = 8.dp) .size(14.dp) ) { Icon(Icons.Default.Close, contentDescription = null, tint = MaterialTheme.colors.primaryTextColor) } } } } class TabInformation( val tabName: MutableState, val key: Int, val path: String?, appComponent: AppComponent, ) { @Inject lateinit var tabViewModel: TabViewModel @Inject lateinit var appStateManager: AppStateManager val content: @Composable (TabInformation) -> Unit init { val tabComponent = DaggerTabComponent.builder() .appComponent(appComponent) .build() tabComponent.inject(this) //TODO: This shouldn't be here, should be in the parent method tabViewModel.onRepositoryChanged = { path -> if (path == null) { appStateManager.repositoryTabRemoved(key) } else { tabName.value = Path(path).name appStateManager.repositoryTabChanged(key, path) } } if(path != null) tabViewModel.openRepository(path) content = { AppTab(tabViewModel) } } }