Make sure changing repo starts in a clean state & implemented tab lazy loading

Changing the open repository in the current tab will now create a new tab that replaces the current one instead of updating the TabViewModel and having to make sure that every subviewmodel handles the change of repository properly.

This also allowed implementing lazy loading of a tab, so it does not load every repo at the same time.

Fixes #122
This commit is contained in:
Abdelilah El Aissaoui 2023-06-04 18:56:43 +02:00
parent 8462a40733
commit 60c15131db
No known key found for this signature in database
GPG Key ID: 7587FC860F594869
5 changed files with 60 additions and 12 deletions

View File

@ -34,6 +34,17 @@ fun AppTab(
val repositorySelectionStatusValue = repositorySelectionStatus.value
val processingState = tabViewModel.processing.collectAsState().value
LaunchedEffect(tabViewModel) {
// Init the tab content when the tab is selected and also remove the "initialPath" to avoid opening the
// repository everytime the user changes between tabs
val initialPath = tabViewModel.initialPath
tabViewModel.initialPath = null
if (initialPath != null) {
tabViewModel.openRepository(initialPath)
}
}
Box {
Column(
modifier = Modifier

View File

@ -20,6 +20,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.*
import com.jetpackduba.gitnuro.AppConstants
import com.jetpackduba.gitnuro.LocalTabScope
import com.jetpackduba.gitnuro.extensions.handMouseClickable
import com.jetpackduba.gitnuro.git.DiffEntryType
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
@ -137,6 +138,7 @@ fun RepositoryOpenPage(
onCancelRebaseInteractive = { tabViewModel.cancelRebaseInteractive() }
)
} else {
val currentTabInformation = LocalTabScope.current
Column(modifier = Modifier.weight(1f)) {
Menu(
modifier = Modifier
@ -150,7 +152,7 @@ fun RepositoryOpenPage(
val repo = tabViewModel.openDirectoryPicker()
if (repo != null) {
tabViewModel.openRepository(repo)
tabViewModel.openAnotherRepository(repo, currentTabInformation)
}
},
onQuickActions = { showQuickActionsDialog = true },

View File

@ -42,16 +42,23 @@ class TabsManager @Inject constructor(
_currentTab.value = _tabsFlow.value.first()
}
fun addNewTabFromPath(path: String, selectTab: Boolean) {
fun addNewTabFromPath(path: String, selectTab: Boolean, tabToBeReplaced: TabInformation? = null) {
val newTab = newAppTab(
tabName = mutableStateOf(""),
path = path,
)
_tabsFlow.update {
it.toMutableList().apply {
add(newTab)
val newTabsList = it.toMutableList()
if (tabToBeReplaced != null) {
val index = newTabsList.indexOf(tabToBeReplaced)
newTabsList[index] = newTab
} else {
newTabsList.add(newTab)
}
newTabsList
}
if (selectTab) {
@ -116,7 +123,7 @@ class TabsManager @Inject constructor(
}
private fun newAppTab(
tabName: MutableState<String> = mutableStateOf("New tab"),
tabName: MutableState<String> = mutableStateOf(TabInformation.DEFAULT_NAME),
path: String? = null,
): TabInformation {
return TabInformation(

View File

@ -242,20 +242,34 @@ class TabInformation(
init {
tabComponent.inject(this)
tabViewModel.onRepositoryChanged = { path ->
this.path = path
if (initialPath != null) {
tabName.value = Path(initialPath).name
}
tabViewModel.onRepositoryChanged = { newPath ->
this.path = newPath
if (newPath == null) {
tabName.value = TabInformation.DEFAULT_NAME
} else {
tabName.value = Path(newPath).name
appStateManager.repositoryTabChanged(newPath)
}
tabName.value = Path(path).name
appStateManager.repositoryTabChanged(path)
onTabPathChanged()
}
if (initialPath != null)
tabViewModel.openRepository(initialPath)
// Set the path that should be loaded when the tab is selected for the first time
tabViewModel.initialPath = initialPath
}
fun dispose() {
tabViewModel.dispose()
}
companion object {
const val DEFAULT_NAME = "New tab"
}
}
fun emptyTabInformation() = TabInformation(mutableStateOf(""), "", {}, null)

View File

@ -22,6 +22,8 @@ import com.jetpackduba.gitnuro.system.OpenFilePickerUseCase
import com.jetpackduba.gitnuro.system.OpenUrlInBrowserUseCase
import com.jetpackduba.gitnuro.system.PickerType
import com.jetpackduba.gitnuro.ui.SelectedItem
import com.jetpackduba.gitnuro.ui.TabsManager
import com.jetpackduba.gitnuro.ui.components.TabInformation
import com.jetpackduba.gitnuro.updates.Update
import com.jetpackduba.gitnuro.updates.UpdatesRepository
import kotlinx.coroutines.*
@ -66,8 +68,10 @@ class TabViewModel @Inject constructor(
private val abortRebaseUseCase: AbortRebaseUseCase,
private val openFilePickerUseCase: OpenFilePickerUseCase,
private val openUrlInBrowserUseCase: OpenUrlInBrowserUseCase,
private val tabsManager: TabsManager,
private val tabScope: CoroutineScope,
) {
var initialPath: String? = null // Stores the path that should be opened when the tab is selected
val errorsManager: ErrorsManager = tabState.errorsManager
val selectedItem: StateFlow<SelectedItem> = tabState.selectedItem
var diffViewModel: DiffViewModel? = null
@ -163,6 +167,15 @@ class TabViewModel @Inject constructor(
rebaseInteractiveViewModel?.startRebaseInteractive(taskEvent.revCommit)
}
/**
* To make sure the tab opens the new repository with a clean state,
* instead of opening the repo in the same ViewModel we simply create a new tab with a new TabViewModel
* replacing the current tab
*/
fun openAnotherRepository(directory: String, current: TabInformation) {
tabsManager.addNewTabFromPath(directory, true, current)
}
fun openRepository(directory: String) {
openRepository(File(directory))
}
@ -197,6 +210,7 @@ class TabViewModel @Inject constructor(
watchRepositoryChanges(git)
} catch (ex: Exception) {
onRepositoryChanged(null)
ex.printStackTrace()
errorsManager.addError(newErrorNow(ex, ex.localizedMessage))
_repositorySelectionStatus.value = RepositorySelectionStatus.None
@ -324,7 +338,7 @@ class TabViewModel @Inject constructor(
credentialsStateManager.updateState(CredentialsAccepted.SshCredentialsAccepted(password))
}
var onRepositoryChanged: (path: String) -> Unit = {}
var onRepositoryChanged: (path: String?) -> Unit = {}
fun dispose() {
tabScope.cancel()