Now opened tabs will be saved

This commit is contained in:
Abdelilah El Aissaoui 2021-10-15 02:34:26 +02:00
parent 5f1f015be6
commit fda901c0f2
8 changed files with 142 additions and 47 deletions

View File

@ -6,6 +6,7 @@ plugins {
// __KOTLIN_COMPOSE_VERSION__ // __KOTLIN_COMPOSE_VERSION__
kotlin("jvm") version "1.5.21" kotlin("jvm") version "1.5.21"
kotlin("kapt") version "1.5.21" kotlin("kapt") version "1.5.21"
kotlin("plugin.serialization") version "1.5.21"
// __LATEST_COMPOSE_RELEASE_VERSION__ // __LATEST_COMPOSE_RELEASE_VERSION__
id("org.jetbrains.compose") version "1.0.0-alpha3" id("org.jetbrains.compose") version "1.0.0-alpha3"
} }
@ -27,6 +28,7 @@ dependencies {
implementation("org.apache.sshd:sshd-core:2.7.0") implementation("org.apache.sshd:sshd-core:2.7.0")
implementation("com.google.dagger:dagger:2.39.1") implementation("com.google.dagger:dagger:2.39.1")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.5.21") implementation("org.jetbrains.kotlin:kotlin-reflect:1.5.21")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0")
kapt("com.google.dagger:dagger-compiler:2.39.1") kapt("com.google.dagger:dagger-compiler:2.39.1")
} }

View File

