Added new side bar
This commit is contained in:
parent
c6b0250a63
commit
2ffb8d9038
@ -4,16 +4,12 @@ package com.jetpackduba.gitnuro
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.PointerIconDefaults
|
||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.Density
|
||||
@ -35,8 +31,6 @@ import com.jetpackduba.gitnuro.theme.secondaryTextColor
|
||||
import com.jetpackduba.gitnuro.ui.AppTab
|
||||
import com.jetpackduba.gitnuro.ui.components.RepositoriesTabPanel
|
||||
import com.jetpackduba.gitnuro.ui.components.TabInformation
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.settings.SettingsDialog
|
||||
import com.jetpackduba.gitnuro.viewmodels.SettingsViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
@ -53,9 +47,6 @@ class App {
|
||||
@Inject
|
||||
lateinit var appSettings: AppSettings
|
||||
|
||||
@Inject
|
||||
lateinit var settingsViewModel: SettingsViewModel
|
||||
|
||||
init {
|
||||
appComponent.inject(this)
|
||||
}
|
||||
@ -107,25 +98,12 @@ class App {
|
||||
emptyArray()
|
||||
|
||||
CompositionLocalProvider(values = density) {
|
||||
var showSettingsDialog by remember { mutableStateOf(false) }
|
||||
|
||||
AppTheme(
|
||||
selectedTheme = theme,
|
||||
customTheme = customTheme,
|
||||
) {
|
||||
Box(modifier = Modifier.background(MaterialTheme.colors.background)) {
|
||||
AppTabs(
|
||||
onOpenSettings = {
|
||||
showSettingsDialog = true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (showSettingsDialog) {
|
||||
SettingsDialog(
|
||||
settingsViewModel = settingsViewModel,
|
||||
onDismiss = { showSettingsDialog = false }
|
||||
)
|
||||
AppTabs()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,9 +138,7 @@ class App {
|
||||
|
||||
|
||||
@Composable
|
||||
fun AppTabs(
|
||||
onOpenSettings: () -> Unit,
|
||||
) {
|
||||
fun AppTabs() {
|
||||
val tabs by tabsFlow.collectAsState()
|
||||
val tabsInformationList = tabs.sortedBy { it.key }
|
||||
val selectedTabKey = remember { mutableStateOf(0) }
|
||||
@ -173,7 +149,6 @@ class App {
|
||||
Tabs(
|
||||
tabsInformationList = tabsInformationList,
|
||||
selectedTabKey = selectedTabKey,
|
||||
onOpenSettings = onOpenSettings,
|
||||
onAddedTab = { tabInfo ->
|
||||
addTab(tabInfo)
|
||||
},
|
||||
@ -203,11 +178,9 @@ class App {
|
||||
tabsFlow.value = tabsFlow.value.toMutableList().apply { add(tabInformation) }
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun Tabs(
|
||||
selectedTabKey: MutableState<Int>,
|
||||
onOpenSettings: () -> Unit,
|
||||
tabsInformationList: List<TabInformation>,
|
||||
onAddedTab: (TabInformation) -> Unit,
|
||||
onRemoveTab: (Int) -> Unit,
|
||||
@ -237,20 +210,6 @@ class App {
|
||||
},
|
||||
onTabClosed = onRemoveTab
|
||||
)
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
.size(24.dp)
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand),
|
||||
onClick = onOpenSettings
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource("settings.svg"),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
tint = MaterialTheme.colors.primaryVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package com.jetpackduba.gitnuro.di
|
||||
import com.jetpackduba.gitnuro.App
|
||||
import com.jetpackduba.gitnuro.AppStateManager
|
||||
import com.jetpackduba.gitnuro.preferences.AppSettings
|
||||
import com.jetpackduba.gitnuro.viewmodels.SettingsViewModel
|
||||
import dagger.Component
|
||||
import javax.inject.Singleton
|
||||
|
||||
@ -11,6 +12,7 @@ import javax.inject.Singleton
|
||||
interface AppComponent {
|
||||
fun inject(main: App)
|
||||
fun appStateManager(): AppStateManager
|
||||
fun settingsViewModel(): SettingsViewModel
|
||||
|
||||
fun appPreferences(): AppSettings
|
||||
}
|
@ -17,11 +17,10 @@ fun Modifier.backgroundIf(condition: Boolean, color: Color): Modifier {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
fun Modifier.handMouseClickable(onClick: () -> Unit): Modifier {
|
||||
return this
|
||||
.clickable { onClick() }
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,4 +29,9 @@ fun Modifier.handMouseClickable(onClick: () -> Unit): Modifier {
|
||||
*/
|
||||
fun Modifier.ignoreKeyEvents(): Modifier {
|
||||
return this.onPreviewKeyEvent { true }
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
fun Modifier.handOnHover(): Modifier {
|
||||
return this.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
}
|
@ -31,7 +31,7 @@ val lightTheme = ColorsScheme(
|
||||
|
||||
|
||||
val darkBlueTheme = ColorsScheme(
|
||||
primary = Color(0xFF014F97),
|
||||
primary = Color(0xFF1074BC),
|
||||
primaryVariant = Color(0xFF9FD1FF),
|
||||
onPrimary = Color(0xFFFFFFFFF),
|
||||
secondary = Color(0xFFe9c754),
|
||||
@ -39,10 +39,10 @@ val darkBlueTheme = ColorsScheme(
|
||||
secondaryText = Color(0xFFCCCBCB),
|
||||
error = Color(0xFFc93838),
|
||||
onError = Color(0xFFFFFFFF),
|
||||
background = Color(0xFF0E1621),
|
||||
background = Color(0xFF16181F),
|
||||
backgroundSelected = Color(0xFF2f3640),
|
||||
surface = Color(0xFF15212d),
|
||||
secondarySurface = Color(0xFF1a2c40),
|
||||
surface = Color(0xFF202538),
|
||||
secondarySurface = Color(0xFF122C46),
|
||||
headerBackground = Color(0xFF0a335c),
|
||||
borderColor = Color(0xFF989898),
|
||||
addFile = Color(0xFF32A852),
|
||||
|
@ -27,6 +27,7 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.extensions.lineAt
|
||||
import com.jetpackduba.gitnuro.extensions.toStringWithSpaces
|
||||
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
@ -187,7 +188,7 @@ fun MinimizedBlame(
|
||||
onClick = onClose,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource("close.svg"),
|
||||
@ -222,7 +223,7 @@ private fun Header(
|
||||
IconButton(
|
||||
onClick = onClose,
|
||||
modifier = Modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource("close.svg"),
|
||||
|
@ -24,6 +24,7 @@ import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.extensions.toSmartSystemString
|
||||
import com.jetpackduba.gitnuro.git.diff.DiffResult
|
||||
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
@ -102,7 +103,7 @@ private fun Header(
|
||||
IconButton(
|
||||
onClick = onClose,
|
||||
modifier = Modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource("close.svg"),
|
||||
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
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.ArrowDropDown
|
||||
@ -13,6 +14,8 @@ import androidx.compose.runtime.*
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
@ -22,6 +25,7 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.extensions.ignoreKeyEvents
|
||||
import com.jetpackduba.gitnuro.theme.primaryTextColor
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.*
|
||||
@ -32,7 +36,6 @@ import com.jetpackduba.gitnuro.viewmodels.MenuViewModel
|
||||
fun Menu(
|
||||
modifier: Modifier,
|
||||
menuViewModel: MenuViewModel,
|
||||
onRepositoryOpen: () -> Unit,
|
||||
onCreateBranch: () -> Unit,
|
||||
onStashWithMessage: () -> Unit,
|
||||
) {
|
||||
@ -43,15 +46,6 @@ fun Menu(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
MenuButton(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
title = "Open",
|
||||
icon = painterResource("open.svg"),
|
||||
onClick = {
|
||||
onRepositoryOpen()
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
ExtendedMenuButton(
|
||||
@ -129,7 +123,6 @@ fun Menu(
|
||||
val menuOptions = remember {
|
||||
repositoryAdditionalOptionsMenu(
|
||||
onOpenRepositoryOnFileExplorer = { menuViewModel.openFolderInFileExplorer() },
|
||||
onForceRepositoryRefresh = { menuViewModel.refresh() },
|
||||
)
|
||||
}
|
||||
for (item in menuOptions) {
|
||||
@ -153,34 +146,31 @@ fun MenuButton(
|
||||
icon: Painter,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val iconColor = if (enabled) {
|
||||
MaterialTheme.colors.primaryVariant
|
||||
} else {
|
||||
MaterialTheme.colors.secondaryVariant //todo this color isn't specified anywhere
|
||||
}
|
||||
|
||||
Column(
|
||||
Row(
|
||||
modifier = modifier
|
||||
.ignoreKeyEvents()
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(MaterialTheme.colors.primary)
|
||||
.handMouseClickable { if (enabled) onClick() }
|
||||
.padding(vertical = 4.dp, horizontal = 16.dp)
|
||||
.width(48.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
.width(100.dp),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
Icon(
|
||||
painter = icon,
|
||||
contentDescription = title,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 2.dp)
|
||||
.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(iconColor),
|
||||
tint = MaterialTheme.colors.onPrimary,
|
||||
)
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(start = 2.dp, top = 8.dp, bottom = 8.dp),
|
||||
maxLines = 1,
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colors.onPrimary,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -194,44 +184,40 @@ fun ExtendedMenuButton(
|
||||
onClick: () -> Unit,
|
||||
extendedListItems: List<DropDownContentData>,
|
||||
) {
|
||||
val iconColor = if (enabled) {
|
||||
MaterialTheme.colors.primaryVariant
|
||||
} else {
|
||||
MaterialTheme.colors.secondaryVariant
|
||||
}
|
||||
|
||||
var showDropDownMenu by remember { mutableStateOf(false) }
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.height(IntrinsicSize.Min)
|
||||
.ignoreKeyEvents()
|
||||
.handMouseClickable { if (enabled) onClick() }
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(MaterialTheme.colors.primary)
|
||||
) {
|
||||
Column(
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp, bottom = 4.dp, start = 16.dp, end = 4.dp)
|
||||
.width(40.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
.width(92.dp)
|
||||
.handMouseClickable { if (enabled) onClick() },
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
Icon(
|
||||
painter = icon,
|
||||
contentDescription = title,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 2.dp)
|
||||
.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(iconColor),
|
||||
tint = MaterialTheme.colors.onPrimary,
|
||||
)
|
||||
Text(
|
||||
text = title,
|
||||
modifier = Modifier.padding(start = 2.dp, top = 8.dp, bottom = 8.dp),
|
||||
style = MaterialTheme.typography.body2,
|
||||
color = MaterialTheme.colors.onPrimary,
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(20.dp)
|
||||
.width(24.dp)
|
||||
.fillMaxHeight()
|
||||
.ignoreKeyEvents()
|
||||
.handMouseClickable {
|
||||
@ -239,10 +225,18 @@ fun ExtendedMenuButton(
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.background(MaterialTheme.colors.onPrimary.copy(alpha = 0.5f))
|
||||
.width(1.dp)
|
||||
.align(Alignment.CenterStart)
|
||||
)
|
||||
|
||||
Icon(
|
||||
Icons.Default.ArrowDropDown,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colors.primaryTextColor,
|
||||
tint = MaterialTheme.colors.onPrimary,
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
@ -275,7 +269,7 @@ fun IconMenuButton(
|
||||
|
||||
IconButton(
|
||||
modifier = modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand),
|
||||
.handOnHover(),
|
||||
enabled = enabled,
|
||||
onClick = onClick,
|
||||
) {
|
||||
|
@ -16,6 +16,7 @@ import androidx.compose.ui.input.pointer.PointerIconDefaults
|
||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.extensions.simpleName
|
||||
import com.jetpackduba.gitnuro.theme.primaryTextColor
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuPanel
|
||||
@ -29,7 +30,6 @@ import com.jetpackduba.gitnuro.viewmodels.RemoteView
|
||||
import com.jetpackduba.gitnuro.viewmodels.RemotesViewModel
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun Remotes(
|
||||
remotesViewModel: RemotesViewModel,
|
||||
@ -62,7 +62,7 @@ fun Remotes(
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp)
|
||||
.size(16.dp)
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand),
|
||||
.handOnHover(),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource("settings.svg"),
|
||||
|
@ -4,27 +4,44 @@ package com.jetpackduba.gitnuro.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.focusable
|
||||
import androidx.compose.foundation.hoverable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.key.onKeyEvent
|
||||
import androidx.compose.ui.input.pointer.PointerIcon
|
||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.positionInRoot
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.*
|
||||
import androidx.compose.ui.window.Popup
|
||||
import androidx.compose.ui.window.PopupPositionProvider
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.git.DiffEntryType
|
||||
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
||||
import com.jetpackduba.gitnuro.theme.primaryTextColor
|
||||
import com.jetpackduba.gitnuro.theme.secondarySurface
|
||||
import com.jetpackduba.gitnuro.ui.components.ScrollableColumn
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.AuthorDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.NewBranchDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.StashWithMessageDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.settings.SettingsDialog
|
||||
import com.jetpackduba.gitnuro.ui.diff.Diff
|
||||
import com.jetpackduba.gitnuro.ui.log.Log
|
||||
import com.jetpackduba.gitnuro.viewmodels.BlameState
|
||||
@ -44,7 +61,6 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
val selectedItem by tabViewModel.selectedItem.collectAsState()
|
||||
val blameState by tabViewModel.blameState.collectAsState()
|
||||
val showHistory by tabViewModel.showHistory.collectAsState()
|
||||
val userInfo by tabViewModel.authorInfoSimple.collectAsState()
|
||||
val showAuthorInfo by tabViewModel.showAuthorInfo.collectAsState()
|
||||
|
||||
var showNewBranchDialog by remember { mutableStateOf(false) }
|
||||
@ -87,40 +103,45 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
LaunchedEffect(selectedItem) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
Column {
|
||||
Row(modifier = Modifier.weight(1f)) {
|
||||
SideBar(tabViewModel)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.focusable()
|
||||
.onKeyEvent { keyEvent ->
|
||||
if (keyEvent.matchesBinding(KeybindingOption.REFRESH)) {
|
||||
tabViewModel.refreshAll()
|
||||
true
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.focusable()
|
||||
.onKeyEvent { keyEvent ->
|
||||
if (keyEvent.matchesBinding(KeybindingOption.REFRESH)) {
|
||||
tabViewModel.refreshAll()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
) {
|
||||
val rebaseInteractiveViewModel = tabViewModel.rebaseInteractiveViewModel
|
||||
|
||||
if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) {
|
||||
RebaseInteractive(rebaseInteractiveViewModel)
|
||||
} else {
|
||||
false
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Menu(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
top = 12.dp,
|
||||
bottom = 16.dp
|
||||
) // Linear progress bar already take 4 additional dp for top
|
||||
.fillMaxWidth(),
|
||||
menuViewModel = tabViewModel.menuViewModel,
|
||||
onCreateBranch = { showNewBranchDialog = true },
|
||||
onStashWithMessage = { showStashWithMessageDialog = true },
|
||||
)
|
||||
|
||||
RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState, blameState, showHistory)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
val rebaseInteractiveViewModel = tabViewModel.rebaseInteractiveViewModel
|
||||
|
||||
if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) {
|
||||
RebaseInteractive(rebaseInteractiveViewModel)
|
||||
} else {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Menu(
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp, bottom = 8.dp) // Linear progress bar already take 4 additional dp for top
|
||||
.fillMaxWidth(),
|
||||
menuViewModel = tabViewModel.menuViewModel,
|
||||
onRepositoryOpen = {
|
||||
openRepositoryDialog(tabViewModel = tabViewModel)
|
||||
},
|
||||
onCreateBranch = { showNewBranchDialog = true },
|
||||
onStashWithMessage = { showStashWithMessageDialog = true },
|
||||
)
|
||||
|
||||
RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState, blameState, showHistory)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(
|
||||
@ -129,27 +150,142 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colors.primaryVariant.copy(alpha = 0.2f))
|
||||
)
|
||||
Row(
|
||||
|
||||
BottomInfoBar(tabViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SideBar(tabViewModel: TabViewModel) {
|
||||
var showSettingsDialog by remember { mutableStateOf(false) }
|
||||
if (showSettingsDialog) {
|
||||
SettingsDialog(
|
||||
settingsViewModel = tabViewModel.settingsViewModel,
|
||||
onDismiss = { showSettingsDialog = false }
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(48.dp)
|
||||
.background(MaterialTheme.colors.secondarySurface)
|
||||
.padding(vertical = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
SideBarButton(
|
||||
painterName = "open.svg",
|
||||
label = "Open a new repository",
|
||||
onClick = {
|
||||
openRepositoryDialog(tabViewModel = tabViewModel)
|
||||
}
|
||||
)
|
||||
SideBarButton(
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
painterName = "refresh.svg",
|
||||
label = "Refresh repository information",
|
||||
onClick = {
|
||||
tabViewModel.refreshAll()
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
SideBarButton(
|
||||
painterName = "settings.svg",
|
||||
label = "Settings",
|
||||
onClick = { showSettingsDialog = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomInfoBar(tabViewModel: TabViewModel) {
|
||||
val userInfo by tabViewModel.authorInfoSimple.collectAsState()
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(32.dp)
|
||||
.background(MaterialTheme.colors.surface)
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(32.dp)
|
||||
.background(MaterialTheme.colors.surface)
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
.fillMaxHeight()
|
||||
.handMouseClickable { tabViewModel.showAuthorInfoDialog() },
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
text = "${userInfo.name ?: "Name not set"} <${userInfo.email ?: "Email not set"}>",
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SideBarButton(
|
||||
modifier: Modifier = Modifier,
|
||||
painterName: String,
|
||||
label: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val hoverInteraction = remember { MutableInteractionSource() }
|
||||
val isHovered by hoverInteraction.collectIsHoveredAsState()
|
||||
|
||||
val (buttonCoordinates, setButtonCoordinates) = remember { mutableStateOf<Pair<Offset, IntSize>?>(null) }
|
||||
|
||||
if (isHovered && buttonCoordinates != null) {
|
||||
Popup(
|
||||
popupPositionProvider = object : PopupPositionProvider {
|
||||
override fun calculatePosition(
|
||||
anchorBounds: IntRect,
|
||||
windowSize: IntSize,
|
||||
layoutDirection: LayoutDirection,
|
||||
popupContentSize: IntSize
|
||||
): IntOffset {
|
||||
val position = buttonCoordinates.first
|
||||
val size = buttonCoordinates.second
|
||||
val x = position.x + size.width + 8
|
||||
val y = position.y + (size.height / 2) - (popupContentSize.height / 2)
|
||||
|
||||
return IntOffset(x.toInt(), y.toInt())
|
||||
}
|
||||
|
||||
}
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.handMouseClickable { tabViewModel.showAuthorInfoDialog() },
|
||||
contentAlignment = Alignment.Center,
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(MaterialTheme.colors.background)
|
||||
) {
|
||||
Text(
|
||||
text = "${userInfo.name ?: "Name not set"} <${userInfo.email ?: "Email not set"}>",
|
||||
style = MaterialTheme.typography.body2,
|
||||
text = label,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
.handOnHover()
|
||||
.hoverable(hoverInteraction)
|
||||
.size(24.dp)
|
||||
.onGloballyPositioned { layoutCoordinates ->
|
||||
setButtonCoordinates(layoutCoordinates.positionInRoot() to layoutCoordinates.size)
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(painterName),
|
||||
contentDescription = null,
|
||||
modifier = Modifier,
|
||||
tint = MaterialTheme.colors.primaryTextColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,6 +382,7 @@ fun MainContentView(
|
||||
repositoryState = repositoryState,
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
val diffViewModel = tabViewModel.diffViewModel
|
||||
|
||||
|
@ -29,6 +29,7 @@ import com.jetpackduba.gitnuro.AppStateManager
|
||||
import com.jetpackduba.gitnuro.di.AppComponent
|
||||
import com.jetpackduba.gitnuro.di.DaggerTabComponent
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.theme.primaryTextColor
|
||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModel
|
||||
import javax.inject.Inject
|
||||
@ -117,7 +118,7 @@ fun TabPanel(
|
||||
onClick = onNewTabClicked,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
.align(Alignment.CenterStart),
|
||||
) {
|
||||
Icon(
|
||||
|
@ -5,7 +5,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun repositoryAdditionalOptionsMenu(
|
||||
onOpenRepositoryOnFileExplorer: () -> Unit,
|
||||
onForceRepositoryRefresh: () -> Unit,
|
||||
): List<DropDownContentData> {
|
||||
return mutableListOf(
|
||||
DropDownContentData(
|
||||
@ -13,10 +12,5 @@ fun repositoryAdditionalOptionsMenu(
|
||||
icon = "source.svg",
|
||||
onClick = onOpenRepositoryOnFileExplorer,
|
||||
),
|
||||
DropDownContentData(
|
||||
label = "Refresh repository",
|
||||
icon = "refresh.svg",
|
||||
onClick = onForceRepositoryRefresh,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.theme.*
|
||||
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
||||
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
||||
import com.jetpackduba.gitnuro.viewmodels.RemotesViewModel
|
||||
import org.eclipse.jgit.transport.RemoteConfig
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun EditRemotesDialog(
|
||||
remotesViewModel: RemotesViewModel,
|
||||
@ -90,7 +90,7 @@ fun EditRemotesDialog(
|
||||
IconButton(
|
||||
onClick = onDismiss,
|
||||
modifier = Modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Clear,
|
||||
@ -153,7 +153,7 @@ fun EditRemotesDialog(
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand),
|
||||
.handOnHover(),
|
||||
onClick = {
|
||||
val remotesWithNew = remotesEditorData.listRemotes.toMutableList()
|
||||
val newRemote = RemoteWrapper(
|
||||
@ -182,7 +182,7 @@ fun EditRemotesDialog(
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand),
|
||||
.handOnHover(),
|
||||
enabled = selectedRemote != null,
|
||||
onClick = {
|
||||
if (selectedRemote != null)
|
||||
|
@ -550,7 +550,6 @@ fun HunkHeader(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
private fun DiffHeader(
|
||||
diffEntryType: DiffEntryType,
|
||||
@ -598,7 +597,7 @@ private fun DiffHeader(
|
||||
IconButton(
|
||||
onClick = onCloseDiffView,
|
||||
modifier = Modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource("close.svg"),
|
||||
@ -677,7 +676,6 @@ fun UncommitedDiffFileHeaderButtons(
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
private fun PathOnlyDiffHeader(
|
||||
filePath: String,
|
||||
@ -703,7 +701,7 @@ private fun PathOnlyDiffHeader(
|
||||
IconButton(
|
||||
onClick = onCloseDiffView,
|
||||
modifier = Modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource("close.svg"),
|
||||
|
@ -333,7 +333,7 @@ fun SearchFilter(
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand),
|
||||
.handOnHover(),
|
||||
onClick = {
|
||||
scope.launch { logViewModel.selectPreviousFilterCommit() }
|
||||
}
|
||||
@ -343,7 +343,7 @@ fun SearchFilter(
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand),
|
||||
.handOnHover(),
|
||||
onClick = {
|
||||
scope.launch { logViewModel.selectNextFilterCommit() }
|
||||
}
|
||||
@ -353,7 +353,7 @@ fun SearchFilter(
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
.padding(end = 4.dp),
|
||||
onClick = { logViewModel.closeSearch() }
|
||||
) {
|
||||
@ -613,7 +613,7 @@ fun GraphHeader(
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.padding(end = 8.dp)
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand),
|
||||
.handOnHover(),
|
||||
onClick = onShowSearch
|
||||
) {
|
||||
Icon(
|
||||
@ -1135,7 +1135,7 @@ fun RefChip(
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.border(width = 2.dp, color = color, shape = RoundedCornerShape(16.dp))
|
||||
.combinedClickable(onDoubleClick = onCheckoutRef, onClick = {})
|
||||
.pointerHoverIcon(PointerIconDefaults.Hand)
|
||||
.handOnHover()
|
||||
) {
|
||||
ContextMenu(
|
||||
items = contextMenuItemsList
|
||||
|
@ -68,10 +68,4 @@ class MenuViewModel @Inject constructor(
|
||||
) { git ->
|
||||
Desktop.getDesktop().open(git.repository.directory.parentFile)
|
||||
}
|
||||
|
||||
fun refresh() = tabState.safeProcessing(
|
||||
refreshType = RefreshType.ALL_DATA,
|
||||
) {
|
||||
// Nothing to do here
|
||||
}
|
||||
}
|
@ -55,6 +55,7 @@ class TabViewModel @Inject constructor(
|
||||
private val authorViewModelProvider: Provider<AuthorViewModel>,
|
||||
private val tabState: TabState,
|
||||
val appStateManager: AppStateManager,
|
||||
val settingsViewModel: SettingsViewModel,
|
||||
private val fileChangesWatcher: FileChangesWatcher,
|
||||
private val updatesRepository: UpdatesRepository,
|
||||
) {
|
||||
|
@ -1,7 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<g>
|
||||
<path d="M0,0h24v24H0V0z" fill="none"/>
|
||||
<path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
Loading…
Reference in New Issue
Block a user