diff --git a/src/main/kotlin/app/App.kt b/src/main/kotlin/app/App.kt index 697e239..84f1c17 100644 --- a/src/main/kotlin/app/App.kt +++ b/src/main/kotlin/app/App.kt @@ -3,8 +3,6 @@ package app import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -16,24 +14,26 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.* +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.WindowPlacement +import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState import androidx.compose.ui.zIndex import app.di.DaggerAppComponent import app.git.GitManager import app.theme.AppTheme import app.ui.AppTab -import app.ui.components.DialogBox import app.ui.components.RepositoriesTabPanel import app.ui.components.TabInformation +import app.ui.dialogs.MaterialDialog import javax.inject.Inject import javax.inject.Provider class Main { - val appComponent = DaggerAppComponent.create() + private val appComponent = DaggerAppComponent.create() @Inject lateinit var gitManagerProvider: Provider @@ -66,39 +66,14 @@ class Main { val dialogManager = remember { DialogManager(showDialog) } Box { - AppTabs(dialogManager) if (showDialog.value) { - val interactionSource = remember { MutableInteractionSource() } - - Box( - modifier = Modifier - .fillMaxSize() - .alpha(0.8f) - .background(Color.Black) - .clickable( - enabled = true, - onClick = {}, - interactionSource = interactionSource, - indication = null - ) - ) - DialogBox( - modifier = Modifier - .align(Alignment.Center) - .clickable( - enabled = true, - onClick = {}, - interactionSource = interactionSource, - indication = null - ) - ) { + MaterialDialog { dialogManager.dialog() } } } - } } } @@ -128,76 +103,66 @@ class Main { mutableStateOf(repoTabs) } - var selectedTabKey by remember { mutableStateOf(0) } + val selectedTabKey = remember { mutableStateOf(0) } Column( - modifier = - Modifier.background(MaterialTheme.colors.background) + modifier = Modifier.background(MaterialTheme.colors.background) ) { - Row( + Tabs( + tabs = tabs, + selectedTabKey = selectedTabKey, + dialogManager = dialogManager, + ) + + TabsContent(tabs.value, selectedTabKey.value) + } + } + + @Composable + fun Tabs( + tabs: MutableState>, + selectedTabKey: MutableState, + dialogManager: DialogManager, + ) { + Row( + modifier = Modifier + .padding(top = 4.dp, bottom = 2.dp, start = 4.dp, end = 4.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + RepositoriesTabPanel( modifier = Modifier - .padding(top = 4.dp, bottom = 2.dp, start = 4.dp, end = 4.dp) - .fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - ) { - RepositoriesTabPanel( - modifier = Modifier - .weight(1f), - tabs = tabs.value, - selectedTabKey = selectedTabKey, - onTabSelected = { newSelectedTabKey -> - selectedTabKey = newSelectedTabKey - }, - newTabContent = { key -> - newAppTab( - dialogManager = dialogManager, - key = key - ) - }, - onTabsUpdated = { tabInformationList -> - tabs.value = tabInformationList - }, - onTabClosed = { key -> - appStateManager.repositoryTabRemoved(key) - } - ) - IconButton( - modifier = Modifier - .padding(horizontal = 8.dp) - .size(24.dp), - onClick = {} - ) { - Icon( - painter = painterResource("settings.svg"), - contentDescription = null, - modifier = Modifier.fillMaxSize(), - tint = MaterialTheme.colors.primary, + .weight(1f), + tabs = tabs.value, + selectedTabKey = selectedTabKey.value, + onTabSelected = { newSelectedTabKey -> + selectedTabKey.value = newSelectedTabKey + }, + newTabContent = { key -> + newAppTab( + dialogManager = dialogManager, + key = key ) + }, + onTabsUpdated = { tabInformationList -> + tabs.value = tabInformationList + }, + onTabClosed = { key -> + appStateManager.repositoryTabRemoved(key) } - } - - LazyColumn( + ) + IconButton( modifier = Modifier - .fillMaxSize(), + .padding(horizontal = 8.dp) + .size(24.dp), + onClick = {} ) { - 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(it) - } - } + Icon( + painter = painterResource("settings.svg"), + contentDescription = null, + modifier = Modifier.fillMaxSize(), + tint = MaterialTheme.colors.primary, + ) } } } @@ -226,6 +191,33 @@ class Main { } } +@Composable +private fun TabsContent(tabs: List, selectedTabKey: Int) { + LazyColumn( + modifier = Modifier + .fillMaxSize(), + ) { + items(items = tabs, 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(it) + } + } + } +} + class DialogManager(private val showDialog: MutableState) { private var content: @Composable () -> Unit = {} diff --git a/src/main/kotlin/app/ui/AppTab.kt b/src/main/kotlin/app/ui/AppTab.kt index 1a66e99..66a479d 100644 --- a/src/main/kotlin/app/ui/AppTab.kt +++ b/src/main/kotlin/app/ui/AppTab.kt @@ -21,9 +21,12 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import app.DialogManager import app.LoadingRepository +import app.credentials.CredentialsState import app.git.GitManager import app.git.RepositorySelectionStatus import app.theme.tabBackground +import app.ui.dialogs.PasswordDialog +import app.ui.dialogs.UserPasswordDialog import kotlinx.coroutines.delay @@ -89,6 +92,8 @@ fun AppTab( .alpha(linearProgressAlpha) ) + CredentialsDialog(gitManager) + Box(modifier = Modifier.fillMaxSize()) { Crossfade(targetState = repositorySelectionStatus) { @@ -154,4 +159,29 @@ fun AppTab( } } } -} \ No newline at end of file +} + +@Composable +fun CredentialsDialog(gitManager: GitManager) { + val credentialsState by gitManager.credentialsState.collectAsState() + + if (credentialsState == CredentialsState.HttpCredentialsRequested) { + UserPasswordDialog( + onReject = { + gitManager.credentialsDenied() + }, + onAccept = { user, password -> + gitManager.httpCredentialsAccepted(user, password) + } + ) + } else if (credentialsState == CredentialsState.SshCredentialsRequested) { + PasswordDialog( + onReject = { + gitManager.credentialsDenied() + }, + onAccept = { password -> + gitManager.sshCredentialsAccepted(password) + } + ) + } +} diff --git a/src/main/kotlin/app/ui/Log.kt b/src/main/kotlin/app/ui/Log.kt index 96ed63c..000b342 100644 --- a/src/main/kotlin/app/ui/Log.kt +++ b/src/main/kotlin/app/ui/Log.kt @@ -1,4 +1,5 @@ -@file:OptIn(ExperimentalComposeUiApi::class) +@file:OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class) + @file:Suppress("UNUSED_PARAMETER") package app.ui @@ -28,6 +29,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import app.DialogManager @@ -87,8 +89,8 @@ fun Log( .fillMaxSize() ) { val hasUncommitedChanges by gitManager.hasUncommitedChanges.collectAsState() - var weightMod by remember { mutableStateOf(0f) } - var graphWidth = (CANVAS_MIN_WIDTH + weightMod).dp//(weightMod / 500) + val weightMod = remember { mutableStateOf(0f) } + var graphWidth = (CANVAS_MIN_WIDTH + weightMod.value).dp if (graphWidth.value < CANVAS_MIN_WIDTH) graphWidth = CANVAS_MIN_WIDTH.dp @@ -120,7 +122,7 @@ fun Log( DividerLog( modifier = Modifier.draggable(rememberDraggableState { - weightMod += it + weightMod.value += it }, Orientation.Horizontal) ) @@ -166,7 +168,7 @@ fun Log( modifier = Modifier .draggable( rememberDraggableState { - weightMod += it + weightMod.value += it }, Orientation.Horizontal ) @@ -192,131 +194,155 @@ fun Log( } itemsIndexed(items = commitList) { index, graphNode -> - val commitRefs = graphNode.refs - Box(modifier = Modifier - .clickable { + CommitLine( + gitManager = gitManager, + dialogManager = dialogManager, + graphNode = graphNode, + selected = selectedIndex.value == index, + weightMod = weightMod, + graphWidth = graphWidth, + onRevCommitSelected = { selectedIndex.value = index selectedUncommited.value = false - onRevCommitSelected(graphNode) + onRevCommitSelected(it) } - ) { + ) + } + } + } + } +} - ContextMenuArea( - items = { - listOf( - ContextMenuItem( - label = "Checkout commit", - onClick = { - gitManager.checkoutCommit(graphNode) - }), - ContextMenuItem( - label = "Create branch", - onClick = { - dialogManager.show { - NewBranchDialog( - onReject = { - dialogManager.dismiss() - }, - onAccept = { branchName -> - dialogManager.dismiss() - gitManager.createBranchOnCommit(branchName, graphNode) - } - ) - } - } - ), - ContextMenuItem( - label = "Create tag", - onClick = { - dialogManager.show { - NewTagDialog( - onReject = { - dialogManager.dismiss() - }, - onAccept = { tagName -> - gitManager.createTagOnCommit(tagName, graphNode) - dialogManager.dismiss() - } - ) - } - } - ), - ContextMenuItem( - label = "Revert commit", - onClick = { - gitManager.revertCommit(graphNode) - } - ), +@Composable +fun CommitLine( + gitManager: GitManager, + dialogManager: DialogManager, + graphNode: GraphNode, + selected: Boolean, + weightMod: MutableState, + graphWidth: Dp, + onRevCommitSelected: (GraphNode) -> Unit, +) { + val commitRefs = graphNode.refs + var showCreateBranchDialog by remember(graphNode.id.name) { mutableStateOf(false) } + if(showCreateBranchDialog) + NewBranchDialog( + onReject = { + showCreateBranchDialog = false + }, + onAccept = { branchName -> + gitManager.createBranchOnCommit(branchName, graphNode) + showCreateBranchDialog = false + } + ) - ContextMenuItem( - label = "Reset current branch to this commit", - onClick = { - dialogManager.show { - ResetBranchDialog( - onReject = { - dialogManager.dismiss() - }, - onAccept = { resetType -> - dialogManager.dismiss() - gitManager.resetToCommit(graphNode, resetType) - } - ) - } - } - ) - ) - }, - ) { - Row( - modifier = Modifier - .height(40.dp) - .fillMaxWidth(), - ) { - CommitsGraphLine( - modifier = Modifier - .width(graphWidth) - .fillMaxHeight(), - plotCommit = graphNode - ) - - DividerLog( - modifier = Modifier - .draggable( - rememberDraggableState { - weightMod += it - }, - Orientation.Horizontal - ) - ) - - CommitMessage( - modifier = Modifier.weight(1f), - commit = graphNode, - selected = selectedIndex.value == index, - refs = commitRefs, - onCheckoutRef = { ref -> gitManager.checkoutRef(ref) }, - onMergeBranch = { ref -> - dialogManager.show { - MergeDialog( - currentBranchName = "HEAD", - mergeBranchName = ref.simpleName, - onReject = { - dialogManager.dismiss() - }, - onAccept = { fastForward -> - dialogManager.dismiss() - gitManager.mergeBranch(ref, fastForward) - } - ) - } + Box(modifier = Modifier + .clickable { + onRevCommitSelected(graphNode) + } + ) { + ContextMenuArea( + items = { + listOf( + ContextMenuItem( + label = "Checkout commit", + onClick = { + gitManager.checkoutCommit(graphNode) + }), + ContextMenuItem( + label = "Create branch", + onClick = { + showCreateBranchDialog = true + } + ), + ContextMenuItem( + label = "Create tag", + onClick = { + dialogManager.show { + NewTagDialog( + onReject = { + dialogManager.dismiss() }, - onDeleteBranch = { ref -> gitManager.deleteBranch(ref) } + onAccept = { tagName -> + gitManager.createTagOnCommit(tagName, graphNode) + dialogManager.dismiss() + } ) } } - } - } + ), + ContextMenuItem( + label = "Revert commit", + onClick = { + gitManager.revertCommit(graphNode) + } + ), + + ContextMenuItem( + label = "Reset current branch to this commit", + onClick = { + dialogManager.show { + ResetBranchDialog( + onReject = { + dialogManager.dismiss() + }, + onAccept = { resetType -> + dialogManager.dismiss() + gitManager.resetToCommit(graphNode, resetType) + } + ) + } + } + ) + ) + }, + ) { + Row( + modifier = Modifier + .height(40.dp) + .fillMaxWidth(), + ) { + CommitsGraphLine( + modifier = Modifier + .width(graphWidth) + .fillMaxHeight(), + plotCommit = graphNode + ) + + DividerLog( + modifier = Modifier + .draggable( + rememberDraggableState { + weightMod.value += it + }, + Orientation.Horizontal + ) + ) + + CommitMessage( + modifier = Modifier.weight(1f), + commit = graphNode, + selected = selected, + refs = commitRefs, + onCheckoutRef = { ref -> gitManager.checkoutRef(ref) }, + onMergeBranch = { ref -> + dialogManager.show { + MergeDialog( + currentBranchName = "HEAD", + mergeBranchName = ref.simpleName, + onReject = { + dialogManager.dismiss() + }, + onAccept = { fastForward -> + dialogManager.dismiss() + gitManager.mergeBranch(ref, fastForward) + } + ) + } + }, + onDeleteBranch = { ref -> gitManager.deleteBranch(ref) } + ) } } } diff --git a/src/main/kotlin/app/ui/RepositoryOpen.kt b/src/main/kotlin/app/ui/RepositoryOpen.kt index b4ab21f..a837ba7 100644 --- a/src/main/kotlin/app/ui/RepositoryOpen.kt +++ b/src/main/kotlin/app/ui/RepositoryOpen.kt @@ -44,36 +44,6 @@ fun RepositoryOpenPage(gitManager: GitManager, dialogManager: DialogManager) { val selectedIndexCommitLog = remember { mutableStateOf(-1) } - val credentialsState by gitManager.credentialsState.collectAsState() - - if (credentialsState == CredentialsState.HttpCredentialsRequested) { - dialogManager.show { - UserPasswordDialog( - onReject = { - gitManager.credentialsDenied() - dialogManager.dismiss() - }, - onAccept = { user, password -> - gitManager.httpCredentialsAccepted(user, password) - dialogManager.dismiss() - } - ) - } - } else if (credentialsState == CredentialsState.SshCredentialsRequested) { - dialogManager.show { - PasswordDialog( - onReject = { - gitManager.credentialsDenied() - dialogManager.dismiss() - }, - onAccept = { password -> - gitManager.sshCredentialsAccepted(password) - dialogManager.dismiss() - } - ) - } - } - Column { GMenu( onRepositoryOpen = {