parent
be616315f8
commit
0a8c8ac1ed
@ -26,6 +26,7 @@ import com.jetpackduba.gitnuro.logging.printError
|
||||
import com.jetpackduba.gitnuro.managers.AppStateManager
|
||||
import com.jetpackduba.gitnuro.managers.TempFilesManager
|
||||
import com.jetpackduba.gitnuro.preferences.AppSettings
|
||||
import com.jetpackduba.gitnuro.preferences.ProxySettings
|
||||
import com.jetpackduba.gitnuro.system.systemSeparator
|
||||
import com.jetpackduba.gitnuro.theme.AppTheme
|
||||
import com.jetpackduba.gitnuro.theme.Theme
|
||||
@ -36,11 +37,17 @@ import com.jetpackduba.gitnuro.ui.components.RepositoriesTabPanel
|
||||
import com.jetpackduba.gitnuro.ui.components.TabInformation
|
||||
import com.jetpackduba.gitnuro.ui.components.emptyTabInformation
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.AppPopupMenu
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.settings.ProxyType
|
||||
import kotlinx.coroutines.launch
|
||||
import org.eclipse.jgit.lib.GpgSigner
|
||||
import java.io.File
|
||||
import java.net.Authenticator
|
||||
import java.net.PasswordAuthentication
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
private const val TAG = "App"
|
||||
|
||||
val LocalTabScope = compositionLocalOf { emptyTabInformation() }
|
||||
@ -73,6 +80,9 @@ class App {
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun start(args: Array<String>) {
|
||||
tabsManager.appComponent = this.appComponent
|
||||
|
||||
initProxySettings()
|
||||
|
||||
val windowPlacement = appSettings.windowPlacement.toWindowPlacement
|
||||
val dirToOpen = getDirToOpen(args)
|
||||
|
||||
@ -118,7 +128,8 @@ class App {
|
||||
state = windowState,
|
||||
icon = painterResource(AppIcons.LOGO),
|
||||
) {
|
||||
val compositionValues: MutableList<ProvidedValue<*>> = mutableListOf(LocalTextContextMenu provides AppPopupMenu())
|
||||
val compositionValues: MutableList<ProvidedValue<*>> =
|
||||
mutableListOf(LocalTextContextMenu provides AppPopupMenu())
|
||||
|
||||
if (scale != -1f) {
|
||||
compositionValues.add(LocalDensity provides Density(scale, 1f))
|
||||
@ -146,6 +157,71 @@ class App {
|
||||
}
|
||||
}
|
||||
|
||||
private fun initProxySettings() {
|
||||
appStateManager.appScope.launch {
|
||||
appSettings.proxyFlow.collect { proxySettings ->
|
||||
if (proxySettings.useProxy) {
|
||||
when (proxySettings.proxyType) {
|
||||
ProxyType.HTTP -> setHttpProxy(proxySettings)
|
||||
ProxyType.SOCKS -> setSocksProxy(proxySettings)
|
||||
}
|
||||
} else {
|
||||
clearProxySettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearProxySettings() {
|
||||
System.setProperty("http.proxyHost", "")
|
||||
System.setProperty("http.proxyPort", "")
|
||||
System.setProperty("https.proxyHost", "")
|
||||
System.setProperty("https.proxyPort", "")
|
||||
System.setProperty("socksProxyHost", "")
|
||||
System.setProperty("socksProxyPort", "")
|
||||
}
|
||||
|
||||
private fun setHttpProxy(proxySettings: ProxySettings) {
|
||||
System.setProperty("http.proxyHost", proxySettings.hostName)
|
||||
System.setProperty("http.proxyPort", proxySettings.hostPort.toString())
|
||||
System.setProperty("https.proxyHost", proxySettings.hostName)
|
||||
System.setProperty("https.proxyPort", proxySettings.hostPort.toString())
|
||||
|
||||
if (proxySettings.useAuth) {
|
||||
Authenticator.setDefault(
|
||||
object : Authenticator() {
|
||||
public override fun getPasswordAuthentication(): PasswordAuthentication {
|
||||
return PasswordAuthentication(proxySettings.hostUser, proxySettings.hostPassword.toCharArray())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
System.setProperty("http.proxyUser", proxySettings.hostUser)
|
||||
System.setProperty("http.proxyPassword", proxySettings.hostPassword)
|
||||
System.setProperty("https.proxyUser", proxySettings.hostUser)
|
||||
System.setProperty("https.proxyPassword", proxySettings.hostPassword)
|
||||
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setSocksProxy(proxySettings: ProxySettings) {
|
||||
System.setProperty("socksProxyHost", proxySettings.hostName)
|
||||
System.setProperty("socksProxyPort", proxySettings.hostPort.toString())
|
||||
|
||||
if (proxySettings.useAuth) {
|
||||
Authenticator.setDefault(
|
||||
object : Authenticator() {
|
||||
public override fun getPasswordAuthentication(): PasswordAuthentication {
|
||||
return PasswordAuthentication(proxySettings.hostUser, proxySettings.hostPassword.toCharArray())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
System.setProperty("java.net.socks.username", proxySettings.hostUser)
|
||||
System.setProperty("java.net.socks.password", proxySettings.hostPassword)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDirTab(dirToOpen: File) {
|
||||
val absolutePath = dirToOpen.normalize().absolutePath
|
||||
.removeSuffix(systemSeparator)
|
||||
|
@ -5,6 +5,7 @@ import com.jetpackduba.gitnuro.system.OS
|
||||
import com.jetpackduba.gitnuro.system.currentOs
|
||||
import com.jetpackduba.gitnuro.theme.ColorsScheme
|
||||
import com.jetpackduba.gitnuro.theme.Theme
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.settings.ProxyType
|
||||
import com.jetpackduba.gitnuro.viewmodels.TextDiffType
|
||||
import com.jetpackduba.gitnuro.viewmodels.textDiffTypeFromValue
|
||||
import kotlinx.coroutines.flow.*
|
||||
@ -30,6 +31,13 @@ private const val PREF_DIFF_TYPE = "diffType"
|
||||
private const val PREF_DIFF_FULL_FILE = "diffFullFile"
|
||||
private const val PREF_SWAP_UNCOMMITTED_CHANGES = "inverseUncommittedChanges"
|
||||
private const val PREF_TERMINAL_PATH = "terminalPath"
|
||||
private const val PREF_USE_PROXY = "useProxy"
|
||||
private const val PREF_PROXY_TYPE = "proxyType"
|
||||
private const val PREF_PROXY_HOST_NAME = "proxyHostName"
|
||||
private const val PREF_PROXY_PORT = "proxyPort"
|
||||
private const val PREF_PROXY_USE_AUTH = "proxyUseAuth"
|
||||
private const val PREF_PROXY_USER = "proxyHostUser"
|
||||
private const val PREF_PROXY_PASSWORD = "proxyHostPassword"
|
||||
private const val PREF_CACHE_CREDENTIALS_IN_MEMORY = "credentialsInMemory"
|
||||
|
||||
|
||||
@ -86,6 +94,20 @@ class AppSettings @Inject constructor() {
|
||||
private val _terminalPathFlow = MutableStateFlow(terminalPath)
|
||||
val terminalPathFlow = _terminalPathFlow.asStateFlow()
|
||||
|
||||
private val _proxyFlow = MutableStateFlow(
|
||||
ProxySettings(
|
||||
useProxy,
|
||||
proxyType,
|
||||
proxyHostName,
|
||||
proxyPortNumber,
|
||||
proxyUseAuth,
|
||||
proxyHostUser,
|
||||
proxyHostPassword,
|
||||
)
|
||||
)
|
||||
|
||||
val proxyFlow = _proxyFlow.asStateFlow()
|
||||
|
||||
var latestTabsOpened: String
|
||||
get() = preferences.get(PREF_LATEST_REPOSITORIES_TABS_OPENED, "")
|
||||
set(value) {
|
||||
@ -238,6 +260,62 @@ class AppSettings @Inject constructor() {
|
||||
_terminalPathFlow.value = value
|
||||
}
|
||||
|
||||
var useProxy: Boolean
|
||||
get() {
|
||||
return preferences.getBoolean(PREF_USE_PROXY, false)
|
||||
}
|
||||
set(value) {
|
||||
preferences.putBoolean(PREF_USE_PROXY, value)
|
||||
_proxyFlow.value = _proxyFlow.value.copy(useProxy = value)
|
||||
}
|
||||
|
||||
var proxyUseAuth: Boolean
|
||||
get() {
|
||||
return preferences.getBoolean(PREF_PROXY_USE_AUTH, false)
|
||||
}
|
||||
set(value) {
|
||||
preferences.putBoolean(PREF_PROXY_USE_AUTH, value)
|
||||
_proxyFlow.value = _proxyFlow.value.copy(useAuth = value)
|
||||
}
|
||||
|
||||
var proxyType: ProxyType
|
||||
get() {
|
||||
val value = preferences.getInt(PREF_PROXY_TYPE, ProxyType.HTTP.value)
|
||||
return ProxyType.fromInt(value)
|
||||
}
|
||||
set(value) {
|
||||
preferences.putInt(PREF_PROXY_TYPE, value.value)
|
||||
_proxyFlow.value = _proxyFlow.value.copy(proxyType = value)
|
||||
}
|
||||
|
||||
var proxyHostName: String
|
||||
get() = preferences.get(PREF_PROXY_HOST_NAME, "")
|
||||
set(value) {
|
||||
preferences.put(PREF_PROXY_HOST_NAME, value)
|
||||
_proxyFlow.value = _proxyFlow.value.copy(hostName = value)
|
||||
}
|
||||
|
||||
var proxyPortNumber: Int
|
||||
get() = preferences.getInt(PREF_PROXY_PORT, 80)
|
||||
set(value) {
|
||||
preferences.putInt(PREF_PROXY_PORT, value)
|
||||
_proxyFlow.value = _proxyFlow.value.copy(hostPort = value)
|
||||
}
|
||||
|
||||
var proxyHostUser: String
|
||||
get() = preferences.get(PREF_PROXY_USER, "")
|
||||
set(value) {
|
||||
preferences.put(PREF_PROXY_USER, value)
|
||||
_proxyFlow.value = _proxyFlow.value.copy(hostUser = value)
|
||||
}
|
||||
|
||||
var proxyHostPassword: String
|
||||
get() = preferences.get(PREF_PROXY_PASSWORD, "")
|
||||
set(value) {
|
||||
preferences.put(PREF_PROXY_PASSWORD, value)
|
||||
_proxyFlow.value = _proxyFlow.value.copy(hostPassword = value)
|
||||
}
|
||||
|
||||
fun saveCustomTheme(filePath: String) {
|
||||
val file = File(filePath)
|
||||
val content = file.readText()
|
||||
@ -254,8 +332,31 @@ class AppSettings @Inject constructor() {
|
||||
_customThemeFlow.value = Json.decodeFromString<ColorsScheme>(themeJson)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadProxySettings() {
|
||||
_proxyFlow.value = ProxySettings(
|
||||
useProxy,
|
||||
proxyType,
|
||||
proxyHostName,
|
||||
proxyPortNumber,
|
||||
proxyUseAuth,
|
||||
proxyHostUser,
|
||||
proxyHostPassword,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ProxySettings(
|
||||
val useProxy: Boolean,
|
||||
val proxyType: ProxyType,
|
||||
val hostName: String,
|
||||
val hostPort: Int,
|
||||
val useAuth: Boolean,
|
||||
val hostUser: String,
|
||||
val hostPassword: String,
|
||||
)
|
||||
|
||||
|
||||
// TODO migrate old prefs path to new one?
|
||||
fun initPreferencesPath() {
|
||||
if (currentOs == OS.LINUX) {
|
||||
|
@ -47,7 +47,7 @@ val settings = listOf(
|
||||
SettingsEntry.Entry(AppIcons.CLOUD, "Remote actions") { RemoteActions(it) },
|
||||
|
||||
SettingsEntry.Section("Network"),
|
||||
SettingsEntry.Entry(AppIcons.NETWORK, "Proxy") { Proxy() },
|
||||
SettingsEntry.Entry(AppIcons.NETWORK, "Proxy") { Proxy(it) },
|
||||
SettingsEntry.Entry(AppIcons.PASSWORD, "Authentication") { Authentication(it) },
|
||||
|
||||
SettingsEntry.Section("Tools"),
|
||||
@ -55,24 +55,32 @@ val settings = listOf(
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun Proxy() {
|
||||
var useProxy by remember { mutableStateOf(false) }
|
||||
fun Proxy(settingsViewModel: SettingsViewModel) {
|
||||
var useProxy by remember { mutableStateOf(settingsViewModel.useProxy) }
|
||||
|
||||
var hostName by remember { mutableStateOf("") }
|
||||
var portNumber by remember { mutableStateOf(80) }
|
||||
var login by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var hostName by remember { mutableStateOf(settingsViewModel.proxyHostName) }
|
||||
var portNumber by remember { mutableStateOf(settingsViewModel.proxyPortNumber) }
|
||||
|
||||
var useAuth by remember { mutableStateOf(settingsViewModel.proxyUseAuth) }
|
||||
var user by remember { mutableStateOf(settingsViewModel.proxyHostUser) }
|
||||
var password by remember { mutableStateOf(settingsViewModel.proxyHostPassword) }
|
||||
|
||||
val proxyTypes = listOf(ProxyType.HTTP, ProxyType.SOCKS)
|
||||
val proxyTypesDropDownOptions = proxyTypes.map { DropDownOption(it, it.name) }
|
||||
var currentProxyType by remember { mutableStateOf(proxyTypesDropDownOptions.first()) }
|
||||
|
||||
var currentProxyType by remember {
|
||||
mutableStateOf(proxyTypesDropDownOptions.first { it.value == settingsViewModel.proxyType })
|
||||
}
|
||||
|
||||
Column {
|
||||
SettingToggle(
|
||||
title = "Use proxy",
|
||||
subtitle = "Set up your proxy configuration if needed",
|
||||
value = useProxy,
|
||||
onValueChanged = { useProxy = it },
|
||||
onValueChanged = {
|
||||
useProxy = it
|
||||
settingsViewModel.useProxy = it
|
||||
},
|
||||
)
|
||||
|
||||
SettingDropDown(
|
||||
@ -80,14 +88,20 @@ fun Proxy() {
|
||||
subtitle = "Pick between HTTP or SOCKS",
|
||||
dropDownOptions = proxyTypesDropDownOptions,
|
||||
currentOption = currentProxyType,
|
||||
onOptionSelected = { currentProxyType = it }
|
||||
onOptionSelected = {
|
||||
currentProxyType = it
|
||||
settingsViewModel.proxyType = it.value
|
||||
}
|
||||
)
|
||||
|
||||
SettingTextInput(
|
||||
title = "Host name",
|
||||
subtitle = "",
|
||||
value = hostName,
|
||||
onValueChanged = { hostName = it },
|
||||
onValueChanged = {
|
||||
hostName = it
|
||||
settingsViewModel.proxyHostName = it
|
||||
},
|
||||
enabled = useProxy,
|
||||
)
|
||||
|
||||
@ -95,16 +109,32 @@ fun Proxy() {
|
||||
title = "Port number",
|
||||
subtitle = "",
|
||||
value = portNumber,
|
||||
onValueChanged = { portNumber = it },
|
||||
onValueChanged = {
|
||||
portNumber = it
|
||||
settingsViewModel.proxyPortNumber = it
|
||||
},
|
||||
enabled = useProxy,
|
||||
)
|
||||
|
||||
SettingToggle(
|
||||
title = "Proxy authentication",
|
||||
subtitle = "Use your credentials to provide your identity the proxy server",
|
||||
value = useAuth,
|
||||
onValueChanged = {
|
||||
useAuth = it
|
||||
settingsViewModel.proxyUseAuth = it
|
||||
}
|
||||
)
|
||||
|
||||
SettingTextInput(
|
||||
title = "Login",
|
||||
subtitle = "",
|
||||
value = login,
|
||||
onValueChanged = { login = it },
|
||||
enabled = useProxy,
|
||||
value = user,
|
||||
onValueChanged = {
|
||||
user = it
|
||||
settingsViewModel.proxyHostUser = it
|
||||
},
|
||||
enabled = useProxy && useAuth,
|
||||
)
|
||||
|
||||
|
||||
@ -112,9 +142,12 @@ fun Proxy() {
|
||||
title = "Password",
|
||||
subtitle = "",
|
||||
value = password,
|
||||
onValueChanged = { password = it },
|
||||
onValueChanged = {
|
||||
password = it
|
||||
settingsViewModel.proxyHostPassword = it
|
||||
},
|
||||
isPassword = true,
|
||||
enabled = useProxy,
|
||||
enabled = useProxy && useAuth,
|
||||
)
|
||||
|
||||
}
|
||||
@ -691,7 +724,17 @@ private fun isValidFloat(value: String): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
enum class ProxyType {
|
||||
HTTP,
|
||||
SOCKS,
|
||||
enum class ProxyType(val value: Int) {
|
||||
HTTP(1),
|
||||
SOCKS(2);
|
||||
|
||||
companion object {
|
||||
fun fromInt(value: Int): ProxyType {
|
||||
return when (value) {
|
||||
HTTP.value -> HTTP
|
||||
SOCKS.value -> SOCKS
|
||||
else -> throw NotImplementedError("Proxy type unknown")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import com.jetpackduba.gitnuro.preferences.AppSettings
|
||||
import com.jetpackduba.gitnuro.system.OpenFilePickerUseCase
|
||||
import com.jetpackduba.gitnuro.system.PickerType
|
||||
import com.jetpackduba.gitnuro.theme.Theme
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.settings.ProxyType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
@ -84,6 +85,48 @@ class SettingsViewModel @Inject constructor(
|
||||
appSettings.terminalPath = value
|
||||
}
|
||||
|
||||
var useProxy: Boolean
|
||||
get() = appSettings.useProxy
|
||||
set(value) {
|
||||
appSettings.useProxy = value
|
||||
}
|
||||
|
||||
var proxyType: ProxyType
|
||||
get() = appSettings.proxyType
|
||||
set(value) {
|
||||
appSettings.proxyType = value
|
||||
}
|
||||
|
||||
var proxyHostName: String
|
||||
get() = appSettings.proxyHostName
|
||||
set(value) {
|
||||
appSettings.proxyHostName = value
|
||||
}
|
||||
|
||||
var proxyPortNumber: Int
|
||||
get() = appSettings.proxyPortNumber
|
||||
set(value) {
|
||||
appSettings.proxyPortNumber = value
|
||||
}
|
||||
|
||||
var proxyUseAuth: Boolean
|
||||
get() = appSettings.proxyUseAuth
|
||||
set(value) {
|
||||
appSettings.proxyUseAuth = value
|
||||
}
|
||||
|
||||
var proxyHostUser: String
|
||||
get() = appSettings.proxyHostUser
|
||||
set(value) {
|
||||
appSettings.proxyHostUser = value
|
||||
}
|
||||
|
||||
var proxyHostPassword: String
|
||||
get() = appSettings.proxyHostPassword
|
||||
set(value) {
|
||||
appSettings.proxyHostPassword = value
|
||||
}
|
||||
|
||||
fun saveCustomTheme(filePath: String): Error? {
|
||||
return try {
|
||||
appSettings.saveCustomTheme(filePath)
|
||||
|
Loading…
Reference in New Issue
Block a user