Refactored tab management to its own single file without having to deal with unique IDs or having code to manage the tab scattered around the app
This commit is contained in:
parent
0d91ec747a
commit
a55dd755d7
@ -34,13 +34,10 @@ import com.jetpackduba.gitnuro.theme.AppTheme
|
|||||||
import com.jetpackduba.gitnuro.theme.Theme
|
import com.jetpackduba.gitnuro.theme.Theme
|
||||||
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
|
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
|
||||||
import com.jetpackduba.gitnuro.ui.AppTab
|
import com.jetpackduba.gitnuro.ui.AppTab
|
||||||
|
import com.jetpackduba.gitnuro.ui.TabsManager
|
||||||
import com.jetpackduba.gitnuro.ui.components.RepositoriesTabPanel
|
import com.jetpackduba.gitnuro.ui.components.RepositoriesTabPanel
|
||||||
import com.jetpackduba.gitnuro.ui.components.TabInformation
|
import com.jetpackduba.gitnuro.ui.components.TabInformation
|
||||||
import com.jetpackduba.gitnuro.ui.components.emptyTabInformation
|
import com.jetpackduba.gitnuro.ui.components.emptyTabInformation
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.update
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.eclipse.jgit.lib.GpgSigner
|
import org.eclipse.jgit.lib.GpgSigner
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@ -65,16 +62,17 @@ class App {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appEnvInfo: AppEnvInfo
|
lateinit var appEnvInfo: AppEnvInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var tabsManager: TabsManager
|
||||||
|
|
||||||
init {
|
init {
|
||||||
appComponent.inject(this)
|
appComponent.inject(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val tabsFlow = MutableStateFlow<List<TabInformation>>(emptyList())
|
|
||||||
|
|
||||||
fun start(args: Array<String>) {
|
fun start(args: Array<String>) {
|
||||||
|
tabsManager.appComponent = this.appComponent
|
||||||
val windowPlacement = appSettings.windowPlacement.toWindowPlacement
|
val windowPlacement = appSettings.windowPlacement.toWindowPlacement
|
||||||
val dirToOpen = getDirToOpen(args)
|
val dirToOpen = getDirToOpen(args)
|
||||||
var defaultSelectedTabKey = 0
|
|
||||||
|
|
||||||
appEnvInfo.isFlatpak = args.contains("--flatpak") // TODO Test this
|
appEnvInfo.isFlatpak = args.contains("--flatpak") // TODO Test this
|
||||||
appStateManager.loadRepositoriesTabs()
|
appStateManager.loadRepositoriesTabs()
|
||||||
@ -88,12 +86,12 @@ class App {
|
|||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTabs()
|
tabsManager.loadPersistedTabs()
|
||||||
|
|
||||||
GpgSigner.setDefault(appGpgSigner)
|
GpgSigner.setDefault(appGpgSigner)
|
||||||
|
|
||||||
if (dirToOpen != null)
|
if (dirToOpen != null)
|
||||||
defaultSelectedTabKey = addDirTab(dirToOpen)
|
addDirTab(dirToOpen)
|
||||||
|
|
||||||
application {
|
application {
|
||||||
var isOpen by remember { mutableStateOf(true) }
|
var isOpen by remember { mutableStateOf(true) }
|
||||||
@ -129,7 +127,7 @@ class App {
|
|||||||
customTheme = customTheme,
|
customTheme = customTheme,
|
||||||
) {
|
) {
|
||||||
Box(modifier = Modifier.background(MaterialTheme.colors.background)) {
|
Box(modifier = Modifier.background(MaterialTheme.colors.background)) {
|
||||||
AppTabs(defaultSelectedTabKey)
|
AppTabs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,100 +140,46 @@ class App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addDirTab(dirToOpen: File): Int {
|
private fun addDirTab(dirToOpen: File) {
|
||||||
var defaultSelectedTabKey = 0
|
val absolutePath = dirToOpen.normalize().absolutePath
|
||||||
|
.removeSuffix(systemSeparator)
|
||||||
|
.removeSuffix("$systemSeparator.git")
|
||||||
|
|
||||||
tabsFlow.update {
|
tabsManager.addNewTabFromPath(absolutePath, true)
|
||||||
val newList = it.toMutableList()
|
|
||||||
val absolutePath = dirToOpen.normalize().absolutePath
|
|
||||||
.removeSuffix(systemSeparator)
|
|
||||||
.removeSuffix("$systemSeparator.git")
|
|
||||||
val newKey = it.count()
|
|
||||||
|
|
||||||
val existingIndex =
|
|
||||||
newList.indexOfFirst { repo -> repo.path?.removeSuffix(systemSeparator) == absolutePath }
|
|
||||||
|
|
||||||
defaultSelectedTabKey = if (existingIndex == -1) {
|
|
||||||
newList.add(newAppTab(key = newKey, path = absolutePath))
|
|
||||||
newKey
|
|
||||||
} else {
|
|
||||||
existingIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
newList
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultSelectedTabKey
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadTabs() {
|
|
||||||
val repositoriesSavedTabs = appStateManager.openRepositoriesPathsTabs
|
|
||||||
var repoTabs = repositoriesSavedTabs.map { repositoryTab ->
|
|
||||||
newAppTab(
|
|
||||||
key = repositoryTab.key,
|
|
||||||
path = repositoryTab.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (repoTabs.isEmpty()) {
|
|
||||||
repoTabs = listOf(
|
|
||||||
newAppTab()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
tabsFlow.value = repoTabs
|
|
||||||
|
|
||||||
println("After reading prefs, got ${tabsFlow.value.count()} tabs")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppTabs(defaultSelectedTabKey: Int) {
|
fun AppTabs() {
|
||||||
val tabs by tabsFlow.collectAsState()
|
val tabs by tabsManager.tabsFlow.collectAsState()
|
||||||
val tabsInformationList = tabs.sortedBy { it.key }
|
val currentTab = tabsManager.currentTab.collectAsState().value
|
||||||
val selectedTabKey = remember { mutableStateOf(defaultSelectedTabKey) }
|
|
||||||
|
|
||||||
Column(
|
if(currentTab != null) {
|
||||||
modifier = Modifier.background(MaterialTheme.colors.background)
|
Column(
|
||||||
) {
|
modifier = Modifier.background(MaterialTheme.colors.background)
|
||||||
Tabs(
|
) {
|
||||||
tabsInformationList = tabsInformationList,
|
Tabs(
|
||||||
selectedTabKey = selectedTabKey,
|
tabsInformationList = tabs,
|
||||||
onAddedTab = { tabInfo ->
|
currentTab = currentTab,
|
||||||
addTab(tabInfo)
|
onAddedTab = {
|
||||||
},
|
tabsManager.newTab()
|
||||||
onRemoveTab = { key ->
|
},
|
||||||
removeTab(key)
|
onCloseTab = { tab ->
|
||||||
}
|
tabsManager.closeTab(tab)
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
TabsContent(tabsInformationList, selectedTabKey.value)
|
TabsContent(tabs, currentTab)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeTab(key: Int) = appStateManager.appScope.launch(Dispatchers.IO) {
|
|
||||||
// Stop any running jobs
|
|
||||||
val tabs = tabsFlow.value
|
|
||||||
val tabToRemove = tabs.firstOrNull { it.key == key } ?: return@launch
|
|
||||||
tabToRemove.tabViewModel.dispose()
|
|
||||||
|
|
||||||
// Remove tab from persistent tabs storage
|
|
||||||
appStateManager.repositoryTabRemoved(key)
|
|
||||||
|
|
||||||
// Remove from tabs flow
|
|
||||||
tabsFlow.value = tabsFlow.value.filter { tab -> tab.key != key }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addTab(tabInformation: TabInformation) = appStateManager.appScope.launch(Dispatchers.IO) {
|
|
||||||
tabsFlow.value = tabsFlow.value.toMutableList().apply { add(tabInformation) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Tabs(
|
fun Tabs(
|
||||||
selectedTabKey: MutableState<Int>,
|
|
||||||
tabsInformationList: List<TabInformation>,
|
tabsInformationList: List<TabInformation>,
|
||||||
onAddedTab: (TabInformation) -> Unit,
|
currentTab: TabInformation?,
|
||||||
onRemoveTab: (Int) -> Unit,
|
onAddedTab: () -> Unit,
|
||||||
|
onCloseTab: (TabInformation) -> Unit,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -245,36 +189,16 @@ class App {
|
|||||||
) {
|
) {
|
||||||
RepositoriesTabPanel(
|
RepositoriesTabPanel(
|
||||||
tabs = tabsInformationList,
|
tabs = tabsInformationList,
|
||||||
selectedTabKey = selectedTabKey.value,
|
currentTab = currentTab,
|
||||||
onTabSelected = { newSelectedTabKey ->
|
onTabSelected = { selectedTab ->
|
||||||
selectedTabKey.value = newSelectedTabKey
|
tabsManager.selectTab(selectedTab)
|
||||||
},
|
},
|
||||||
onTabClosed = onRemoveTab
|
onTabClosed = onCloseTab,
|
||||||
) { key ->
|
onAddNewTab = onAddedTab
|
||||||
val newAppTab = newAppTab(
|
)
|
||||||
key = key
|
|
||||||
)
|
|
||||||
|
|
||||||
onAddedTab(newAppTab)
|
|
||||||
newAppTab
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newAppTab(
|
|
||||||
key: Int = 0,
|
|
||||||
tabName: MutableState<String> = mutableStateOf("New tab"),
|
|
||||||
path: String? = null,
|
|
||||||
): TabInformation {
|
|
||||||
|
|
||||||
return TabInformation(
|
|
||||||
tabName = tabName,
|
|
||||||
key = key,
|
|
||||||
path = path,
|
|
||||||
appComponent = appComponent,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDirToOpen(args: Array<String>): File? {
|
fun getDirToOpen(args: Array<String>): File? {
|
||||||
if (args.isNotEmpty()) {
|
if (args.isNotEmpty()) {
|
||||||
val repoToOpen = args.first()
|
val repoToOpen = args.first()
|
||||||
@ -296,20 +220,18 @@ class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TabsContent(tabs: List<TabInformation>, selectedTabKey: Int) {
|
private fun TabsContent(tabs: List<TabInformation>, currentTab: TabInformation?) {
|
||||||
val selectedTab = tabs.firstOrNull { it.key == selectedTabKey }
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(MaterialTheme.colors.background)
|
.background(MaterialTheme.colors.background)
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
if (selectedTab != null) {
|
if (currentTab != null) {
|
||||||
val density = arrayOf(LocalTabScope provides selectedTab)
|
val density = arrayOf(LocalTabScope provides currentTab)
|
||||||
|
|
||||||
|
|
||||||
CompositionLocalProvider(values = density) {
|
CompositionLocalProvider(values = density) {
|
||||||
AppTab(selectedTab.tabViewModel)
|
AppTab(currentTab.tabViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,12 +51,6 @@ class AppStateManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun repositoryTabRemoved(key: Int) = appScope.launch(Dispatchers.IO) {
|
|
||||||
_openRepositoriesPaths.remove(key)
|
|
||||||
|
|
||||||
updateSavedRepositoryTabs()
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun updateSavedRepositoryTabs() = withContext(Dispatchers.IO) {
|
private suspend fun updateSavedRepositoryTabs() = withContext(Dispatchers.IO) {
|
||||||
val tabsList = _openRepositoriesPaths.map { it.value }
|
val tabsList = _openRepositoriesPaths.map { it.value }
|
||||||
appSettings.latestTabsOpened = Json.encodeToString(tabsList)
|
appSettings.latestTabsOpened = Json.encodeToString(tabsList)
|
||||||
@ -67,16 +61,6 @@ class AppStateManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun loadRepositoriesTabs() {
|
fun loadRepositoriesTabs() {
|
||||||
val repositoriesSaved = appSettings.latestTabsOpened
|
|
||||||
|
|
||||||
if (repositoriesSaved.isNotEmpty()) {
|
|
||||||
val repositoriesList = Json.decodeFromString<List<String>>(repositoriesSaved)
|
|
||||||
|
|
||||||
repositoriesList.forEachIndexed { index, repository ->
|
|
||||||
_openRepositoriesPaths[index] = repository
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val repositoriesPathsSaved = appSettings.latestOpenedRepositoriesPath
|
val repositoriesPathsSaved = appSettings.latestOpenedRepositoriesPath
|
||||||
if (repositoriesPathsSaved.isNotEmpty()) {
|
if (repositoriesPathsSaved.isNotEmpty()) {
|
||||||
val repositories = Json.decodeFromString<List<String>>(repositoriesPathsSaved)
|
val repositories = Json.decodeFromString<List<String>>(repositoriesPathsSaved)
|
||||||
|
128
src/main/kotlin/com/jetpackduba/gitnuro/ui/TabsManager.kt
Normal file
128
src/main/kotlin/com/jetpackduba/gitnuro/ui/TabsManager.kt
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package com.jetpackduba.gitnuro.ui
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import com.jetpackduba.gitnuro.di.AppComponent
|
||||||
|
import com.jetpackduba.gitnuro.preferences.AppSettings
|
||||||
|
import com.jetpackduba.gitnuro.ui.components.TabInformation
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class TabsManager @Inject constructor(
|
||||||
|
private val appSettings: AppSettings
|
||||||
|
) {
|
||||||
|
lateinit var appComponent: AppComponent
|
||||||
|
|
||||||
|
private val _tabsFlow = MutableStateFlow<List<TabInformation>>(emptyList())
|
||||||
|
val tabsFlow: StateFlow<List<TabInformation>> = _tabsFlow
|
||||||
|
|
||||||
|
private val _currentTab = MutableStateFlow<TabInformation?>(null)
|
||||||
|
val currentTab: StateFlow<TabInformation?> = _currentTab
|
||||||
|
|
||||||
|
fun loadPersistedTabs() {
|
||||||
|
val repositoriesSaved = appSettings.latestTabsOpened
|
||||||
|
|
||||||
|
val tabs = if (repositoriesSaved.isNotEmpty()) {
|
||||||
|
val repositoriesList = Json.decodeFromString<List<String>>(repositoriesSaved)
|
||||||
|
|
||||||
|
repositoriesList.map { path ->
|
||||||
|
newAppTab(
|
||||||
|
path = path,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listOf(newAppTab())
|
||||||
|
}
|
||||||
|
|
||||||
|
_tabsFlow.value = tabs
|
||||||
|
_currentTab.value = _tabsFlow.value.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addNewTabFromPath(path: String, selectTab: Boolean) {
|
||||||
|
val newTab = newAppTab(
|
||||||
|
tabName = mutableStateOf(""),
|
||||||
|
path = path,
|
||||||
|
)
|
||||||
|
|
||||||
|
_tabsFlow.update {
|
||||||
|
it.toMutableList().apply {
|
||||||
|
add(newTab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectTab) {
|
||||||
|
_currentTab.value = newTab
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun selectTab(tab: TabInformation) {
|
||||||
|
_currentTab.value = tab
|
||||||
|
}
|
||||||
|
|
||||||
|
fun closeTab(tab: TabInformation) {
|
||||||
|
val tabsList = _tabsFlow.value.toMutableList()
|
||||||
|
var newCurrentTab: TabInformation? = null
|
||||||
|
|
||||||
|
if (currentTab.value == tab) {
|
||||||
|
val index = tabsList.indexOf(tab)
|
||||||
|
if (tabsList.count() == 1) {
|
||||||
|
newCurrentTab = newAppTab()
|
||||||
|
} else if (index > 0) {
|
||||||
|
newCurrentTab = tabsList[index - 1]
|
||||||
|
} else if (index == 0) {
|
||||||
|
newCurrentTab = tabsList[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tab.tabViewModel.dispose()
|
||||||
|
tabsList.remove(tab)
|
||||||
|
|
||||||
|
if (newCurrentTab != null) {
|
||||||
|
if (!tabsList.contains(newCurrentTab)) {
|
||||||
|
tabsList.add(newCurrentTab)
|
||||||
|
}
|
||||||
|
|
||||||
|
_tabsFlow.value = tabsList
|
||||||
|
_currentTab.value = newCurrentTab
|
||||||
|
} else {
|
||||||
|
_tabsFlow.value = tabsList
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePersistedTabs()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePersistedTabs() {
|
||||||
|
val tabs = tabsFlow.value
|
||||||
|
appSettings.latestTabsOpened = Json.encodeToString(tabs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun newTab() {
|
||||||
|
val newTab = newAppTab()
|
||||||
|
|
||||||
|
_tabsFlow.update {
|
||||||
|
it.toMutableList().apply {
|
||||||
|
add(newTab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentTab.value = newTab
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newAppTab(
|
||||||
|
tabName: MutableState<String> = mutableStateOf("New tab"),
|
||||||
|
path: String? = null,
|
||||||
|
): TabInformation {
|
||||||
|
return TabInformation(
|
||||||
|
tabName = tabName,
|
||||||
|
path = path,
|
||||||
|
appComponent = appComponent,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -22,17 +22,13 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.jetpackduba.gitnuro.App
|
|
||||||
import com.jetpackduba.gitnuro.AppStateManager
|
import com.jetpackduba.gitnuro.AppStateManager
|
||||||
import com.jetpackduba.gitnuro.LocalTabScope
|
import com.jetpackduba.gitnuro.LocalTabScope
|
||||||
import com.jetpackduba.gitnuro.credentials.CredentialsStateManager
|
|
||||||
import com.jetpackduba.gitnuro.di.AppComponent
|
import com.jetpackduba.gitnuro.di.AppComponent
|
||||||
import com.jetpackduba.gitnuro.di.DaggerTabComponent
|
import com.jetpackduba.gitnuro.di.DaggerTabComponent
|
||||||
import com.jetpackduba.gitnuro.di.TabComponent
|
import com.jetpackduba.gitnuro.di.TabComponent
|
||||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||||
import com.jetpackduba.gitnuro.preferences.AppSettings
|
|
||||||
import com.jetpackduba.gitnuro.viewmodels.SettingsViewModel
|
|
||||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModel
|
import com.jetpackduba.gitnuro.viewmodels.TabViewModel
|
||||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModelsHolder
|
import com.jetpackduba.gitnuro.viewmodels.TabViewModelsHolder
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -42,21 +38,20 @@ import kotlin.io.path.name
|
|||||||
@Composable
|
@Composable
|
||||||
fun RepositoriesTabPanel(
|
fun RepositoriesTabPanel(
|
||||||
tabs: List<TabInformation>,
|
tabs: List<TabInformation>,
|
||||||
selectedTabKey: Int,
|
currentTab: TabInformation?,
|
||||||
onTabSelected: (Int) -> Unit,
|
onTabSelected: (TabInformation) -> Unit,
|
||||||
onTabClosed: (Int) -> Unit,
|
onTabClosed: (TabInformation) -> Unit,
|
||||||
newTabContent: (key: Int) -> TabInformation,
|
onAddNewTab: () -> Unit,
|
||||||
) {
|
) {
|
||||||
var tabsIdentifier by remember { mutableStateOf(tabs.count()) }
|
|
||||||
val stateHorizontal = rememberLazyListState()
|
val stateHorizontal = rememberLazyListState()
|
||||||
|
|
||||||
LaunchedEffect(selectedTabKey) {
|
// LaunchedEffect(selectedTabKey) {
|
||||||
val index = tabs.indexOfFirst { it.key == selectedTabKey }
|
// val index = tabs.indexOfFirst { it.key == selectedTabKey }
|
||||||
// todo sometimes it scrolls to (index - 1) for some weird reason
|
// // todo sometimes it scrolls to (index - 1) for some weird reason
|
||||||
if (index > -1) {
|
// if (index > -1) {
|
||||||
stateHorizontal.scrollToItem(index)
|
// stateHorizontal.scrollToItem(index)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
val canBeScrolled by remember {
|
val canBeScrolled by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
@ -89,31 +84,15 @@ fun RepositoriesTabPanel(
|
|||||||
.fillMaxHeight(),
|
.fillMaxHeight(),
|
||||||
state = stateHorizontal,
|
state = stateHorizontal,
|
||||||
) {
|
) {
|
||||||
items(items = tabs, key = { it.key }) { tab ->
|
items(items = tabs) { tab ->
|
||||||
Tab(
|
Tab(
|
||||||
title = tab.tabName,
|
title = tab.tabName,
|
||||||
isSelected = tab.key == selectedTabKey,
|
isSelected = currentTab == tab,
|
||||||
onClick = {
|
onClick = {
|
||||||
onTabSelected(tab.key)
|
onTabSelected(tab)
|
||||||
},
|
},
|
||||||
onCloseTab = {
|
onCloseTab = {
|
||||||
val isTabSelected = selectedTabKey == tab.key
|
onTabClosed(tab)
|
||||||
|
|
||||||
if (isTabSelected) {
|
|
||||||
val nextKey = getTabNextKey(tab, tabs)
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -135,10 +114,7 @@ fun RepositoriesTabPanel(
|
|||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
tabsIdentifier++
|
onAddNewTab()
|
||||||
|
|
||||||
newTabContent(tabsIdentifier)
|
|
||||||
onTabSelected(tabsIdentifier)
|
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(36.dp)
|
.size(36.dp)
|
||||||
@ -154,24 +130,6 @@ fun RepositoriesTabPanel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getTabNextKey(tab: TabInformation, tabs: List<TabInformation>): Int {
|
|
||||||
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
|
|
||||||
|
|
||||||
return if (nextIndex >= 0)
|
|
||||||
tabs[nextIndex].key
|
|
||||||
else
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Tab(title: MutableState<String>, isSelected: Boolean, onClick: () -> Unit, onCloseTab: () -> Unit) {
|
fun Tab(title: MutableState<String>, isSelected: Boolean, onClick: () -> Unit, onCloseTab: () -> Unit) {
|
||||||
Box {
|
Box {
|
||||||
@ -239,7 +197,6 @@ fun Tab(title: MutableState<String>, isSelected: Boolean, onClick: () -> Unit, o
|
|||||||
|
|
||||||
class TabInformation(
|
class TabInformation(
|
||||||
val tabName: MutableState<String>,
|
val tabName: MutableState<String>,
|
||||||
val key: Int,
|
|
||||||
val path: String?,
|
val path: String?,
|
||||||
appComponent: AppComponent?,
|
appComponent: AppComponent?,
|
||||||
) {
|
) {
|
||||||
@ -261,10 +218,10 @@ class TabInformation(
|
|||||||
|
|
||||||
tabViewModel.onRepositoryChanged = { path ->
|
tabViewModel.onRepositoryChanged = { path ->
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
appStateManager.repositoryTabRemoved(key)
|
// appStateManager.repositoryTabRemoved(key)
|
||||||
} else {
|
} else {
|
||||||
tabName.value = Path(path).name
|
tabName.value = Path(path).name
|
||||||
appStateManager.repositoryTabChanged(key, path)
|
// appStateManager.repositoryTabChanged(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (path != null)
|
if (path != null)
|
||||||
@ -272,7 +229,7 @@ class TabInformation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun emptyTabInformation() = TabInformation(mutableStateOf(""), 0, "", null)
|
fun emptyTabInformation() = TabInformation(mutableStateOf(""), "", null)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
inline fun <reified T> gitnuroViewModel(): T {
|
inline fun <reified T> gitnuroViewModel(): T {
|
||||||
|
Loading…
Reference in New Issue
Block a user