@ -29,13 +29,18 @@ class Main {
@Inject @Inject
lateinit var gitManagerProvider: Provider<GitManager> lateinit var gitManagerProvider: Provider<GitManager>
@Inject
lateinit var appStateManager: AppStateManager
init { init {
appComponent.inject(this) appComponent.inject(this)
appStateManager.loadRepositoriesTabs()
} }
fun start() = application { fun start() = application {
var isOpen by remember { mutableStateOf(true) } var isOpen by remember { mutableStateOf(true) }
if (isOpen) { if (isOpen) {
Window( Window(
title = "Gitnuro", title = "Gitnuro",
@ -49,15 +54,19 @@ class Main {
) { ) {
AppTheme { AppTheme {
val tabs = remember { val tabs = remember {
val tabName = mutableStateOf("New tab")
mutableStateOf( val repositoriesSavedTabs = appStateManager.openRepositoriesPathsTabs
listOf( var repoTabs = repositoriesSavedTabs.map { repositoryTab ->
TabInformation(tabName, key = 0) { newAppTab(key = repositoryTab.key, path = repositoryTab.value)
val gitManager = remember { gitManagerProvider.get() } }
Gitnuro(gitManager, false, tabName)
}, if (repoTabs.isEmpty()) {
repoTabs = listOf(
newAppTab()
) )
) }
mutableStateOf(repoTabs)
} }
var selectedTabKey by remember { mutableStateOf(0) } var selectedTabKey by remember { mutableStateOf(0) }
@ -74,12 +83,14 @@ class Main {
onTabSelected = { newSelectedTabKey -> onTabSelected = { newSelectedTabKey ->
selectedTabKey = newSelectedTabKey selectedTabKey = newSelectedTabKey
}, },
newTabContent = { tabName -> newTabContent = { key ->
val gitManager = remember { gitManagerProvider.get() } newAppTab(key)
Gitnuro(gitManager, true, tabName)
}, },
onTabsUpdated = { tabInformationList -> onTabsUpdated = { tabInformationList ->
tabs.value = tabInformationList tabs.value = tabInformationList
},
onTabClosed = { key ->
appStateManager.repositoryTabRemoved(key)
} }
) )
@ -111,13 +122,35 @@ class Main {
} }
} }
} }
private fun newAppTab(
key: Int = 0,
tabName: MutableState<String> = mutableStateOf("New tab"),
path: String? = null,
): TabInformation {
return TabInformation(
title = tabName,
key = key
) {
val gitManager = remember { gitManagerProvider.get() }
gitManager.onRepositoryChanged = { path ->
if (path == null) {
appStateManager.repositoryTabRemoved(key)
} else
appStateManager.repositoryTabChanged(key, path)
}
Gitnuro(gitManager, path, tabName)
}
}
} }
@Composable @Composable
fun Gitnuro(gitManager: GitManager, isNewTab: Boolean, tabName: MutableState<String>) { fun Gitnuro(gitManager: GitManager, repositoryPath: String?, tabName: MutableState<String>) {
LaunchedEffect(gitManager) { LaunchedEffect(gitManager) {
if (!isNewTab) if (repositoryPath != null)
gitManager.loadLatestOpenedRepository() gitManager.openRepository(repositoryPath)
} }

View File

@ -2,14 +2,23 @@ package app
import java.util.prefs.Preferences import java.util.prefs.Preferences
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton
private const val PREFERENCES_NAME = "GitnuroConfig" private const val PREFERENCES_NAME = "GitnuroConfig"
private const val PREF_LATEST_REPOSITORIES_OPENED = "latestRepositoriesOpened"
private const val PREF_LAST_OPENED_REPOSITORY_PATH = "lastOpenedRepositoryPath" private const val PREF_LAST_OPENED_REPOSITORY_PATH = "lastOpenedRepositoryPath"
class GPreferences @Inject constructor() { @Singleton
class AppPreferences @Inject constructor() {
private val preferences: Preferences = Preferences.userRoot().node(PREFERENCES_NAME) private val preferences: Preferences = Preferences.userRoot().node(PREFERENCES_NAME)
var latestTabsOpened: String
get() = preferences.get(PREF_LATEST_REPOSITORIES_OPENED, "")
set(value) {
preferences.put(PREF_LATEST_REPOSITORIES_OPENED, value)
}
var latestOpenedRepositoryPath: String var latestOpenedRepositoryPath: String
get() = preferences.get(PREF_LAST_OPENED_REPOSITORY_PATH, "") get() = preferences.get(PREF_LAST_OPENED_REPOSITORY_PATH, "")
set(value) { set(value) {

View File

@ -0,0 +1,56 @@
package app
import kotlinx.coroutines.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AppStateManager @Inject constructor(
private val appPreferences: AppPreferences,
) {
private val _openRepositoriesPaths = mutableMapOf<Int, String>()
val openRepositoriesPathsTabs: Map<Int, String>
get() = _openRepositoriesPaths
private val appStateScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) // TODO Stop this when closing the app
var latestOpenedRepositoryPath: String
get() = appPreferences.latestOpenedRepositoryPath
set(value) {
appPreferences.latestOpenedRepositoryPath = value
}
fun repositoryTabChanged(key: Int, path: String) {
_openRepositoriesPaths[key] = path
updateSavedRepositoryTabs()
}
fun repositoryTabRemoved(key: Int) {
_openRepositoriesPaths.remove(key)
updateSavedRepositoryTabs()
}
private fun updateSavedRepositoryTabs() = appStateScope.launch(Dispatchers.IO) {
val tabsList = _openRepositoriesPaths.map { it.value }
appPreferences.latestTabsOpened = Json.encodeToString(tabsList)
}
fun loadRepositoriesTabs() = appStateScope.launch(Dispatchers.IO) {
val repositoriesSaved = appPreferences.latestTabsOpened
if (repositoriesSaved.isNotEmpty()) {
val repositoriesList = Json.decodeFromString<List<String>>(repositoriesSaved)
repositoriesList.forEachIndexed { index, repository ->
_openRepositoriesPaths[index] = repository
}
}
}
}

View File

@ -2,7 +2,9 @@ package app.di
import app.Main import app.Main
import dagger.Component import dagger.Component
import javax.inject.Singleton
@Singleton
@Component @Component
interface AppComponent { interface AppComponent {
fun inject(main: Main) fun inject(main: Main)

View File

@ -11,19 +11,20 @@ import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.revwalk.RevCommit import org.eclipse.jgit.revwalk.RevCommit
import org.eclipse.jgit.storage.file.FileRepositoryBuilder import org.eclipse.jgit.storage.file.FileRepositoryBuilder
import app.GPreferences import app.AppPreferences
import app.AppStateManager
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
class GitManager @Inject constructor( class GitManager @Inject constructor(
private val preferences: GPreferences,
private val statusManager: StatusManager, private val statusManager: StatusManager,
private val logManager: LogManager, private val logManager: LogManager,
private val remoteOperationsManager: RemoteOperationsManager, private val remoteOperationsManager: RemoteOperationsManager,
private val branchesManager: BranchesManager, private val branchesManager: BranchesManager,
private val stashManager: StashManager, private val stashManager: StashManager,
private val diffManager: DiffManager, private val diffManager: DiffManager,
private val appStateManager: AppStateManager,
) { ) {
val repositoryName: String val repositoryName: String
get() = safeGit.repository.directory.parentFile.name get() = safeGit.repository.directory.parentFile.name
@ -59,12 +60,12 @@ class GitManager @Inject constructor(
val stashStatus: StateFlow<StashStatus> val stashStatus: StateFlow<StashStatus>
get() = stashManager.stashStatus get() = stashManager.stashStatus
val latestDirectoryOpened: File?
get() = File(preferences.latestOpenedRepositoryPath).parentFile
val credentialsState: StateFlow<CredentialsState> val credentialsState: StateFlow<CredentialsState>
get() = credentialsStateManager.credentialsState get() = credentialsStateManager.credentialsState
val latestOpenedRepositoryPath: String
get() = appStateManager.latestOpenedRepositoryPath
private var git: Git? = null private var git: Git? = null
val safeGit: Git val safeGit: Git
@ -77,12 +78,8 @@ class GitManager @Inject constructor(
return git return git
} }
fun openRepository(directory: String) {
suspend fun loadLatestOpenedRepository() = withContext(Dispatchers.IO) { openRepository(File(directory))
val latestOpenedRepositoryPath = preferences.latestOpenedRepositoryPath
if (latestOpenedRepositoryPath.isNotEmpty()) {
openRepository(File(latestOpenedRepositoryPath))
}
} }
fun openRepository(directory: File) { fun openRepository(directory: File) {
@ -107,13 +104,16 @@ class GitManager @Inject constructor(
try { try {
repository.workTree // test if repository is valid repository.workTree // test if repository is valid
preferences.latestOpenedRepositoryPath = gitDirectory.path
_repositorySelectionStatus.value = RepositorySelectionStatus.Open(repository) _repositorySelectionStatus.value = RepositorySelectionStatus.Open(repository)
git = Git(repository) git = Git(repository)
onRepositoryChanged(repository.directory.parent)
appStateManager.latestOpenedRepositoryPath = directory.absolutePath
refreshRepositoryInfo() refreshRepositoryInfo()
} catch (ex: Exception) { } catch (ex: Exception) {
ex.printStackTrace() ex.printStackTrace()
onRepositoryChanged(null)
} }
} }
@ -213,6 +213,8 @@ class GitManager @Inject constructor(
fun stageAll() = managerScope.launch { fun stageAll() = managerScope.launch {
statusManager.stageAll(safeGit) statusManager.stageAll(safeGit)
} }
var onRepositoryChanged: (path: String?) -> Unit = {}
} }

View File

@ -2,16 +2,16 @@ import app.git.GitManager
import javax.swing.JFileChooser import javax.swing.JFileChooser
fun openRepositoryDialog(gitManager: GitManager) { fun openRepositoryDialog(gitManager: GitManager) {
val latestDirectoryOpened = gitManager.latestDirectoryOpened val latestDirectoryOpened = gitManager.latestOpenedRepositoryPath
val f = if (latestDirectoryOpened == null) val fileChooser = if (latestDirectoryOpened.isEmpty())
JFileChooser() JFileChooser()
else else
JFileChooser(latestDirectoryOpened) JFileChooser(latestDirectoryOpened)
f.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY fileChooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
f.showSaveDialog(null) fileChooser.showSaveDialog(null)
if (f.selectedFile != null) if (fileChooser.selectedFile != null)
gitManager.openRepository(f.selectedFile) gitManager.openRepository(fileChooser.selectedFile)
} }

View File

@ -14,8 +14,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import app.theme.primaryLight
import app.theme.primaryTextColor
import app.theme.tabColorActive import app.theme.tabColorActive
import app.theme.tabColorInactive import app.theme.tabColorInactive
@ -27,7 +25,8 @@ fun RepositoriesTabPanel(
selectedTabKey: Int, selectedTabKey: Int,
onTabSelected: (Int) -> Unit, onTabSelected: (Int) -> Unit,
onTabsUpdated: (List<TabInformation>) -> Unit, onTabsUpdated: (List<TabInformation>) -> Unit,
newTabContent: @Composable (tabTitle: MutableState<String>) -> Unit, onTabClosed: (Int) -> Unit,
newTabContent: (key: Int) -> TabInformation,
) { ) {
var tabsIdentifier by remember { var tabsIdentifier by remember {
mutableStateOf(tabs.count()) mutableStateOf(tabs.count())
@ -40,13 +39,7 @@ fun RepositoriesTabPanel(
tabsIdentifier++ tabsIdentifier++
val tabName = mutableStateOf("New tab") tabsCopy.add(newTabContent(tabsIdentifier))
tabsCopy.add(
TabInformation(tabName, key = tabsIdentifier) {
newTabContent(tabName)
}
)
onTabSelected(tabsIdentifier) onTabSelected(tabsIdentifier)
onTabsUpdated(tabsCopy) onTabsUpdated(tabsCopy)
@ -83,17 +76,15 @@ fun RepositoriesTabPanel(
} else { } else {
tabsIdentifier++ tabsIdentifier++
val tabName = mutableStateOf("New tab")
tabsCopy.add( tabsCopy.add(
TabInformation(tabName, key = tabsIdentifier) { newTabContent(tabsIdentifier)
newTabContent(tabName)
}
) )
onTabSelected(tabsIdentifier) onTabSelected(tabsIdentifier)
} }
} }
onTabClosed(tab.key)
onTabsUpdated(tabsCopy) onTabsUpdated(tabsCopy)
} }
) )