Now opened tabs will be saved
This commit is contained in:
parent
5f1f015be6
commit
fda901c0f2
8 changed files with 142 additions and 47 deletions
|
@ -6,6 +6,7 @@ plugins {
|
|||
// __KOTLIN_COMPOSE_VERSION__
|
||||
kotlin("jvm") version "1.5.21"
|
||||
kotlin("kapt") version "1.5.21"
|
||||
kotlin("plugin.serialization") version "1.5.21"
|
||||
// __LATEST_COMPOSE_RELEASE_VERSION__
|
||||
id("org.jetbrains.compose") version "1.0.0-alpha3"
|
||||
}
|
||||
|
@ -27,6 +28,7 @@ dependencies {
|
|||
implementation("org.apache.sshd:sshd-core:2.7.0")
|
||||
implementation("com.google.dagger:dagger:2.39.1")
|
||||
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")
|
||||
}
|
||||
|
||||
|
|
|
@ -29,13 +29,18 @@ class Main {
|
|||
@Inject
|
||||
lateinit var gitManagerProvider: Provider<GitManager>
|
||||
|
||||
@Inject
|
||||
lateinit var appStateManager: AppStateManager
|
||||
|
||||
init {
|
||||
appComponent.inject(this)
|
||||
|
||||
appStateManager.loadRepositoriesTabs()
|
||||
}
|
||||
|
||||
fun start() = application {
|
||||
var isOpen by remember { mutableStateOf(true) }
|
||||
|
||||
if (isOpen) {
|
||||
Window(
|
||||
title = "Gitnuro",
|
||||
|
@ -49,15 +54,19 @@ class Main {
|
|||
) {
|
||||
AppTheme {
|
||||
val tabs = remember {
|
||||
val tabName = mutableStateOf("New tab")
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
TabInformation(tabName, key = 0) {
|
||||
val gitManager = remember { gitManagerProvider.get() }
|
||||
Gitnuro(gitManager, false, tabName)
|
||||
},
|
||||
|
||||
val repositoriesSavedTabs = appStateManager.openRepositoriesPathsTabs
|
||||
var repoTabs = repositoriesSavedTabs.map { repositoryTab ->
|
||||
newAppTab(key = repositoryTab.key, path = repositoryTab.value)
|
||||
}
|
||||
|
||||
if (repoTabs.isEmpty()) {
|
||||
repoTabs = listOf(
|
||||
newAppTab()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
mutableStateOf(repoTabs)
|
||||
}
|
||||
|
||||
var selectedTabKey by remember { mutableStateOf(0) }
|
||||
|
@ -74,12 +83,14 @@ class Main {
|
|||
onTabSelected = { newSelectedTabKey ->
|
||||
selectedTabKey = newSelectedTabKey
|
||||
},
|
||||
newTabContent = { tabName ->
|
||||
val gitManager = remember { gitManagerProvider.get() }
|
||||
Gitnuro(gitManager, true, tabName)
|
||||
newTabContent = { key ->
|
||||
newAppTab(key)
|
||||
},
|
||||
onTabsUpdated = { 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
|
||||
fun Gitnuro(gitManager: GitManager, isNewTab: Boolean, tabName: MutableState<String>) {
|
||||
fun Gitnuro(gitManager: GitManager, repositoryPath: String?, tabName: MutableState<String>) {
|
||||
LaunchedEffect(gitManager) {
|
||||
if (!isNewTab)
|
||||
gitManager.loadLatestOpenedRepository()
|
||||
if (repositoryPath != null)
|
||||
gitManager.openRepository(repositoryPath)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,14 +2,23 @@ package app
|
|||
|
||||
import java.util.prefs.Preferences
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val PREFERENCES_NAME = "GitnuroConfig"
|
||||
|
||||
private const val PREF_LATEST_REPOSITORIES_OPENED = "latestRepositoriesOpened"
|
||||
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)
|
||||
|
||||
var latestTabsOpened: String
|
||||
get() = preferences.get(PREF_LATEST_REPOSITORIES_OPENED, "")
|
||||
set(value) {
|
||||
preferences.put(PREF_LATEST_REPOSITORIES_OPENED, value)
|
||||
}
|
||||
|
||||
var latestOpenedRepositoryPath: String
|
||||
get() = preferences.get(PREF_LAST_OPENED_REPOSITORY_PATH, "")
|
||||
set(value) {
|
56
src/main/kotlin/app/AppStateManager.kt
Normal file
56
src/main/kotlin/app/AppStateManager.kt
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@ package app.di
|
|||
|
||||
import app.Main
|
||||
import dagger.Component
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Component
|
||||
interface AppComponent {
|
||||
fun inject(main: Main)
|
||||
|
|
|
@ -11,19 +11,20 @@ import org.eclipse.jgit.lib.Ref
|
|||
import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.revwalk.RevCommit
|
||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
|
||||
import app.GPreferences
|
||||
import app.AppPreferences
|
||||
import app.AppStateManager
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class GitManager @Inject constructor(
|
||||
private val preferences: GPreferences,
|
||||
private val statusManager: StatusManager,
|
||||
private val logManager: LogManager,
|
||||
private val remoteOperationsManager: RemoteOperationsManager,
|
||||
private val branchesManager: BranchesManager,
|
||||
private val stashManager: StashManager,
|
||||
private val diffManager: DiffManager,
|
||||
private val appStateManager: AppStateManager,
|
||||
) {
|
||||
val repositoryName: String
|
||||
get() = safeGit.repository.directory.parentFile.name
|
||||
|
@ -59,12 +60,12 @@ class GitManager @Inject constructor(
|
|||
val stashStatus: StateFlow<StashStatus>
|
||||
get() = stashManager.stashStatus
|
||||
|
||||
val latestDirectoryOpened: File?
|
||||
get() = File(preferences.latestOpenedRepositoryPath).parentFile
|
||||
|
||||
val credentialsState: StateFlow<CredentialsState>
|
||||
get() = credentialsStateManager.credentialsState
|
||||
|
||||
val latestOpenedRepositoryPath: String
|
||||
get() = appStateManager.latestOpenedRepositoryPath
|
||||
|
||||
private var git: Git? = null
|
||||
|
||||
val safeGit: Git
|
||||
|
@ -77,12 +78,8 @@ class GitManager @Inject constructor(
|
|||
return git
|
||||
}
|
||||
|
||||
|
||||
suspend fun loadLatestOpenedRepository() = withContext(Dispatchers.IO) {
|
||||
val latestOpenedRepositoryPath = preferences.latestOpenedRepositoryPath
|
||||
if (latestOpenedRepositoryPath.isNotEmpty()) {
|
||||
openRepository(File(latestOpenedRepositoryPath))
|
||||
}
|
||||
fun openRepository(directory: String) {
|
||||
openRepository(File(directory))
|
||||
}
|
||||
|
||||
fun openRepository(directory: File) {
|
||||
|
@ -107,13 +104,16 @@ class GitManager @Inject constructor(
|
|||
|
||||
try {
|
||||
repository.workTree // test if repository is valid
|
||||
preferences.latestOpenedRepositoryPath = gitDirectory.path
|
||||
_repositorySelectionStatus.value = RepositorySelectionStatus.Open(repository)
|
||||
git = Git(repository)
|
||||
|
||||
onRepositoryChanged(repository.directory.parent)
|
||||
appStateManager.latestOpenedRepositoryPath = directory.absolutePath
|
||||
refreshRepositoryInfo()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
onRepositoryChanged(null)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,6 +213,8 @@ class GitManager @Inject constructor(
|
|||
fun stageAll() = managerScope.launch {
|
||||
statusManager.stageAll(safeGit)
|
||||
}
|
||||
|
||||
var onRepositoryChanged: (path: String?) -> Unit = {}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@ import app.git.GitManager
|
|||
import javax.swing.JFileChooser
|
||||
|
||||
fun openRepositoryDialog(gitManager: GitManager) {
|
||||
val latestDirectoryOpened = gitManager.latestDirectoryOpened
|
||||
val latestDirectoryOpened = gitManager.latestOpenedRepositoryPath
|
||||
|
||||
val f = if (latestDirectoryOpened == null)
|
||||
val fileChooser = if (latestDirectoryOpened.isEmpty())
|
||||
JFileChooser()
|
||||
else
|
||||
JFileChooser(latestDirectoryOpened)
|
||||
|
||||
f.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
|
||||
f.showSaveDialog(null)
|
||||
fileChooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
|
||||
fileChooser.showSaveDialog(null)
|
||||
|
||||
if (f.selectedFile != null)
|
||||
gitManager.openRepository(f.selectedFile)
|
||||
if (fileChooser.selectedFile != null)
|
||||
gitManager.openRepository(fileChooser.selectedFile)
|
||||
}
|
|
@ -14,8 +14,6 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.theme.primaryLight
|
||||
import app.theme.primaryTextColor
|
||||
import app.theme.tabColorActive
|
||||
import app.theme.tabColorInactive
|
||||
|
||||
|
@ -27,7 +25,8 @@ fun RepositoriesTabPanel(
|
|||
selectedTabKey: Int,
|
||||
onTabSelected: (Int) -> Unit,
|
||||
onTabsUpdated: (List<TabInformation>) -> Unit,
|
||||
newTabContent: @Composable (tabTitle: MutableState<String>) -> Unit,
|
||||
onTabClosed: (Int) -> Unit,
|
||||
newTabContent: (key: Int) -> TabInformation,
|
||||
) {
|
||||
var tabsIdentifier by remember {
|
||||
mutableStateOf(tabs.count())
|
||||
|
@ -40,13 +39,7 @@ fun RepositoriesTabPanel(
|
|||
|
||||
tabsIdentifier++
|
||||
|
||||
val tabName = mutableStateOf("New tab")
|
||||
|
||||
tabsCopy.add(
|
||||
TabInformation(tabName, key = tabsIdentifier) {
|
||||
newTabContent(tabName)
|
||||
}
|
||||
)
|
||||
tabsCopy.add(newTabContent(tabsIdentifier))
|
||||
|
||||
onTabSelected(tabsIdentifier)
|
||||
onTabsUpdated(tabsCopy)
|
||||
|
@ -83,17 +76,15 @@ fun RepositoriesTabPanel(
|
|||
} else {
|
||||
tabsIdentifier++
|
||||
|
||||
val tabName = mutableStateOf("New tab")
|
||||
tabsCopy.add(
|
||||
TabInformation(tabName, key = tabsIdentifier) {
|
||||
newTabContent(tabName)
|
||||
}
|
||||
newTabContent(tabsIdentifier)
|
||||
)
|
||||
|
||||
onTabSelected(tabsIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
onTabClosed(tab.key)
|
||||
onTabsUpdated(tabsCopy)
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue