Added basic tabs support
This commit is contained in:
parent
1433c0f601
commit
68917c40c9
@ -1,7 +1,8 @@
|
|||||||
package git
|
package git
|
||||||
|
|
||||||
import credentials.CredentialsState
|
import credentials.CredentialsState
|
||||||
import credentials.CredentialsStateManager import kotlinx.coroutines.*
|
import credentials.CredentialsStateManager
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
@ -15,6 +16,8 @@ import java.io.File
|
|||||||
|
|
||||||
|
|
||||||
class GitManager {
|
class GitManager {
|
||||||
|
val repositoryName: String
|
||||||
|
get() = safeGit.repository.directory.parentFile.name
|
||||||
private val preferences = GPreferences()
|
private val preferences = GPreferences()
|
||||||
private val statusManager = StatusManager()
|
private val statusManager = StatusManager()
|
||||||
private val logManager = LogManager()
|
private val logManager = LogManager()
|
||||||
@ -71,7 +74,8 @@ class GitManager {
|
|||||||
return git
|
return git
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
|
fun loadLatestOpenedRepository() {
|
||||||
val latestOpenedRepositoryPath = preferences.latestOpenedRepositoryPath
|
val latestOpenedRepositoryPath = preferences.latestOpenedRepositoryPath
|
||||||
if (latestOpenedRepositoryPath.isNotEmpty()) {
|
if (latestOpenedRepositoryPath.isNotEmpty()) {
|
||||||
openRepository(File(latestOpenedRepositoryPath))
|
openRepository(File(latestOpenedRepositoryPath))
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
@ -15,18 +24,19 @@ import androidx.compose.ui.res.painterResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.window.*
|
import androidx.compose.ui.window.*
|
||||||
|
import androidx.compose.ui.zIndex
|
||||||
import git.GitManager
|
import git.GitManager
|
||||||
import git.RepositorySelectionStatus
|
import git.RepositorySelectionStatus
|
||||||
import theme.*
|
import theme.*
|
||||||
import ui.RepositoryOpenPage
|
import ui.RepositoryOpenPage
|
||||||
import ui.WelcomePage
|
import ui.WelcomePage
|
||||||
|
import ui.components.RepositoriesTabPanel
|
||||||
|
import ui.components.TabInformation
|
||||||
import javax.swing.JFileChooser
|
import javax.swing.JFileChooser
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalComposeUiApi::class)
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
fun main() = application {
|
fun main() = application {
|
||||||
var isOpen by remember { mutableStateOf(true) }
|
var isOpen by remember { mutableStateOf(true) }
|
||||||
val gitManager = GitManager()
|
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
Window(
|
Window(
|
||||||
title = "Gitnuro",
|
title = "Gitnuro",
|
||||||
@ -36,18 +46,87 @@ fun main() = application {
|
|||||||
state = rememberWindowState(placement = WindowPlacement.Maximized, size = WindowSize(1280.dp, 720.dp))
|
state = rememberWindowState(placement = WindowPlacement.Maximized, size = WindowSize(1280.dp, 720.dp))
|
||||||
) {
|
) {
|
||||||
GitnuroTheme {
|
GitnuroTheme {
|
||||||
Gitnuro(gitManager)
|
val tabs = remember {
|
||||||
|
val tabName = mutableStateOf("New tab")
|
||||||
|
mutableStateOf(
|
||||||
|
listOf(
|
||||||
|
TabInformation(tabName, key = 0) {
|
||||||
|
Gitnuro(false, tabName)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedTabKey by remember { mutableStateOf(0) }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
RepositoriesTabPanel(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 4.dp, bottom = 2.dp, start = 4.dp, end = 4.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
tabs = tabs.value,
|
||||||
|
selectedTabKey = selectedTabKey,
|
||||||
|
onTabSelected = { newSelectedTabKey ->
|
||||||
|
selectedTabKey = newSelectedTabKey
|
||||||
|
},
|
||||||
|
newTabContent = { tabName ->
|
||||||
|
Gitnuro(true, tabName)
|
||||||
|
},
|
||||||
|
onTabsUpdated = { tabInformationList ->
|
||||||
|
tabs.value = tabInformationList
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(Color.Cyan)
|
||||||
|
) {
|
||||||
|
items(items = tabs.value, key = { it.key }) {
|
||||||
|
val isItemSelected = it.key == selectedTabKey
|
||||||
|
|
||||||
|
var tabMod: Modifier = if (!isItemSelected)
|
||||||
|
Modifier.size(0.dp)
|
||||||
|
else
|
||||||
|
Modifier
|
||||||
|
.fillParentMaxSize()
|
||||||
|
|
||||||
|
tabMod = tabMod.background(MaterialTheme.colors.primary)
|
||||||
|
.alpha(if (isItemSelected) 1f else -1f)
|
||||||
|
.zIndex(if (isItemSelected) 1f else -1f)
|
||||||
|
Box(
|
||||||
|
modifier = tabMod,
|
||||||
|
) {
|
||||||
|
it.content()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Gitnuro(gitManager: GitManager) {
|
fun Gitnuro(isNewTab: Boolean, tabName: MutableState<String>) {
|
||||||
|
val gitManager = remember {
|
||||||
|
GitManager().apply {
|
||||||
|
if (!isNewTab)
|
||||||
|
loadLatestOpenedRepository()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val repositorySelectionStatus by gitManager.repositorySelectionStatus.collectAsState()
|
val repositorySelectionStatus by gitManager.repositorySelectionStatus.collectAsState()
|
||||||
|
|
||||||
|
if (repositorySelectionStatus is RepositorySelectionStatus.Open) {
|
||||||
|
tabName.value = gitManager.repositoryName
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.background(MaterialTheme.colors.background)
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colors.background)
|
||||||
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
GMenu(
|
GMenu(
|
||||||
onRepositoryOpen = {
|
onRepositoryOpen = {
|
||||||
|
@ -32,6 +32,26 @@ fun WelcomePage() {
|
|||||||
Text("Open repository")
|
Text("Open repository")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button(onClick = {}) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource("open.svg"),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(contentColorFor(MaterialTheme.colors.primary))
|
||||||
|
|
||||||
|
)
|
||||||
|
Text("Clone repository")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(onClick = {}) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource("open.svg"),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(contentColorFor(MaterialTheme.colors.primary))
|
||||||
|
|
||||||
|
)
|
||||||
|
Text("Init a new repository")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
158
src/main/kotlin/ui/components/RepositoriesTabPanel.kt
Normal file
158
src/main/kotlin/ui/components/RepositoriesTabPanel.kt
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import theme.primaryLight
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RepositoriesTabPanel(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
tabs: List<TabInformation>,
|
||||||
|
selectedTabKey: Int,
|
||||||
|
onTabSelected: (Int) -> Unit,
|
||||||
|
onTabsUpdated: (List<TabInformation>) -> Unit,
|
||||||
|
newTabContent: @Composable (tabTitle: MutableState<String>) -> Unit,
|
||||||
|
) {
|
||||||
|
var tabsIdentifier by remember { mutableStateOf(0) }
|
||||||
|
|
||||||
|
TabPanel(
|
||||||
|
modifier = modifier,
|
||||||
|
onNewTabClicked = {
|
||||||
|
val tabsCopy = tabs.toMutableList()
|
||||||
|
|
||||||
|
tabsIdentifier++
|
||||||
|
|
||||||
|
val tabName = mutableStateOf("New tab")
|
||||||
|
|
||||||
|
tabsCopy.add(
|
||||||
|
TabInformation(tabName, key = tabsIdentifier) {
|
||||||
|
newTabContent(tabName)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
onTabSelected(tabsIdentifier)
|
||||||
|
onTabsUpdated(tabsCopy)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
tabs.forEach { tab ->
|
||||||
|
Tab(
|
||||||
|
title = tab.title,
|
||||||
|
selected = tab.key == selectedTabKey,
|
||||||
|
onClick = {
|
||||||
|
onTabSelected(tab.key)
|
||||||
|
},
|
||||||
|
onCloseTab = {
|
||||||
|
val isTabSelected = selectedTabKey == tab.key
|
||||||
|
val index = tabs.indexOf(tab)
|
||||||
|
val nextIndex = if (index == 0 && tabs.count() >= 2) {
|
||||||
|
0
|
||||||
|
} else if (tabs.count() >= 2)
|
||||||
|
index - 1
|
||||||
|
else
|
||||||
|
-1
|
||||||
|
|
||||||
|
val tabsCopy = tabs.toMutableList()
|
||||||
|
tabsCopy.remove(tab)
|
||||||
|
|
||||||
|
val nextKey = if (nextIndex >= 0)
|
||||||
|
tabsCopy[nextIndex].key
|
||||||
|
else
|
||||||
|
-1
|
||||||
|
|
||||||
|
if (isTabSelected) {
|
||||||
|
if (nextKey >= 0) {
|
||||||
|
onTabSelected(nextKey)
|
||||||
|
} else {
|
||||||
|
tabsIdentifier++
|
||||||
|
|
||||||
|
val tabName = mutableStateOf("New tab")
|
||||||
|
tabsCopy.add(
|
||||||
|
TabInformation(tabName, key = tabsIdentifier) {
|
||||||
|
newTabContent(tabName)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
onTabSelected(tabsIdentifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTabsUpdated(tabsCopy)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TabPanel(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onNewTabClicked: () -> Unit,
|
||||||
|
tabs: @Composable RowScope.() -> Unit
|
||||||
|
) {
|
||||||
|
Row(modifier = modifier) {
|
||||||
|
this.tabs()
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
onClick = onNewTabClicked,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(36.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Add,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colors.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Tab(title: MutableState<String>, selected: Boolean, onClick: () -> Unit, onCloseTab: () -> Unit) {
|
||||||
|
Card {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 1.dp)
|
||||||
|
.height(36.dp)
|
||||||
|
.clip(RoundedCornerShape(5.dp))
|
||||||
|
.background(if (selected) MaterialTheme.colors.primary else primaryLight)
|
||||||
|
.clickable { onClick() },
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title.value,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 8.dp, horizontal = 32.dp),
|
||||||
|
color = contentColorFor(MaterialTheme.colors.primary),
|
||||||
|
)
|
||||||
|
IconButton(
|
||||||
|
onClick = onCloseTab,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterEnd)
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
.size(16.dp)
|
||||||
|
) {
|
||||||
|
Icon(Icons.Default.Close, contentDescription = null, tint = Color.White)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabInformation(
|
||||||
|
val title: MutableState<String>,
|
||||||
|
val key: Int,
|
||||||
|
val content: @Composable () -> Unit
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user