Now opened tabs will be saved
This commit is contained in:
parent
5f1f015be6
commit
fda901c0f2
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,17 +54,21 @@ 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) }
|
||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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) {
|
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 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)
|
||||||
|
@ -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 = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user