Added scaling setting
This commit is contained in:
parent
02906a253d
commit
591fa98508
@ -11,12 +11,13 @@ import androidx.compose.ui.ExperimentalComposeUiApi
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.pointer.PointerIconDefaults
|
import androidx.compose.ui.input.pointer.PointerIconDefaults
|
||||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.Density
|
||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
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.Window
|
import androidx.compose.ui.window.Window
|
||||||
import androidx.compose.ui.window.WindowPlacement
|
|
||||||
import androidx.compose.ui.window.application
|
import androidx.compose.ui.window.application
|
||||||
import androidx.compose.ui.window.rememberWindowState
|
import androidx.compose.ui.window.rememberWindowState
|
||||||
import app.di.DaggerAppComponent
|
import app.di.DaggerAppComponent
|
||||||
@ -29,11 +30,13 @@ import app.theme.secondaryTextColor
|
|||||||
import app.ui.AppTab
|
import app.ui.AppTab
|
||||||
import app.ui.components.RepositoriesTabPanel
|
import app.ui.components.RepositoriesTabPanel
|
||||||
import app.ui.components.TabInformation
|
import app.ui.components.TabInformation
|
||||||
import app.ui.dialogs.SettingsDialog
|
import app.ui.dialogs.settings.SettingsDialog
|
||||||
|
import app.viewmodels.SettingsViewModel
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
private val appComponent = DaggerAppComponent.create()
|
private val appComponent = DaggerAppComponent.create()
|
||||||
|
|
||||||
@ -43,6 +46,9 @@ class App {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appPreferences: AppPreferences
|
lateinit var appPreferences: AppPreferences
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var settingsViewModel: SettingsViewModel
|
||||||
|
|
||||||
init {
|
init {
|
||||||
appComponent.inject(this)
|
appComponent.inject(this)
|
||||||
}
|
}
|
||||||
@ -60,6 +66,7 @@ class App {
|
|||||||
var isOpen by remember { mutableStateOf(true) }
|
var isOpen by remember { mutableStateOf(true) }
|
||||||
val theme by appPreferences.themeState.collectAsState()
|
val theme by appPreferences.themeState.collectAsState()
|
||||||
val customTheme by appPreferences.customThemeFlow.collectAsState()
|
val customTheme by appPreferences.customThemeFlow.collectAsState()
|
||||||
|
val scale by appPreferences.scaleUiFlow.collectAsState()
|
||||||
|
|
||||||
val windowState = rememberWindowState(
|
val windowState = rememberWindowState(
|
||||||
placement = windowPlacement,
|
placement = windowPlacement,
|
||||||
@ -78,25 +85,32 @@ class App {
|
|||||||
state = windowState,
|
state = windowState,
|
||||||
icon = painterResource("logo.svg"),
|
icon = painterResource("logo.svg"),
|
||||||
) {
|
) {
|
||||||
var showSettingsDialog by remember { mutableStateOf(false) }
|
val density = if(scale != -1f) {
|
||||||
|
arrayOf(LocalDensity provides Density(scale, 1f))
|
||||||
|
} else
|
||||||
|
emptyArray()
|
||||||
|
|
||||||
AppTheme(
|
CompositionLocalProvider(values = density) {
|
||||||
selectedTheme = theme,
|
var showSettingsDialog by remember { mutableStateOf(false) }
|
||||||
customTheme = customTheme,
|
|
||||||
) {
|
|
||||||
Box(modifier = Modifier.background(MaterialTheme.colors.background)) {
|
|
||||||
AppTabs(
|
|
||||||
onOpenSettings = {
|
|
||||||
showSettingsDialog = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showSettingsDialog) {
|
AppTheme(
|
||||||
SettingsDialog(
|
selectedTheme = theme,
|
||||||
appPreferences = appPreferences,
|
customTheme = customTheme,
|
||||||
onDismiss = { showSettingsDialog = false }
|
) {
|
||||||
)
|
Box(modifier = Modifier.background(MaterialTheme.colors.background)) {
|
||||||
|
AppTabs(
|
||||||
|
onOpenSettings = {
|
||||||
|
showSettingsDialog = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showSettingsDialog) {
|
||||||
|
SettingsDialog(
|
||||||
|
settingsViewModel = settingsViewModel,
|
||||||
|
onDismiss = { showSettingsDialog = false }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,6 +118,7 @@ class App {
|
|||||||
appStateManager.cancelCoroutines()
|
appStateManager.cancelCoroutines()
|
||||||
this.exitApplication()
|
this.exitApplication()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ package app.preferences
|
|||||||
|
|
||||||
import app.extensions.defaultWindowPlacement
|
import app.extensions.defaultWindowPlacement
|
||||||
import app.theme.ColorsScheme
|
import app.theme.ColorsScheme
|
||||||
import app.theme.Themes
|
import app.theme.Theme
|
||||||
import app.theme.darkBlueTheme
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -12,7 +11,6 @@ import java.util.prefs.Preferences
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
|
|
||||||
private const val PREFERENCES_NAME = "GitnuroConfig"
|
private const val PREFERENCES_NAME = "GitnuroConfig"
|
||||||
|
|
||||||
@ -23,19 +21,21 @@ private const val PREF_COMMITS_LIMIT = "commitsLimit"
|
|||||||
private const val PREF_COMMITS_LIMIT_ENABLED = "commitsLimitEnabled"
|
private const val PREF_COMMITS_LIMIT_ENABLED = "commitsLimitEnabled"
|
||||||
private const val PREF_WINDOW_PLACEMENT = "windowsPlacement"
|
private const val PREF_WINDOW_PLACEMENT = "windowsPlacement"
|
||||||
private const val PREF_CUSTOM_THEME = "customTheme"
|
private const val PREF_CUSTOM_THEME = "customTheme"
|
||||||
|
private const val PREF_UI_SCALE = "ui_scale"
|
||||||
|
|
||||||
|
|
||||||
private const val PREF_GIT_FF_MERGE = "gitFFMerge"
|
private const val PREF_GIT_FF_MERGE = "gitFFMerge"
|
||||||
|
|
||||||
private const val DEFAULT_COMMITS_LIMIT = 1000
|
private const val DEFAULT_COMMITS_LIMIT = 1000
|
||||||
private const val DEFAULT_COMMITS_LIMIT_ENABLED = true
|
private const val DEFAULT_COMMITS_LIMIT_ENABLED = true
|
||||||
|
const val DEFAULT_UI_SCALE = -1f
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AppPreferences @Inject constructor() {
|
class AppPreferences @Inject constructor() {
|
||||||
private val preferences: Preferences = Preferences.userRoot().node(PREFERENCES_NAME)
|
private val preferences: Preferences = Preferences.userRoot().node(PREFERENCES_NAME)
|
||||||
|
|
||||||
private val _themeState = MutableStateFlow(theme)
|
private val _themeState = MutableStateFlow(theme)
|
||||||
val themeState: StateFlow<Themes> = _themeState
|
val themeState: StateFlow<Theme> = _themeState
|
||||||
|
|
||||||
private val _commitsLimitEnabledFlow = MutableStateFlow(commitsLimitEnabled)
|
private val _commitsLimitEnabledFlow = MutableStateFlow(commitsLimitEnabled)
|
||||||
val commitsLimitEnabledFlow: StateFlow<Boolean> = _commitsLimitEnabledFlow
|
val commitsLimitEnabledFlow: StateFlow<Boolean> = _commitsLimitEnabledFlow
|
||||||
@ -49,6 +49,9 @@ class AppPreferences @Inject constructor() {
|
|||||||
private val _customThemeFlow = MutableStateFlow<ColorsScheme?>(null)
|
private val _customThemeFlow = MutableStateFlow<ColorsScheme?>(null)
|
||||||
val customThemeFlow: StateFlow<ColorsScheme?> = _customThemeFlow
|
val customThemeFlow: StateFlow<ColorsScheme?> = _customThemeFlow
|
||||||
|
|
||||||
|
private val _scaleUiFlow = MutableStateFlow(scaleUi)
|
||||||
|
val scaleUiFlow: StateFlow<Float> = _scaleUiFlow
|
||||||
|
|
||||||
var latestTabsOpened: String
|
var latestTabsOpened: String
|
||||||
get() = preferences.get(PREF_LATEST_REPOSITORIES_TABS_OPENED, "")
|
get() = preferences.get(PREF_LATEST_REPOSITORIES_TABS_OPENED, "")
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -61,14 +64,14 @@ class AppPreferences @Inject constructor() {
|
|||||||
preferences.put(PREF_LAST_OPENED_REPOSITORIES_PATH, value)
|
preferences.put(PREF_LAST_OPENED_REPOSITORIES_PATH, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var theme: Themes
|
var theme: Theme
|
||||||
get() {
|
get() {
|
||||||
val lastTheme = preferences.get(PREF_THEME, Themes.DARK.toString())
|
val lastTheme = preferences.get(PREF_THEME, Theme.DARK.toString())
|
||||||
return try {
|
return try {
|
||||||
Themes.valueOf(lastTheme)
|
Theme.valueOf(lastTheme)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
Themes.DARK
|
Theme.DARK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -85,6 +88,15 @@ class AppPreferences @Inject constructor() {
|
|||||||
_commitsLimitEnabledFlow.value = value
|
_commitsLimitEnabledFlow.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var scaleUi: Float
|
||||||
|
get() {
|
||||||
|
return preferences.getFloat(PREF_UI_SCALE, DEFAULT_UI_SCALE)
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
preferences.putFloat(PREF_UI_SCALE, value)
|
||||||
|
_scaleUiFlow.value = value
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property that decides if the merge should fast-forward when possible
|
* Property that decides if the merge should fast-forward when possible
|
||||||
*/
|
*/
|
||||||
|
@ -13,15 +13,15 @@ private var appTheme: ColorsScheme = defaultAppTheme
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppTheme(
|
fun AppTheme(
|
||||||
selectedTheme: Themes = Themes.DARK,
|
selectedTheme: Theme = Theme.DARK,
|
||||||
customTheme: ColorsScheme?,
|
customTheme: ColorsScheme?,
|
||||||
content: @Composable() () -> Unit
|
content: @Composable() () -> Unit
|
||||||
) {
|
) {
|
||||||
val theme = when (selectedTheme) {
|
val theme = when (selectedTheme) {
|
||||||
Themes.LIGHT -> lightTheme
|
Theme.LIGHT -> lightTheme
|
||||||
Themes.DARK -> darkBlueTheme
|
Theme.DARK -> darkBlueTheme
|
||||||
Themes.DARK_GRAY -> darkGrayTheme
|
Theme.DARK_GRAY -> darkGrayTheme
|
||||||
Themes.CUSTOM -> customTheme ?: defaultAppTheme
|
Theme.CUSTOM -> customTheme ?: defaultAppTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
appTheme = theme
|
appTheme = theme
|
||||||
@ -99,7 +99,7 @@ val Colors.dialogOverlay: Color
|
|||||||
get() = appTheme.dialogOverlay
|
get() = appTheme.dialogOverlay
|
||||||
|
|
||||||
|
|
||||||
enum class Themes(val displayName: String) : DropDownOption {
|
enum class Theme(val displayName: String) : DropDownOption {
|
||||||
LIGHT("Light"),
|
LIGHT("Light"),
|
||||||
DARK("Dark"),
|
DARK("Dark"),
|
||||||
DARK_GRAY("Dark gray"),
|
DARK_GRAY("Dark gray"),
|
||||||
@ -109,9 +109,9 @@ enum class Themes(val displayName: String) : DropDownOption {
|
|||||||
get() = displayName
|
get() = displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
val themesList = listOf(
|
val themeLists = listOf(
|
||||||
Themes.LIGHT,
|
Theme.LIGHT,
|
||||||
Themes.DARK,
|
Theme.DARK,
|
||||||
Themes.DARK_GRAY,
|
Theme.DARK_GRAY,
|
||||||
Themes.CUSTOM,
|
Theme.CUSTOM,
|
||||||
)
|
)
|
@ -1,5 +1,6 @@
|
|||||||
package app.ui.dialogs
|
package app.ui.dialogs.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
@ -10,35 +11,54 @@ import androidx.compose.ui.text.input.KeyboardType
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
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 app.preferences.AppPreferences
|
|
||||||
import app.DropDownOption
|
import app.DropDownOption
|
||||||
import app.theme.*
|
import app.theme.*
|
||||||
import app.ui.components.AdjustableOutlinedTextField
|
import app.ui.components.AdjustableOutlinedTextField
|
||||||
|
import app.ui.components.ScrollableColumn
|
||||||
|
import app.ui.dialogs.MaterialDialog
|
||||||
import app.ui.openFileDialog
|
import app.ui.openFileDialog
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import app.extensions.handMouseClickable
|
||||||
|
import app.preferences.DEFAULT_UI_SCALE
|
||||||
|
import app.viewmodels.SettingsViewModel
|
||||||
|
|
||||||
|
enum class SettingsCategory(val displayName: String) {
|
||||||
|
UI("UI"),
|
||||||
|
GIT("Git"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsDialog(
|
fun SettingsDialog(
|
||||||
appPreferences: AppPreferences,
|
settingsViewModel: SettingsViewModel,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val currentTheme by appPreferences.themeState.collectAsState()
|
|
||||||
val commitsLimitEnabled by appPreferences.commitsLimitEnabledFlow.collectAsState()
|
LaunchedEffect(Unit) {
|
||||||
val ffMerge by appPreferences.ffMergeFlow.collectAsState()
|
settingsViewModel.resetInfo()
|
||||||
var commitsLimit by remember { mutableStateOf(appPreferences.commitsLimit) }
|
}
|
||||||
|
|
||||||
|
val categories = remember {
|
||||||
|
listOf(
|
||||||
|
SettingsCategory.UI,
|
||||||
|
SettingsCategory.GIT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedCategory by remember { mutableStateOf(SettingsCategory.UI) }
|
||||||
|
|
||||||
MaterialDialog(
|
MaterialDialog(
|
||||||
onCloseRequested = {
|
onCloseRequested = {
|
||||||
savePendingSettings(
|
settingsViewModel.savePendingChanges()
|
||||||
appPreferences = appPreferences,
|
|
||||||
commitsLimit = commitsLimit,
|
|
||||||
)
|
|
||||||
|
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.width(720.dp)) {
|
Column(modifier = Modifier.height(720.dp)) {
|
||||||
Text(
|
Text(
|
||||||
text = "Settings",
|
text = "Settings",
|
||||||
color = MaterialTheme.colors.primaryTextColor,
|
color = MaterialTheme.colors.primaryTextColor,
|
||||||
@ -46,69 +66,37 @@ fun SettingsDialog(
|
|||||||
modifier = Modifier.padding(top = 8.dp, bottom = 16.dp, start = 8.dp)
|
modifier = Modifier.padding(top = 8.dp, bottom = 16.dp, start = 8.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
SettingDropDown(
|
Row(modifier = Modifier.weight(1f)) {
|
||||||
title = "Theme",
|
ScrollableColumn(
|
||||||
subtitle = "Select the UI theme between light and dark mode",
|
modifier = Modifier
|
||||||
dropDownOptions = themesList,
|
.width(200.dp)
|
||||||
currentOption = currentTheme,
|
.fillMaxHeight()
|
||||||
onOptionSelected = { theme ->
|
) {
|
||||||
appPreferences.theme = theme
|
categories.forEach { category ->
|
||||||
}
|
Category(
|
||||||
)
|
category = category,
|
||||||
|
isSelected = category == selectedCategory,
|
||||||
if (currentTheme == Themes.CUSTOM) {
|
onClick = { selectedCategory = category }
|
||||||
SettingButton(
|
)
|
||||||
title = "Custom theme",
|
|
||||||
subtitle = "Select a JSON file to load the custom theme",
|
|
||||||
buttonText = "Open file",
|
|
||||||
onClick = {
|
|
||||||
val filePath = openFileDialog()
|
|
||||||
|
|
||||||
if (filePath != null) {
|
|
||||||
appPreferences.saveCustomTheme(filePath)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Column(modifier = Modifier.width(720.dp)) {
|
||||||
|
when (selectedCategory) {
|
||||||
|
SettingsCategory.UI -> UiSettings(settingsViewModel)
|
||||||
|
SettingsCategory.GIT -> GitSettings(settingsViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingToogle(
|
|
||||||
title = "Limit log commits",
|
|
||||||
subtitle = "Turning off this may affect the performance",
|
|
||||||
value = commitsLimitEnabled,
|
|
||||||
onValueChanged = { value ->
|
|
||||||
appPreferences.commitsLimitEnabled = value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
SettingIntInput(
|
|
||||||
title = "Max commits",
|
|
||||||
subtitle = "Increasing this value may affect the performance",
|
|
||||||
value = commitsLimit,
|
|
||||||
enabled = commitsLimitEnabled,
|
|
||||||
onValueChanged = { value ->
|
|
||||||
commitsLimit = value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
SettingToogle(
|
|
||||||
title = "Fast-forward merge",
|
|
||||||
subtitle = "Try to fast-forward merges when possible",
|
|
||||||
value = ffMerge,
|
|
||||||
onValueChanged = { value ->
|
|
||||||
appPreferences.ffMerge = value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
TextButton(
|
TextButton(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(end = 8.dp)
|
.padding(end = 8.dp)
|
||||||
.align(Alignment.End),
|
.align(Alignment.End),
|
||||||
colors = textButtonColors(),
|
colors = textButtonColors(),
|
||||||
onClick = {
|
onClick = {
|
||||||
savePendingSettings(
|
settingsViewModel.savePendingChanges()
|
||||||
appPreferences = appPreferences,
|
|
||||||
commitsLimit = commitsLimit,
|
|
||||||
)
|
|
||||||
|
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
@ -119,18 +107,126 @@ fun SettingsDialog(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun savePendingSettings(
|
@Composable
|
||||||
appPreferences: AppPreferences,
|
fun GitSettings(settingsViewModel: SettingsViewModel) {
|
||||||
commitsLimit: Int,
|
val commitsLimitEnabled by settingsViewModel.commitsLimitEnabledFlow.collectAsState()
|
||||||
) {
|
val ffMerge by settingsViewModel.ffMergeFlow.collectAsState()
|
||||||
if (appPreferences.commitsLimit != commitsLimit) {
|
var commitsLimit by remember { mutableStateOf(settingsViewModel.commitsLimit) }
|
||||||
appPreferences.commitsLimit = commitsLimit
|
|
||||||
}
|
SettingToggle(
|
||||||
|
title = "Limit log commits",
|
||||||
|
subtitle = "Turning off this may affect the performance",
|
||||||
|
value = commitsLimitEnabled,
|
||||||
|
onValueChanged = { value ->
|
||||||
|
settingsViewModel.commitsLimitEnabled = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
SettingIntInput(
|
||||||
|
title = "Max commits",
|
||||||
|
subtitle = "Increasing this value may affect the performance",
|
||||||
|
value = commitsLimit,
|
||||||
|
enabled = commitsLimitEnabled,
|
||||||
|
onValueChanged = { value ->
|
||||||
|
commitsLimit = value
|
||||||
|
settingsViewModel.commitsLimit = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
SettingToggle(
|
||||||
|
title = "Fast-forward merge",
|
||||||
|
subtitle = "Try to fast-forward merges when possible",
|
||||||
|
value = ffMerge,
|
||||||
|
onValueChanged = { value ->
|
||||||
|
settingsViewModel.ffMerge = value
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UiSettings(settingsViewModel: SettingsViewModel) {
|
||||||
|
val currentTheme by settingsViewModel.themeState.collectAsState()
|
||||||
|
|
||||||
|
SettingDropDown(
|
||||||
|
title = "Theme",
|
||||||
|
subtitle = "Select the UI theme between light and dark mode",
|
||||||
|
dropDownOptions = themeLists,
|
||||||
|
currentOption = currentTheme,
|
||||||
|
onOptionSelected = { theme ->
|
||||||
|
settingsViewModel.theme = theme
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (currentTheme == Theme.CUSTOM) {
|
||||||
|
SettingButton(
|
||||||
|
title = "Custom theme",
|
||||||
|
subtitle = "Select a JSON file to load the custom theme",
|
||||||
|
buttonText = "Open file",
|
||||||
|
onClick = {
|
||||||
|
val filePath = openFileDialog()
|
||||||
|
|
||||||
|
if (filePath != null) {
|
||||||
|
settingsViewModel.saveCustomTheme(filePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val density = LocalDensity.current.density
|
||||||
|
var scaleValue by remember {
|
||||||
|
val savedScaleUi = settingsViewModel.scaleUi
|
||||||
|
val scaleUi = if (savedScaleUi == DEFAULT_UI_SCALE) {
|
||||||
|
density
|
||||||
|
} else {
|
||||||
|
savedScaleUi
|
||||||
|
} * 100
|
||||||
|
|
||||||
|
mutableStateOf(scaleUi)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSlider(
|
||||||
|
title = "Scale",
|
||||||
|
subtitle = "Adapt the size the UI to your preferred scale",
|
||||||
|
value = scaleValue,
|
||||||
|
onValueChanged = { newValue ->
|
||||||
|
scaleValue = newValue
|
||||||
|
},
|
||||||
|
onValueChangeFinished = {
|
||||||
|
settingsViewModel.scaleUi = scaleValue / 100
|
||||||
|
},
|
||||||
|
steps = 5,
|
||||||
|
minValue = 100f,
|
||||||
|
maxValue = 300f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun <T : DropDownOption> SettingDropDown(
|
fun <T : DropDownOption> SettingDropDown(
|
||||||
title: String,
|
title: String,
|
||||||
@ -203,7 +299,7 @@ fun SettingButton(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingToogle(
|
fun SettingToggle(
|
||||||
title: String,
|
title: String,
|
||||||
subtitle: String,
|
subtitle: String,
|
||||||
value: Boolean,
|
value: Boolean,
|
||||||
@ -221,6 +317,46 @@ fun SettingToogle(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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, horizontal = 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
FieldTitles(title, subtitle)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "$minValue%",
|
||||||
|
style = MaterialTheme.typography.caption,
|
||||||
|
)
|
||||||
|
|
||||||
|
Slider(
|
||||||
|
value = value,
|
||||||
|
onValueChange = onValueChanged,
|
||||||
|
onValueChangeFinished = onValueChangeFinished,
|
||||||
|
steps = steps,
|
||||||
|
valueRange = minValue..maxValue,
|
||||||
|
modifier = Modifier.width(200.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "$maxValue%",
|
||||||
|
style = MaterialTheme.typography.caption,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingIntInput(
|
fun SettingIntInput(
|
||||||
title: String,
|
title: String,
|
||||||
@ -303,4 +439,13 @@ private fun isValidInt(value: String): Boolean {
|
|||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isValidFloat(value: String): Boolean {
|
||||||
|
return try {
|
||||||
|
value.toFloat()
|
||||||
|
true
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
@ -192,10 +192,11 @@ fun Log(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val density = LocalDensity.current.density
|
||||||
DividerLog(
|
DividerLog(
|
||||||
modifier = Modifier.draggable(
|
modifier = Modifier.draggable(
|
||||||
rememberDraggableState {
|
rememberDraggableState {
|
||||||
weightMod.value += it
|
weightMod.value += it * density
|
||||||
}, Orientation.Horizontal
|
}, Orientation.Horizontal
|
||||||
),
|
),
|
||||||
graphWidth = graphWidth,
|
graphWidth = graphWidth,
|
||||||
|
60
src/main/kotlin/app/viewmodels/SettingsViewModel.kt
Normal file
60
src/main/kotlin/app/viewmodels/SettingsViewModel.kt
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package app.viewmodels
|
||||||
|
|
||||||
|
import app.preferences.AppPreferences
|
||||||
|
import app.theme.Theme
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class SettingsViewModel @Inject constructor(
|
||||||
|
val appPreferences: AppPreferences,
|
||||||
|
) {
|
||||||
|
// Temporary values to detect changed variables
|
||||||
|
var commitsLimit: Int = -1
|
||||||
|
|
||||||
|
val themeState = appPreferences.themeState
|
||||||
|
val customThemeFlow = appPreferences.customThemeFlow
|
||||||
|
val ffMergeFlow = appPreferences.ffMergeFlow
|
||||||
|
val commitsLimitEnabledFlow = appPreferences.commitsLimitEnabledFlow
|
||||||
|
|
||||||
|
var scaleUi: Float
|
||||||
|
get() = appPreferences.scaleUi
|
||||||
|
set(value) {
|
||||||
|
appPreferences.scaleUi = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var commitsLimitEnabled: Boolean
|
||||||
|
get() = appPreferences.commitsLimitEnabled
|
||||||
|
set(value) {
|
||||||
|
appPreferences.commitsLimitEnabled = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var ffMerge: Boolean
|
||||||
|
get() = appPreferences.ffMerge
|
||||||
|
set(value) {
|
||||||
|
appPreferences.ffMerge = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var theme: Theme
|
||||||
|
get() = appPreferences.theme
|
||||||
|
set(value) {
|
||||||
|
appPreferences.theme = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveCustomTheme(filePath: String) {
|
||||||
|
appPreferences.saveCustomTheme(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun resetInfo() {
|
||||||
|
commitsLimit = appPreferences.commitsLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
fun savePendingChanges() {
|
||||||
|
val commitsLimit = this.commitsLimit
|
||||||
|
|
||||||
|
if (appPreferences.commitsLimit != commitsLimit) {
|
||||||
|
appPreferences.commitsLimit = commitsLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user