diff --git a/src/main/kotlin/app/App.kt b/src/main/kotlin/app/App.kt index 7265e1d..b72f62f 100644 --- a/src/main/kotlin/app/App.kt +++ b/src/main/kotlin/app/App.kt @@ -28,6 +28,7 @@ import app.theme.AppTheme import app.ui.AppTab import app.ui.components.RepositoriesTabPanel import app.ui.components.TabInformation +import app.ui.dialogs.SettingsDialog import javax.inject.Inject import javax.inject.Provider @@ -40,6 +41,9 @@ class Main { @Inject lateinit var appStateManager: AppStateManager + @Inject + lateinit var appPreferences: AppPreferences + init { appComponent.inject(this) @@ -48,7 +52,7 @@ class Main { fun start() = application { var isOpen by remember { mutableStateOf(true) } - + val theme by appPreferences.themeState.collectAsState() if (isOpen) { Window( title = "Gitnuro", @@ -61,9 +65,22 @@ class Main { ), icon = painterResource("logo.svg"), ) { - AppTheme { - Box { - AppTabs() + var showSettingsDialog by remember { mutableStateOf(false) } + + AppTheme(theme = theme) { + Box (modifier = Modifier.background(MaterialTheme.colors.background)) { + AppTabs( + onOpenSettings = { + showSettingsDialog = true + } + ) + } + + if(showSettingsDialog) { + SettingsDialog( + appPreferences = appPreferences, + onDismiss = { showSettingsDialog = false } + ) } } } @@ -71,8 +88,12 @@ class Main { } + + @Composable - fun AppTabs() { + fun AppTabs( + onOpenSettings: () -> Unit, + ) { val tabs = remember { val repositoriesSavedTabs = appStateManager.openRepositoriesPathsTabs var repoTabs = repositoriesSavedTabs.map { repositoryTab -> @@ -99,6 +120,7 @@ class Main { Tabs( tabs = tabs, selectedTabKey = selectedTabKey, + onOpenSettings = onOpenSettings ) TabsContent(tabs.value, selectedTabKey.value) @@ -109,6 +131,7 @@ class Main { fun Tabs( tabs: MutableState>, selectedTabKey: MutableState, + onOpenSettings: () -> Unit, ) { Row( modifier = Modifier @@ -140,7 +163,7 @@ class Main { modifier = Modifier .padding(horizontal = 8.dp) .size(24.dp), - onClick = {} + onClick = onOpenSettings ) { Icon( painter = painterResource("settings.svg"), diff --git a/src/main/kotlin/app/AppPreferences.kt b/src/main/kotlin/app/AppPreferences.kt index ee2fb6b..3c5b35e 100644 --- a/src/main/kotlin/app/AppPreferences.kt +++ b/src/main/kotlin/app/AppPreferences.kt @@ -1,5 +1,8 @@ package app +import app.theme.Themes +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import java.util.prefs.Preferences import javax.inject.Inject import javax.inject.Singleton @@ -8,11 +11,15 @@ private const val PREFERENCES_NAME = "GitnuroConfig" private const val PREF_LATEST_REPOSITORIES_TABS_OPENED = "latestRepositoriesTabsOpened" private const val PREF_LAST_OPENED_REPOSITORIES_PATH = "lastOpenedRepositoriesList" +private const val PREF_THEME = "theme" @Singleton class AppPreferences @Inject constructor() { private val preferences: Preferences = Preferences.userRoot().node(PREFERENCES_NAME) + private val _themeState = MutableStateFlow(theme) + val themeState: StateFlow = _themeState + var latestTabsOpened: String get() = preferences.get(PREF_LATEST_REPOSITORIES_TABS_OPENED, "") set(value) { @@ -24,4 +31,14 @@ class AppPreferences @Inject constructor() { set(value) { preferences.put(PREF_LAST_OPENED_REPOSITORIES_PATH, value) } + + var theme: Themes + get() { + val lastTheme = preferences.get(PREF_THEME, Themes.LIGHT.toString()) + return Themes.valueOf(lastTheme) + } + set(value) { + preferences.put(PREF_THEME, value.toString()) + _themeState.value = value + } } \ No newline at end of file diff --git a/src/main/kotlin/app/theme/Theme.kt b/src/main/kotlin/app/theme/Theme.kt index db8eeeb..8fa71ce 100644 --- a/src/main/kotlin/app/theme/Theme.kt +++ b/src/main/kotlin/app/theme/Theme.kt @@ -24,11 +24,10 @@ private val LightColorPalette = lightColors( ) @Composable -fun AppTheme(darkTheme: Boolean = false, content: @Composable() () -> Unit) { - val colors = if (darkTheme) { - DarkColorPalette - } else { - LightColorPalette +fun AppTheme(theme: Themes = Themes.LIGHT, content: @Composable() () -> Unit) { + val colors = when(theme) { + Themes.LIGHT -> LightColorPalette + Themes.DARK -> DarkColorPalette } MaterialTheme( @@ -91,3 +90,12 @@ val Colors.tabColorInactive: Color get() = if (isLight) primaryLight else tabColorInactiveDark +enum class Themes(val displayName: String) { + LIGHT("Light"), + DARK("Dark") +} + +val themesList = listOf( + Themes.LIGHT, + Themes.DARK, +) \ No newline at end of file diff --git a/src/main/kotlin/app/ui/AppTab.kt b/src/main/kotlin/app/ui/AppTab.kt index 26b4fe2..242149c 100644 --- a/src/main/kotlin/app/ui/AppTab.kt +++ b/src/main/kotlin/app/ui/AppTab.kt @@ -74,10 +74,9 @@ fun AppTab( Box { Column( modifier = Modifier - .background(tabBackground) + .background(MaterialTheme.colors.surface) .fillMaxSize() ) { - val linearProgressAlpha = if (isProcessing) DefaultAlpha else diff --git a/src/main/kotlin/app/ui/UncommitedChanges.kt b/src/main/kotlin/app/ui/UncommitedChanges.kt index 239255f..7933519 100644 --- a/src/main/kotlin/app/ui/UncommitedChanges.kt +++ b/src/main/kotlin/app/ui/UncommitedChanges.kt @@ -38,6 +38,7 @@ import app.git.StageStatus import org.eclipse.jgit.diff.DiffEntry import app.theme.headerBackground import app.theme.headerText +import app.theme.primaryTextColor @OptIn(ExperimentalAnimationApi::class, androidx.compose.ui.ExperimentalComposeUiApi::class) @Composable @@ -311,6 +312,7 @@ private fun FileEntry( maxLines = 1, overflow = TextOverflow.Ellipsis, fontSize = 14.sp, + color = MaterialTheme.colors.primaryTextColor, ) } } diff --git a/src/main/kotlin/app/ui/dialogs/CloneDialog.kt b/src/main/kotlin/app/ui/dialogs/CloneDialog.kt index 1af2c4d..892b7a3 100644 --- a/src/main/kotlin/app/ui/dialogs/CloneDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/CloneDialog.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import app.git.CloneStatus import app.git.GitManager +import app.theme.primaryTextColor import java.io.File @Composable @@ -30,7 +31,10 @@ fun CloneDialog( onClose() } - Text("Clone a repository") + Text( + "Clone a repository", + color = MaterialTheme.colors.primaryTextColor, + ) OutlinedTextField( modifier = Modifier diff --git a/src/main/kotlin/app/ui/dialogs/MergeDialog.kt b/src/main/kotlin/app/ui/dialogs/MergeDialog.kt index 54fec9e..c0e4a9a 100644 --- a/src/main/kotlin/app/ui/dialogs/MergeDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/MergeDialog.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import app.theme.primaryTextColor @OptIn(ExperimentalFoundationApi::class) @Composable @@ -41,18 +42,21 @@ fun MergeDialog( Text( text = mergeBranchName, - fontWeight = FontWeight.Medium + fontWeight = FontWeight.Medium, + color = MaterialTheme.colors.primaryTextColor, ) Text( text = "will be merged into", - modifier = Modifier.padding(horizontal = 8.dp) + modifier = Modifier.padding(horizontal = 8.dp), + color = MaterialTheme.colors.primaryTextColor, ) Text( text = currentBranchName, - fontWeight = FontWeight.Medium + fontWeight = FontWeight.Medium, + color = MaterialTheme.colors.primaryTextColor, ) } diff --git a/src/main/kotlin/app/ui/dialogs/PasswordDialog.kt b/src/main/kotlin/app/ui/dialogs/PasswordDialog.kt index 770ff69..35351de 100644 --- a/src/main/kotlin/app/ui/dialogs/PasswordDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/PasswordDialog.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import app.theme.primaryTextColor @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -39,6 +40,7 @@ fun PasswordDialog( text = "Introduce your default SSH key's password", modifier = Modifier .padding(vertical = 8.dp), + color = MaterialTheme.colors.primaryTextColor, ) OutlinedTextField( modifier = Modifier.padding(bottom = 8.dp) diff --git a/src/main/kotlin/app/ui/dialogs/ResetDialog.kt b/src/main/kotlin/app/ui/dialogs/ResetDialog.kt index 999cade..a0792d5 100644 --- a/src/main/kotlin/app/ui/dialogs/ResetDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/ResetDialog.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import app.git.ResetType +import app.theme.primaryTextColor @Composable fun ResetBranchDialog( @@ -109,7 +110,8 @@ fun RadioButtonText( Text( text = text, - modifier = Modifier.padding(horizontal = 8.dp) + modifier = Modifier.padding(horizontal = 8.dp), + color = MaterialTheme.colors.primaryTextColor, ) } } \ No newline at end of file diff --git a/src/main/kotlin/app/ui/dialogs/SettingsDialog.kt b/src/main/kotlin/app/ui/dialogs/SettingsDialog.kt new file mode 100644 index 0000000..d82298a --- /dev/null +++ b/src/main/kotlin/app/ui/dialogs/SettingsDialog.kt @@ -0,0 +1,72 @@ +@file:Suppress("UNUSED_PARAMETER") + +package app.ui.dialogs + +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import app.AppPreferences +import androidx.compose.ui.Alignment +import app.theme.Themes +import app.theme.primaryTextColor +import app.theme.themesList + +@Composable +fun SettingsDialog( + appPreferences: AppPreferences, + onDismiss: () -> Unit, +) { + var showThemeDropdown by remember { mutableStateOf(false) } + val currentTheme by appPreferences.themeState.collectAsState() + + MaterialDialog { + Column { + Text( + text = "Settings", + color = MaterialTheme.colors.primaryTextColor, + ) + + Row( + modifier = Modifier.padding(top = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Theme", + color = MaterialTheme.colors.primaryTextColor, + ) + Spacer(modifier = Modifier.width(300.dp)) + OutlinedButton(onClick = { showThemeDropdown = true }) { + Text( + currentTheme.displayName, + color = MaterialTheme.colors.primaryTextColor, + ) + + DropdownMenu( + expanded = showThemeDropdown, + onDismissRequest = { showThemeDropdown = false }, + ) { + for (theme in themesList) { + DropdownMenuItem( + onClick = { + appPreferences.theme = theme + showThemeDropdown = false + } + ) { Text(theme.displayName) } + } + } + } + } + + TextButton( + modifier = Modifier + .padding(end = 8.dp) + .align(Alignment.End), + onClick = onDismiss + ) { + Text("Close") + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/ui/dialogs/UserPasswordDialog.kt b/src/main/kotlin/app/ui/dialogs/UserPasswordDialog.kt index b15fab8..ca75480 100644 --- a/src/main/kotlin/app/ui/dialogs/UserPasswordDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/UserPasswordDialog.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import app.theme.primaryTextColor @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -43,6 +44,7 @@ fun UserPasswordDialog( text = "Introduce your remote server credentials", modifier = Modifier .padding(vertical = 8.dp), + color = MaterialTheme.colors.primaryTextColor, ) OutlinedTextField(