From f5ee17345312ad69d46be10b4e03db5dfc3d32db Mon Sep 17 00:00:00 2001 From: Abdelilah El Aissaoui Date: Sat, 20 Jul 2024 01:18:39 +0200 Subject: [PATCH] Width of triple vertical split pane columns is now persisted Fixes #176 --- .../jetpackduba/gitnuro/di/AppComponent.kt | 3 ++ .../repositories/AppSettingsRepository.kt | 20 ++++++++ .../jetpackduba/gitnuro/ui/RepositoryOpen.kt | 30 +++++++++-- .../gitnuro/ui/VerticalSplitPaneConfig.kt | 51 +++++++++++++++++++ .../ui/components/TripleVerticalSplitPanel.kt | 35 +++++++++---- .../gitnuro/viewmodels/TabViewModel.kt | 7 +-- 6 files changed, 129 insertions(+), 17 deletions(-) create mode 100644 src/main/kotlin/com/jetpackduba/gitnuro/ui/VerticalSplitPaneConfig.kt diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/di/AppComponent.kt b/src/main/kotlin/com/jetpackduba/gitnuro/di/AppComponent.kt index c7e282c..684a8d1 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/di/AppComponent.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/di/AppComponent.kt @@ -13,6 +13,7 @@ import com.jetpackduba.gitnuro.managers.TempFilesManager import com.jetpackduba.gitnuro.repositories.AppSettingsRepository import com.jetpackduba.gitnuro.terminal.ITerminalProvider import com.jetpackduba.gitnuro.ui.TabsManager +import com.jetpackduba.gitnuro.ui.VerticalSplitPaneConfig import com.jetpackduba.gitnuro.updates.UpdatesRepository import com.jetpackduba.gitnuro.viewmodels.SettingsViewModel import dagger.Component @@ -34,6 +35,8 @@ interface AppComponent { fun appPreferences(): AppSettingsRepository + fun verticalSplitPaneConfig(): VerticalSplitPaneConfig + fun appEnvInfo(): AppEnvInfo fun tabsManager(): TabsManager diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/repositories/AppSettingsRepository.kt b/src/main/kotlin/com/jetpackduba/gitnuro/repositories/AppSettingsRepository.kt index 9f619a4..13ac172 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/repositories/AppSettingsRepository.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/repositories/AppSettingsRepository.kt @@ -43,6 +43,8 @@ private const val PREF_PROXY_USE_AUTH = "proxyUseAuth" private const val PREF_PROXY_USER = "proxyHostUser" private const val PREF_PROXY_PASSWORD = "proxyHostPassword" private const val PREF_CACHE_CREDENTIALS_IN_MEMORY = "credentialsInMemory" +private const val PREF_FIRST_PANE_WIDTH = "firstPaneWidth" +private const val PREF_THIRD_PANE_WIDTH = "thirdPaneWidth" private const val PREF_GIT_FF_MERGE = "gitFFMerge" @@ -57,6 +59,8 @@ private const val DEFAULT_SWAP_UNCOMMITTED_CHANGES = false private const val DEFAULT_SHOW_CHANGES_AS_TREE = false private const val DEFAULT_CACHE_CREDENTIALS_IN_MEMORY = true private const val DEFAULT_VERIFY_SSL = true +private const val DEFAULT_FIRST_PANE_WIDTH = 220f +private const val DEFAULT_THIRD_PANE_WIDTH = 330f const val DEFAULT_UI_SCALE = -1f @Singleton @@ -209,6 +213,22 @@ class AppSettingsRepository @Inject constructor() { _cacheCredentialsInMemoryFlow.value = value } + var firstPaneWidth: Float + get() { + return preferences.getFloat(PREF_FIRST_PANE_WIDTH, DEFAULT_FIRST_PANE_WIDTH) + } + set(value) { + preferences.putFloat(PREF_FIRST_PANE_WIDTH, value) + } + + var thirdPaneWidth: Float + get() { + return preferences.getFloat(PREF_THIRD_PANE_WIDTH, DEFAULT_THIRD_PANE_WIDTH) + } + set(value) { + preferences.putFloat(PREF_THIRD_PANE_WIDTH, value) + } + var verifySsl: Boolean get() { return preferences.getBoolean(PREF_VERIFY_SSL, DEFAULT_VERIFY_SSL) diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt index 21276b2..604c81d 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt @@ -30,6 +30,8 @@ import com.jetpackduba.gitnuro.ui.log.Log import com.jetpackduba.gitnuro.updates.Update import com.jetpackduba.gitnuro.viewmodels.BlameState import com.jetpackduba.gitnuro.viewmodels.TabViewModel +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch import org.eclipse.jgit.lib.RepositoryState import org.eclipse.jgit.revwalk.RevCommit import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi @@ -264,9 +266,19 @@ fun MainContentView( ) { val rebaseInteractiveState by tabViewModel.rebaseInteractiveState.collectAsState() val density = LocalDensity.current.density + val scope = rememberCoroutineScope() - var firstWidth by remember(tabViewModel) { mutableStateOf(tabViewModel.firstPaneWidth) } - var thirdWidth by remember(tabViewModel) { mutableStateOf(tabViewModel.thirdPaneWidth) } + // We create 2 mutableStates here because using directly the flow makes compose lose some drag events for some reason + var firstWidth by remember(tabViewModel) { mutableStateOf(tabViewModel.firstPaneWidth.value) } + var thirdWidth by remember(tabViewModel) { mutableStateOf(tabViewModel.thirdPaneWidth.value) } + + LaunchedEffect(Unit) { + // Update the pane widths if they have been changed in a different tab + tabViewModel.onPanelsWidthPersisted.collectLatest { + firstWidth = tabViewModel.firstPaneWidth.value + thirdWidth = tabViewModel.thirdPaneWidth.value + } + } TripleVerticalSplitPanel( modifier = Modifier.fillMaxSize(), @@ -391,7 +403,12 @@ fun MainContentView( if (newWidth > 150 && rebaseInteractiveState !is RebaseInteractiveState.AwaitingInteraction) { firstWidth = newWidth - tabViewModel.firstPaneWidth = firstWidth + tabViewModel.setFirstPaneWidth(newWidth) + } + }, + onFirstSizeDragStopped = { + scope.launch { + tabViewModel.persistFirstPaneWidth() } }, onThirdSizeDrag = { @@ -399,7 +416,12 @@ fun MainContentView( if (newWidth > 150) { thirdWidth = newWidth - tabViewModel.thirdPaneWidth = thirdWidth + tabViewModel.setThirdPaneWidth(newWidth) + } + }, + onThirdSizeDragStopped = { + scope.launch { + tabViewModel.persistThirdPaneWidth() } }, ) diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/VerticalSplitPaneConfig.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/VerticalSplitPaneConfig.kt new file mode 100644 index 0000000..4842770 --- /dev/null +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/VerticalSplitPaneConfig.kt @@ -0,0 +1,51 @@ +package com.jetpackduba.gitnuro.ui + +import com.jetpackduba.gitnuro.repositories.AppSettingsRepository +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject +import javax.inject.Singleton + +interface IVerticalSplitPaneConfig { + val firstPaneWidth: StateFlow + val onPanelsWidthPersisted: SharedFlow + val thirdPaneWidth: StateFlow + fun setFirstPaneWidth(firstPaneWidth: Float) + fun setThirdPaneWidth(thirdPaneWidth: Float) + suspend fun persistFirstPaneWidth() + suspend fun persistThirdPaneWidth() +} + +@Singleton +class VerticalSplitPaneConfig @Inject constructor( + private val appSettingsRepository: AppSettingsRepository, +) : IVerticalSplitPaneConfig { + private val _firstPaneWidth = MutableStateFlow(appSettingsRepository.firstPaneWidth) + override val firstPaneWidth: StateFlow = _firstPaneWidth + + private val _thirdPaneWidth = MutableStateFlow(appSettingsRepository.thirdPaneWidth) + override val thirdPaneWidth: StateFlow = _thirdPaneWidth + + private val _onPanelsWidthPersisted = MutableSharedFlow() + override val onPanelsWidthPersisted: SharedFlow = _onPanelsWidthPersisted + + override fun setFirstPaneWidth(firstPaneWidth: Float) { + this._firstPaneWidth.value = firstPaneWidth + } + + override fun setThirdPaneWidth(thirdPaneWidth: Float) { + this._thirdPaneWidth.value = thirdPaneWidth + } + + override suspend fun persistFirstPaneWidth() { + appSettingsRepository.firstPaneWidth = _firstPaneWidth.value + _onPanelsWidthPersisted.emit(Unit) + } + + override suspend fun persistThirdPaneWidth() { + appSettingsRepository.thirdPaneWidth = _thirdPaneWidth.value + _onPanelsWidthPersisted.emit(Unit) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/TripleVerticalSplitPanel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/TripleVerticalSplitPanel.kt index d71ba47..727505f 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/TripleVerticalSplitPanel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/TripleVerticalSplitPanel.kt @@ -3,10 +3,7 @@ package com.jetpackduba.gitnuro.ui.components import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.draggable import androidx.compose.foundation.gestures.rememberDraggableState -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.input.pointer.pointerHoverIcon @@ -22,13 +19,18 @@ fun TripleVerticalSplitPanel( firstWidth: Float, thirdWidth: Float, onFirstSizeDrag: (Float) -> Unit, + onFirstSizeDragStopped: (Float) -> Unit, onThirdSizeDrag: (Float) -> Unit, + onThirdSizeDragStopped: (Float) -> Unit, ) { Row( modifier = modifier ) { if (firstWidth > 0) { - Box(modifier = Modifier.width(firstWidth.dp)) { + Box( + modifier = Modifier + .width(firstWidth.dp) + ) { first() } Box( @@ -39,13 +41,19 @@ fun TripleVerticalSplitPanel( state = rememberDraggableState { onFirstSizeDrag(it) }, - orientation = Orientation.Horizontal + orientation = Orientation.Horizontal, + onDragStopped = { + onFirstSizeDragStopped(it) + }, ) .pointerHoverIcon(resizePointerIconEast) ) } - Box(Modifier.weight(1f, true)) { + Box( + Modifier + .weight(1f, true) + ) { second() } @@ -54,14 +62,21 @@ fun TripleVerticalSplitPanel( .fillMaxHeight() .width(8.dp) .draggable( - rememberDraggableState { + state = rememberDraggableState { onThirdSizeDrag(it) - }, Orientation.Horizontal + }, + orientation = Orientation.Horizontal, + onDragStopped = { + onThirdSizeDragStopped(it) + }, ) .pointerHoverIcon(resizePointerIconEast) ) - Box(modifier = Modifier.width(thirdWidth.dp)) { + Box( + modifier = Modifier + .width(thirdWidth.dp) + ) { third() } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt index 6a44fa9..4c478c7 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt @@ -22,8 +22,10 @@ import com.jetpackduba.gitnuro.models.AuthorInfoSimple import com.jetpackduba.gitnuro.system.OpenFilePickerUseCase import com.jetpackduba.gitnuro.system.OpenUrlInBrowserUseCase import com.jetpackduba.gitnuro.system.PickerType +import com.jetpackduba.gitnuro.ui.IVerticalSplitPaneConfig import com.jetpackduba.gitnuro.ui.SelectedItem import com.jetpackduba.gitnuro.ui.TabsManager +import com.jetpackduba.gitnuro.ui.VerticalSplitPaneConfig import com.jetpackduba.gitnuro.updates.Update import com.jetpackduba.gitnuro.updates.UpdatesRepository import kotlinx.coroutines.* @@ -69,10 +71,9 @@ class TabViewModel @Inject constructor( private val sharedRepositoryStateManager: SharedRepositoryStateManager, private val tabsManager: TabsManager, private val tabScope: CoroutineScope, + private val verticalSplitPaneConfig: VerticalSplitPaneConfig, val tabViewModelsProvider: TabViewModelsProvider, -) { - var firstPaneWidth = 220f - var thirdPaneWidth = 360f +) : IVerticalSplitPaneConfig by verticalSplitPaneConfig { var initialPath: String? = null // Stores the path that should be opened when the tab is selected val errorsManager: ErrorsManager = tabState.errorsManager val selectedItem: StateFlow = tabState.selectedItem