|
@ -27,13 +27,17 @@ object AppIcons {
|
|||
const val HISTORY = "history.svg"
|
||||
const val INFO = "info.svg"
|
||||
const val KEY = "key.svg"
|
||||
const val LAYOUT = "layout.svg"
|
||||
const val LIST = "list.svg"
|
||||
const val LOCATION = "location.svg"
|
||||
const val LOCK = "lock.svg"
|
||||
const val LOGO = "logo.svg"
|
||||
const val MERGE = "merge.svg"
|
||||
const val MESSAGE = "message.svg"
|
||||
const val MORE_VERT = "more_vert.svg"
|
||||
const val NETWORK = "network.svg"
|
||||
const val OPEN = "open.svg"
|
||||
const val PALETTE = "palette.svg"
|
||||
const val PASTE = "paste.svg"
|
||||
const val PERSON = "person.svg"
|
||||
const val REFRESH = "refresh.svg"
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.jetpackduba.gitnuro.ui.dialogs.settings
|
|||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
|
@ -9,17 +10,18 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
import com.jetpackduba.gitnuro.managers.Error
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.managers.Error
|
||||
import com.jetpackduba.gitnuro.preferences.DEFAULT_UI_SCALE
|
||||
import com.jetpackduba.gitnuro.theme.*
|
||||
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
||||
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
||||
import com.jetpackduba.gitnuro.ui.components.ScrollableColumn
|
||||
import com.jetpackduba.gitnuro.ui.components.ScrollableLazyColumn
|
||||
import com.jetpackduba.gitnuro.ui.components.gitnuroViewModel
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.ErrorDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.MaterialDialog
|
||||
|
@ -28,11 +30,27 @@ import com.jetpackduba.gitnuro.viewmodels.SettingsViewModel
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
enum class SettingsCategory(val displayName: String) {
|
||||
UI("UI"),
|
||||
GIT("Git"),
|
||||
sealed interface SettingsEntry {
|
||||
data class Section(val name: String) : SettingsEntry
|
||||
|
||||
data class Entry(val icon: String, val name: String, val content: @Composable (SettingsViewModel) -> Unit) :
|
||||
SettingsEntry
|
||||
}
|
||||
|
||||
val settings = listOf(
|
||||
SettingsEntry.Section("User interface"),
|
||||
SettingsEntry.Entry(AppIcons.PALETTE, "Appearance") { UiSettings(it) },
|
||||
SettingsEntry.Entry(AppIcons.LAYOUT, "Layout") { },
|
||||
|
||||
SettingsEntry.Section("GIT"),
|
||||
SettingsEntry.Entry(AppIcons.LIST, "Commits history") { GitSettings(it) },
|
||||
SettingsEntry.Entry(AppIcons.BRANCH, "Branches") { },
|
||||
SettingsEntry.Entry(AppIcons.CLOUD, "Remote actions") { },
|
||||
|
||||
SettingsEntry.Section("Network"),
|
||||
SettingsEntry.Entry(AppIcons.NETWORK, "Proxy") { },
|
||||
)
|
||||
|
||||
|
||||
@Composable
|
||||
fun SettingsDialog(
|
||||
|
@ -44,74 +62,132 @@ fun SettingsDialog(
|
|||
settingsViewModel.resetInfo()
|
||||
}
|
||||
|
||||
val categories = remember {
|
||||
listOf(
|
||||
SettingsCategory.UI,
|
||||
SettingsCategory.GIT,
|
||||
var selectedCategory by remember {
|
||||
mutableStateOf<SettingsEntry.Entry>(
|
||||
settings.filterIsInstance(SettingsEntry.Entry::class.java).first()
|
||||
)
|
||||
}
|
||||
|
||||
var selectedCategory by remember { mutableStateOf(SettingsCategory.UI) }
|
||||
|
||||
MaterialDialog(
|
||||
background = MaterialTheme.colors.surface,
|
||||
onCloseRequested = {
|
||||
settingsViewModel.savePendingChanges()
|
||||
|
||||
onDismiss()
|
||||
}
|
||||
},
|
||||
paddingHorizontal = 0.dp,
|
||||
paddingVertical = 0.dp,
|
||||
) {
|
||||
Column(modifier = Modifier.height(720.dp)) {
|
||||
Text(
|
||||
text = "Settings",
|
||||
style = MaterialTheme.typography.h3,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 16.dp)
|
||||
)
|
||||
Row(modifier = Modifier.height(720.dp).width(1000.dp)) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(200.dp)
|
||||
.fillMaxHeight()
|
||||
.background(MaterialTheme.colors.background)
|
||||
) {
|
||||
Text(
|
||||
text = "Settings",
|
||||
style = MaterialTheme.typography.h3,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
modifier = Modifier.padding(16.dp),
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
|
||||
Row(modifier = Modifier.weight(1f)) {
|
||||
ScrollableColumn(
|
||||
modifier = Modifier
|
||||
.width(200.dp)
|
||||
.fillMaxHeight()
|
||||
.background(MaterialTheme.colors.background)
|
||||
) {
|
||||
categories.forEach { category ->
|
||||
Category(
|
||||
category = category,
|
||||
isSelected = category == selectedCategory,
|
||||
onClick = { selectedCategory = category }
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(modifier = Modifier.weight(1f)) {
|
||||
ScrollableLazyColumn(
|
||||
modifier = Modifier
|
||||
) {
|
||||
itemsIndexed(settings) { index, settingEntry ->
|
||||
when (settingEntry) {
|
||||
is SettingsEntry.Section -> {
|
||||
if (index != 0) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
}
|
||||
Section(settingEntry.name)
|
||||
}
|
||||
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(720.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
when (selectedCategory) {
|
||||
SettingsCategory.UI -> UiSettings(settingsViewModel)
|
||||
SettingsCategory.GIT -> GitSettings(settingsViewModel)
|
||||
is SettingsEntry.Entry -> Entry(
|
||||
icon = settingEntry.icon,
|
||||
name = settingEntry.name,
|
||||
isSelected = settingEntry == selectedCategory,
|
||||
onClick = {
|
||||
selectedCategory = settingEntry
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PrimaryButton(
|
||||
text = "Accept",
|
||||
modifier = Modifier
|
||||
.padding(end = 8.dp, bottom = 8.dp)
|
||||
.align(Alignment.End),
|
||||
onClick = {
|
||||
settingsViewModel.savePendingChanges()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f, true)
|
||||
.padding(start = 16.dp, top = 64.dp, end = 16.dp)
|
||||
) {
|
||||
selectedCategory.content(settingsViewModel)
|
||||
}
|
||||
|
||||
PrimaryButton(
|
||||
text = "Accept",
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp, bottom = 16.dp)
|
||||
.align(Alignment.End),
|
||||
onClick = {
|
||||
settingsViewModel.savePendingChanges()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Entry(icon: String, name: String, isSelected: Boolean, onClick: () -> Unit) {
|
||||
val backgroundColor = if (isSelected)
|
||||
MaterialTheme.colors.backgroundSelected
|
||||
else
|
||||
MaterialTheme.colors.background
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.background(color = backgroundColor)
|
||||
.handMouseClickable(onClick)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
Icon(
|
||||
painterResource(icon),
|
||||
contentDescription = name,
|
||||
tint = MaterialTheme.colors.onBackgroundSecondary,
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, top = 4.dp, bottom = 4.dp, end = 8.dp)
|
||||
.size(24.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = name,
|
||||
style = MaterialTheme.typography.body1,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Section(name: String) {
|
||||
Text(
|
||||
text = name.uppercase(),
|
||||
color = MaterialTheme.colors.onBackgroundSecondary,
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GitSettings(settingsViewModel: SettingsViewModel) {
|
||||
val commitsLimitEnabled by settingsViewModel.commitsLimitEnabledFlow.collectAsState()
|
||||
|
@ -249,29 +325,6 @@ fun UiSettings(settingsViewModel: SettingsViewModel) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Category(
|
||||
category: SettingsCategory,
|
||||
isSelected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val backgroundColor = if (isSelected)
|
||||
MaterialTheme.colors.backgroundSelected
|
||||
else
|
||||
MaterialTheme.colors.background
|
||||
|
||||
Text(
|
||||
text = category.displayName,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = backgroundColor)
|
||||
.handMouseClickable(onClick)
|
||||
.padding(8.dp),
|
||||
style = MaterialTheme.typography.body1,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun <T> SettingDropDown(
|
||||
|
@ -376,48 +429,6 @@ fun SettingToggle(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingSlider(
|
||||
title: String,
|
||||
subtitle: String,
|
||||
value: Float,
|
||||
minValue: Float,
|
||||
maxValue: Float,
|
||||
steps: Int,
|
||||
onValueChanged: (Float) -> Unit,
|
||||
onValueChangeFinished: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
FieldTitles(title, subtitle)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Text(
|
||||
text = "${minValue.toInt()}%",
|
||||
style = MaterialTheme.typography.caption,
|
||||
)
|
||||
|
||||
Slider(
|
||||
value = value,
|
||||
onValueChange = onValueChanged,
|
||||
onValueChangeFinished = onValueChangeFinished,
|
||||
steps = steps,
|
||||
valueRange = minValue..maxValue,
|
||||
modifier = Modifier
|
||||
.width(200.dp)
|
||||
.padding(horizontal = 4.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "${maxValue.toInt()}%",
|
||||
style = MaterialTheme.typography.caption,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingIntInput(
|
||||
title: String,
|
||||
|
|
1
src/main/resources/layout.svg
Normal file
|
@ -0,0 +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"><rect fill="none" height="24" width="24"/><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M5,19V5h6v14H5z M19,19h-6v-7h6V19z M19,10h-6V5h6V10z"/></svg>
|
After Width: | Height: | Size: 332 B |
1
src/main/resources/list.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g fill="none"><path d="M0 0h24v24H0V0z"/><path d="M0 0h24v24H0V0z" opacity=".87"/></g><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7zm-4 6h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/></svg>
|
After Width: | Height: | Size: 379 B |
1
src/main/resources/network.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<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="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM4 12c0-.61.08-1.21.21-1.78L8.99 15v1c0 1.1.9 2 2 2v1.93C7.06 19.43 4 16.07 4 12zm13.89 5.4c-.26-.81-1-1.4-1.9-1.4h-1v-3c0-.55-.45-1-1-1h-6v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41C17.92 5.77 20 8.65 20 12c0 2.08-.81 3.98-2.11 5.4z"/></svg>
|
After Width: | Height: | Size: 460 B |
1
src/main/resources/palette.svg
Normal file
|
@ -0,0 +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><rect fill="none" height="24" width="24"/></g><g><g><g><g><path d="M12,22C6.49,22,2,17.51,2,12S6.49,2,12,2s10,4.04,10,9c0,3.31-2.69,6-6,6h-1.77c-0.28,0-0.5,0.22-0.5,0.5 c0,0.12,0.05,0.23,0.13,0.33c0.41,0.47,0.64,1.06,0.64,1.67C14.5,20.88,13.38,22,12,22z M12,4c-4.41,0-8,3.59-8,8s3.59,8,8,8 c0.28,0,0.5-0.22,0.5-0.5c0-0.16-0.08-0.28-0.14-0.35c-0.41-0.46-0.63-1.05-0.63-1.65c0-1.38,1.12-2.5,2.5-2.5H16 c2.21,0,4-1.79,4-4C20,7.14,16.41,4,12,4z"/><circle cx="6.5" cy="11.5" r="1.5"/><circle cx="9.5" cy="7.5" r="1.5"/><circle cx="14.5" cy="7.5" r="1.5"/><circle cx="17.5" cy="11.5" r="1.5"/></g></g></g></g></svg>
|
After Width: | Height: | Size: 748 B |
|
@ -1,4 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/>
|
||||
</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="M12 6c3.79 0 7.17 2.13 8.82 5.5C19.17 14.87 15.79 17 12 17s-7.17-2.13-8.82-5.5C4.83 8.13 8.21 6 12 6m0-2C7 4 2.73 7.11 1 11.5 2.73 15.89 7 19 12 19s9.27-3.11 11-7.5C21.27 7.11 17 4 12 4zm0 5c1.38 0 2.5 1.12 2.5 2.5S13.38 14 12 14s-2.5-1.12-2.5-2.5S10.62 9 12 9m0-2c-2.48 0-4.5 2.02-4.5 4.5S9.52 16 12 16s4.5-2.02 4.5-4.5S14.48 7 12 7z"/></svg>
|
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 493 B |
|
@ -1,4 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<path d="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" fill="none"/>
|
||||
<path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0zm0 0h24v24H0V0zm0 0h24v24H0V0zm0 0h24v24H0V0z" fill="none"/><path d="M12 6c3.79 0 7.17 2.13 8.82 5.5-.59 1.22-1.42 2.27-2.41 3.12l1.41 1.41c1.39-1.23 2.49-2.77 3.18-4.53C21.27 7.11 17 4 12 4c-1.27 0-2.49.2-3.64.57l1.65 1.65C10.66 6.09 11.32 6 12 6zm-1.07 1.14L13 9.21c.57.25 1.03.71 1.28 1.28l2.07 2.07c.08-.34.14-.7.14-1.07C16.5 9.01 14.48 7 12 7c-.37 0-.72.05-1.07.14zM2.01 3.87l2.68 2.68C3.06 7.83 1.77 9.53 1 11.5 2.73 15.89 7 19 12 19c1.52 0 2.98-.29 4.32-.82l3.42 3.42 1.41-1.41L3.42 2.45 2.01 3.87zm7.5 7.5l2.61 2.61c-.04.01-.08.02-.12.02-1.38 0-2.5-1.12-2.5-2.5 0-.05.01-.08.01-.13zm-3.4-3.4l1.75 1.75c-.23.55-.36 1.15-.36 1.78 0 2.48 2.02 4.5 4.5 4.5.63 0 1.23-.13 1.77-.36l.98.98c-.88.24-1.8.38-2.75.38-3.79 0-7.17-2.13-8.82-5.5.7-1.43 1.72-2.61 2.93-3.53z"/></svg>
|
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 901 B |