From cd592292d1277686ef4cc87759b8969c86048bf7 Mon Sep 17 00:00:00 2001 From: Abdelilah El Aissaoui Date: Sat, 16 Oct 2021 03:39:59 +0200 Subject: [PATCH] Improved welcome/new tab page --- src/main/kotlin/app/App.kt | 4 - src/main/kotlin/app/AppPreferences.kt | 14 +- src/main/kotlin/app/AppStateManager.kt | 41 +++- .../kotlin/app/extensions/StringExtensions.kt | 21 +++ src/main/kotlin/app/git/GitManager.kt | 7 +- src/main/kotlin/app/ui/SystemDialogs.kt | 3 +- src/main/kotlin/app/ui/WelcomePage.kt | 175 ++++++++++++++++-- src/main/resources/bug.svg | 1 + src/main/resources/code.svg | 1 + 9 files changed, 222 insertions(+), 45 deletions(-) create mode 100644 src/main/resources/bug.svg create mode 100644 src/main/resources/code.svg diff --git a/src/main/kotlin/app/App.kt b/src/main/kotlin/app/App.kt index aca37fc..349a59b 100644 --- a/src/main/kotlin/app/App.kt +++ b/src/main/kotlin/app/App.kt @@ -200,11 +200,7 @@ fun App(gitManager: GitManager, repositoryPath: String?, tabName: MutableState() val openRepositoriesPathsTabs: Map get() = _openRepositoriesPaths + private val _latestOpenedRepositoriesPaths = mutableListOf() + val latestOpenedRepositoriesPaths: List + get() = _latestOpenedRepositoriesPaths + 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 - } + val latestOpenedRepositoryPath: String + get() = _latestOpenedRepositoriesPaths.firstOrNull() ?: "" - fun repositoryTabChanged(key: Int, path: String) { - _openRepositoriesPaths[key] = path + fun repositoryTabChanged(key: Int, path: String) = appStateScope.launch(Dispatchers.IO) { + // Do not save already saved repos + if (!_openRepositoriesPaths.containsValue(path)) + _openRepositoriesPaths[key] = path + + // Remove any previously existing path + _latestOpenedRepositoriesPaths.remove(path) + + // Add the latest one to the beginning + _latestOpenedRepositoriesPaths.add(0, path) + + if (_latestOpenedRepositoriesPaths.count() > 5) + _latestOpenedRepositoriesPaths.removeLast() updateSavedRepositoryTabs() + updateLatestRepositoryTabs() } - fun repositoryTabRemoved(key: Int) { + fun repositoryTabRemoved(key: Int) = appStateScope.launch(Dispatchers.IO) { _openRepositoriesPaths.remove(key) updateSavedRepositoryTabs() } - private fun updateSavedRepositoryTabs() = appStateScope.launch(Dispatchers.IO) { + private suspend fun updateSavedRepositoryTabs() = withContext(Dispatchers.IO) { val tabsList = _openRepositoriesPaths.map { it.value } appPreferences.latestTabsOpened = Json.encodeToString(tabsList) } + private suspend fun updateLatestRepositoryTabs() = withContext(Dispatchers.IO) { + appPreferences.latestOpenedRepositoriesPath = Json.encodeToString(_latestOpenedRepositoriesPaths) + } + fun loadRepositoriesTabs() = appStateScope.launch(Dispatchers.IO) { val repositoriesSaved = appPreferences.latestTabsOpened @@ -52,5 +68,10 @@ class AppStateManager @Inject constructor( } } + val repositoriesPathsSaved = appPreferences.latestOpenedRepositoriesPath + if(repositoriesPathsSaved.isNotEmpty()) { + val repositories = Json.decodeFromString>(repositoriesPathsSaved) + _latestOpenedRepositoriesPaths.addAll(repositories) + } } } \ No newline at end of file diff --git a/src/main/kotlin/app/extensions/StringExtensions.kt b/src/main/kotlin/app/extensions/StringExtensions.kt index 75eb57f..364cade 100644 --- a/src/main/kotlin/app/extensions/StringExtensions.kt +++ b/src/main/kotlin/app/extensions/StringExtensions.kt @@ -7,4 +7,25 @@ val String.md5: String get() { val md = MessageDigest.getInstance("MD5") return BigInteger(1, md.digest(this.toByteArray())).toString(16).padStart(32, '0') +} + +val String.dirName: String +get() { + val parts = this.split("/") + + return if(parts.isNotEmpty()) + parts.last() + else + this +} + +val String.dirPath: String +get() { + val parts = this.split("/").toMutableList() + + return if(parts.count() > 1) { + parts.removeLast() + parts.joinToString("/") + } else + this } \ No newline at end of file diff --git a/src/main/kotlin/app/git/GitManager.kt b/src/main/kotlin/app/git/GitManager.kt index a4c4175..3e81a15 100644 --- a/src/main/kotlin/app/git/GitManager.kt +++ b/src/main/kotlin/app/git/GitManager.kt @@ -11,7 +11,6 @@ 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.AppPreferences import app.AppStateManager import java.io.File import javax.inject.Inject @@ -24,7 +23,7 @@ class GitManager @Inject constructor( private val branchesManager: BranchesManager, private val stashManager: StashManager, private val diffManager: DiffManager, - private val appStateManager: AppStateManager, + val appStateManager: AppStateManager, ) { val repositoryName: String get() = safeGit.repository.directory.parentFile.name @@ -63,9 +62,6 @@ class GitManager @Inject constructor( val credentialsState: StateFlow get() = credentialsStateManager.credentialsState - val latestOpenedRepositoryPath: String - get() = appStateManager.latestOpenedRepositoryPath - private var git: Git? = null val safeGit: Git @@ -109,7 +105,6 @@ class GitManager @Inject constructor( git = Git(repository) onRepositoryChanged(repository.directory.parent) - appStateManager.latestOpenedRepositoryPath = directory.absolutePath refreshRepositoryInfo() } catch (ex: Exception) { ex.printStackTrace() diff --git a/src/main/kotlin/app/ui/SystemDialogs.kt b/src/main/kotlin/app/ui/SystemDialogs.kt index 7a67166..6d88ddd 100644 --- a/src/main/kotlin/app/ui/SystemDialogs.kt +++ b/src/main/kotlin/app/ui/SystemDialogs.kt @@ -2,7 +2,8 @@ import app.git.GitManager import javax.swing.JFileChooser fun openRepositoryDialog(gitManager: GitManager) { - val latestDirectoryOpened = gitManager.latestOpenedRepositoryPath + val appStateManager = gitManager.appStateManager + val latestDirectoryOpened = appStateManager.latestOpenedRepositoryPath val fileChooser = if (latestDirectoryOpened.isEmpty()) JFileChooser() diff --git a/src/main/kotlin/app/ui/WelcomePage.kt b/src/main/kotlin/app/ui/WelcomePage.kt index 5854b8d..e473446 100644 --- a/src/main/kotlin/app/ui/WelcomePage.kt +++ b/src/main/kotlin/app/ui/WelcomePage.kt @@ -1,7 +1,10 @@ package app.ui import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -11,56 +14,194 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import app.git.GitManager import openRepositoryDialog +import androidx.compose.foundation.lazy.items +import androidx.compose.ui.Alignment +import androidx.compose.ui.BiasAlignment +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.sp +import app.extensions.dirName +import app.extensions.dirPath +import app.theme.primaryTextColor +import app.theme.secondaryTextColor +import java.awt.Desktop +import java.net.URI @Composable fun WelcomePage(gitManager: GitManager) { + val appStateManager = gitManager.appStateManager + Row( modifier = Modifier .fillMaxSize(), horizontalArrangement = Arrangement.Center, + verticalAlignment = BiasAlignment.Vertical(-0.5f), ) { Column( modifier = Modifier - .fillMaxHeight(), + .padding(end = 32.dp), verticalArrangement = Arrangement.Center, ) { + Text( + text = "Gitnuro", + fontSize = 32.sp, + modifier = Modifier + .padding(bottom = 16.dp), + ) + ButtonTile( - title = "Open repository", + modifier = Modifier + .padding(bottom = 8.dp), + title = "Open a repository", painter = painterResource("open.svg"), onClick = { openRepositoryDialog(gitManager) } ) ButtonTile( - title = "Clone repository", + modifier = Modifier + .padding(bottom = 8.dp), + title = "Clone a repository", painter = painterResource("open.svg"), - onClick = {} + onClick = { } ) + + ButtonTile( + modifier = Modifier + .padding(bottom = 8.dp), + title = "Start a local repository", + painter = painterResource("open.svg"), + onClick = { } + ) + + Text( + text = "About Gitnuro", + fontSize = 18.sp, + modifier = Modifier + .padding(top = 16.dp, bottom = 8.dp), + ) + + IconTextButton( + title = "Source code", + painter = painterResource("code.svg"), + onClick = { + Desktop.getDesktop().browse(URI("https://github.com/aeab13/Gitnuro")) + } + ) + + IconTextButton( + title = "Report a bug", + painter = painterResource("bug.svg"), + onClick = { + Desktop.getDesktop().browse(URI("https://github.com/aeab13/Gitnuro/issues")) + } + ) + } + + Column( + modifier = Modifier + .padding(start = 32.dp), + ) { + + Text( + text = "Recent", + fontSize = 18.sp, + modifier = Modifier + .padding(top = 16.dp, bottom = 8.dp), + ) + LazyColumn { + items(items = appStateManager.latestOpenedRepositoriesPaths) { repo -> + val repoDirName = repo.dirName + val repoDirPath = repo.dirPath + + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + TextButton( + onClick = { + gitManager.openRepository(repo) + } + ) { + Text( + text = repoDirName, + fontSize = 14.sp, + color = MaterialTheme.colors.primary, + ) + } + + Text( + text = repoDirPath, + fontSize = 14.sp, + modifier = Modifier.padding(start = 4.dp), + color = MaterialTheme.colors.secondaryTextColor + ) + } + + } + } } } } @Composable fun ButtonTile( + modifier: Modifier = Modifier, title: String, painter: Painter, onClick: () -> Unit, ) { OutlinedButton( onClick = onClick, - modifier = Modifier.size(width = 200.dp, height = 56.dp) + modifier = modifier.size(width = 280.dp, height = 56.dp) ) { - Image( - modifier = Modifier - .size(24.dp) - .padding(end = 8.dp), - painter = painter, - contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colors.primary), - ) + Row( + modifier = Modifier.fillMaxSize(), + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + modifier = Modifier + .padding(end = 8.dp) + .size(24.dp), + painter = painter, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colors.primary), + ) - Text( - text = title, - ) + Text( + text = title, + ) + } } -} \ No newline at end of file +} + +@Composable +fun IconTextButton( + modifier: Modifier = Modifier, + title: String, + painter: Painter, + onClick: () -> Unit, +) { + TextButton( + onClick = onClick, + modifier = modifier.size(width = 280.dp, height = 40.dp) + ) { + Row( + modifier = Modifier + .fillMaxSize(), + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + modifier = Modifier + .padding(end = 8.dp) + .size(24.dp), + painter = painter, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colors.primary), + ) + + Text( + text = title, + ) + } + } +} + diff --git a/src/main/resources/bug.svg b/src/main/resources/bug.svg new file mode 100644 index 0000000..ca5a1c3 --- /dev/null +++ b/src/main/resources/bug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/code.svg b/src/main/resources/code.svg new file mode 100644 index 0000000..5728238 --- /dev/null +++ b/src/main/resources/code.svg @@ -0,0 +1 @@ + \ No newline at end of file