From c3f8de99be1f81958a1d7a7546f948930b38a322 Mon Sep 17 00:00:00 2001 From: Aditya Wasan Date: Sat, 22 May 2021 17:25:43 +0530 Subject: [PATCH] app: refactor GitSettings and ProxyUtils and inject them using hilt Signed-off-by: Aditya Wasan --- .../java/dev/msfjarvis/aps/Application.kt | 14 +++-- .../aps/ui/git/base/BaseGitActivity.kt | 19 ++++--- .../aps/ui/git/config/GitConfigActivity.kt | 15 +++--- .../ui/git/config/GitServerConfigActivity.kt | 12 ++--- .../aps/ui/passwords/PasswordFragment.kt | 3 +- .../aps/ui/passwords/PasswordStore.kt | 2 +- .../aps/ui/proxy/ProxySelectorActivity.kt | 16 ++++-- .../aps/ui/settings/RepositorySettings.kt | 23 +++++++-- .../aps/util/git/GitCommandExecutor.kt | 17 ++++++- .../aps/util/git/operation/GitOperation.kt | 17 ++++++- .../msfjarvis/aps/util/proxy/ProxyUtils.kt | 21 +++++--- .../aps/util/settings/GitSettings.kt | 51 ++++++++----------- .../msfjarvis/aps/util/settings/Migrations.kt | 21 ++++---- 13 files changed, 140 insertions(+), 91 deletions(-) diff --git a/app/src/main/java/dev/msfjarvis/aps/Application.kt b/app/src/main/java/dev/msfjarvis/aps/Application.kt index d7ca97bc..508bdbf9 100644 --- a/app/src/main/java/dev/msfjarvis/aps/Application.kt +++ b/app/src/main/java/dev/msfjarvis/aps/Application.kt @@ -16,18 +16,24 @@ import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES import com.github.ajalt.timberkt.Timber.DebugTree import com.github.ajalt.timberkt.Timber.plant import dagger.hilt.android.HiltAndroidApp +import dev.msfjarvis.aps.injection.context.FilesDirPath +import dev.msfjarvis.aps.injection.prefs.SettingsPreferences import dev.msfjarvis.aps.util.extensions.getString -import dev.msfjarvis.aps.util.extensions.sharedPrefs import dev.msfjarvis.aps.util.git.sshj.setUpBouncyCastleForSshj import dev.msfjarvis.aps.util.proxy.ProxyUtils +import dev.msfjarvis.aps.util.settings.GitSettings import dev.msfjarvis.aps.util.settings.PreferenceKeys import dev.msfjarvis.aps.util.settings.runMigrations +import javax.inject.Inject @Suppress("Unused") @HiltAndroidApp class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener { - private val prefs by lazy { sharedPrefs } + @Inject @SettingsPreferences lateinit var prefs: SharedPreferences + @Inject @FilesDirPath lateinit var filesDirPath: String + @Inject lateinit var proxyUtils: ProxyUtils + @Inject lateinit var gitSettings: GitSettings override fun onCreate() { super.onCreate() @@ -42,8 +48,8 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere prefs.registerOnSharedPreferenceChangeListener(this) setNightMode() setUpBouncyCastleForSshj() - runMigrations(applicationContext) - ProxyUtils.setDefaultProxy() + runMigrations(filesDirPath, prefs, gitSettings) + proxyUtils.setDefaultProxy() } override fun onTerminate() { diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/git/base/BaseGitActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/git/base/BaseGitActivity.kt index b9bfd911..1d917a3a 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/git/base/BaseGitActivity.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/git/base/BaseGitActivity.kt @@ -12,6 +12,7 @@ import com.github.michaelbull.result.Result import com.github.michaelbull.result.andThen import com.github.michaelbull.result.mapError import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dagger.hilt.android.AndroidEntryPoint import dev.msfjarvis.aps.R import dev.msfjarvis.aps.util.extensions.getEncryptedGitPrefs import dev.msfjarvis.aps.util.extensions.sharedPrefs @@ -25,6 +26,7 @@ import dev.msfjarvis.aps.util.git.operation.SyncOperation import dev.msfjarvis.aps.util.git.sshj.ContinuationContainerActivity import dev.msfjarvis.aps.util.settings.GitSettings import dev.msfjarvis.aps.util.settings.PreferenceKeys +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import net.schmizz.sshj.common.DisconnectReason @@ -36,6 +38,7 @@ import net.schmizz.sshj.userauth.UserAuthException * Abstract [AppCompatActivity] that holds some information that is commonly shared across * git-related tasks and makes sense to be held here. */ +@AndroidEntryPoint abstract class BaseGitActivity : ContinuationContainerActivity() { /** Enum of possible Git operations than can be run through [launchGitOperation]. */ @@ -48,29 +51,31 @@ abstract class BaseGitActivity : ContinuationContainerActivity() { SYNC, } + @Inject lateinit var gitSettings: GitSettings + /** * Attempt to launch the requested Git operation. * @param operation The type of git operation to launch */ suspend fun launchGitOperation(operation: GitOp): Result { - if (GitSettings.url == null) { + if (gitSettings.url == null) { return Err(IllegalStateException("Git url is not set!")) } - if (operation == GitOp.SYNC && !GitSettings.useMultiplexing) { + if (operation == GitOp.SYNC && !gitSettings.useMultiplexing) { // If the server does not support multiple SSH channels per connection, we cannot run // a sync operation without reconnecting and thus break sync into its two parts. return launchGitOperation(GitOp.PULL).andThen { launchGitOperation(GitOp.PUSH) } } val op = when (operation) { - GitOp.CLONE -> CloneOperation(this, GitSettings.url!!) - GitOp.PULL -> PullOperation(this, GitSettings.rebaseOnPull) + GitOp.CLONE -> CloneOperation(this, gitSettings.url!!) + GitOp.PULL -> PullOperation(this, gitSettings.rebaseOnPull) GitOp.PUSH -> PushOperation(this) - GitOp.SYNC -> SyncOperation(this, GitSettings.rebaseOnPull) + GitOp.SYNC -> SyncOperation(this, gitSettings.rebaseOnPull) GitOp.BREAK_OUT_OF_DETACHED -> BreakOutOfDetached(this) GitOp.RESET -> ResetToRemoteOperation(this) } - return op.executeAfterAuthentication(GitSettings.authMode).mapError(::transformGitError) + return op.executeAfterAuthentication(gitSettings.authMode).mapError(::transformGitError) } fun finishOnSuccessHandler(@Suppress("UNUSED_PARAMETER") nothing: Unit) { @@ -105,7 +110,7 @@ abstract class BaseGitActivity : ContinuationContainerActivity() { val err = rootCauseException(throwable) return when { err.message?.contains("cannot open additional channels") == true -> { - GitSettings.useMultiplexing = false + gitSettings.useMultiplexing = false SSHException( DisconnectReason.TOO_MANY_CONNECTIONS, "The server does not support multiple Git operations per SSH session. Please try again, a slower fallback mode will be used." diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitConfigActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitConfigActivity.kt index faaf426f..8ca719eb 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitConfigActivity.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitConfigActivity.kt @@ -25,7 +25,6 @@ import dev.msfjarvis.aps.databinding.ActivityGitConfigBinding import dev.msfjarvis.aps.ui.git.base.BaseGitActivity import dev.msfjarvis.aps.ui.git.log.GitLogActivity import dev.msfjarvis.aps.util.extensions.viewBinding -import dev.msfjarvis.aps.util.settings.GitSettings import kotlinx.coroutines.launch import org.eclipse.jgit.lib.Constants import org.eclipse.jgit.lib.Repository @@ -40,9 +39,9 @@ class GitConfigActivity : BaseGitActivity() { setContentView(binding.root) supportActionBar?.setDisplayHomeAsUpEnabled(true) - if (GitSettings.authorName.isEmpty()) binding.gitUserName.requestFocus() - else binding.gitUserName.setText(GitSettings.authorName) - binding.gitUserEmail.setText(GitSettings.authorEmail) + if (gitSettings.authorName.isEmpty()) binding.gitUserName.requestFocus() + else binding.gitUserName.setText(gitSettings.authorName) + binding.gitUserEmail.setText(gitSettings.authorEmail) setupTools() binding.saveButton.setOnClickListener { val email = binding.gitUserEmail.text.toString().trim() @@ -53,8 +52,8 @@ class GitConfigActivity : BaseGitActivity() { .setPositiveButton(getString(R.string.dialog_ok), null) .show() } else { - GitSettings.authorEmail = email - GitSettings.authorName = name + gitSettings.authorEmail = email + gitSettings.authorName = name Snackbar.make( binding.root, getString(R.string.git_server_config_save_success), @@ -102,8 +101,8 @@ class GitConfigActivity : BaseGitActivity() { setMessage( resources.getString( R.string.git_break_out_of_detached_success, - GitSettings.branch, - "conflicting-${GitSettings.branch}-...", + gitSettings.branch, + "conflicting-${gitSettings.branch}-...", ) ) setOnDismissListener { finish() } diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitServerConfigActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitServerConfigActivity.kt index cab8d3ae..5265131b 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitServerConfigActivity.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitServerConfigActivity.kt @@ -54,7 +54,7 @@ class GitServerConfigActivity : BaseGitActivity() { setContentView(binding.root) supportActionBar?.setDisplayHomeAsUpEnabled(true) - newAuthMode = GitSettings.authMode + newAuthMode = gitSettings.authMode binding.authModeGroup.apply { when (newAuthMode) { @@ -74,21 +74,21 @@ class GitServerConfigActivity : BaseGitActivity() { } binding.serverUrl.setText( - GitSettings.url.also { + gitSettings.url.also { if (it.isNullOrEmpty()) return@also setAuthModes(it.startsWith("http://") || it.startsWith("https://")) } ) - binding.serverBranch.setText(GitSettings.branch) + binding.serverBranch.setText(gitSettings.branch) binding.serverUrl.doOnTextChanged { text, _, _, _ -> if (text.isNullOrEmpty()) return@doOnTextChanged setAuthModes(text.startsWith("http://") || text.startsWith("https://")) } - binding.clearHostKeyButton.isVisible = GitSettings.hasSavedHostKey() + binding.clearHostKeyButton.isVisible = gitSettings.hasSavedHostKey() binding.clearHostKeyButton.setOnClickListener { - GitSettings.clearSavedHostKey() + gitSettings.clearSavedHostKey() Snackbar.make( binding.root, getString(R.string.clear_saved_host_key_success), @@ -135,7 +135,7 @@ class GitServerConfigActivity : BaseGitActivity() { return@setOnClickListener } when (val updateResult = - GitSettings.updateConnectionSettingsIfValid( + gitSettings.updateConnectionSettingsIfValid( newAuthMode = newAuthMode, newUrl = binding.serverUrl.text.toString().trim(), newBranch = binding.serverBranch.text.toString().trim() diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt index c0f2616d..063f472c 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt @@ -53,6 +53,7 @@ import me.zhanghai.android.fastscroll.FastScrollerBuilder @AndroidEntryPoint class PasswordFragment : Fragment(R.layout.password_recycler_view) { + @Inject lateinit var gitSettings: GitSettings @Inject lateinit var shortcutHandler: ShortcutHandler private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter private lateinit var listener: OnFragmentInteractionListener @@ -111,7 +112,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) { // When authentication is set to AuthMode.None then the only git operation we can // run is a pull, so automatically fallback to that. val operationId = - when (GitSettings.authMode) { + when (gitSettings.authMode) { AuthMode.None -> BaseGitActivity.GitOp.PULL else -> BaseGitActivity.GitOp.SYNC } diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt index b2591a92..d2f6ca38 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt @@ -243,7 +243,7 @@ class PasswordStore : BaseGitActivity() { override fun onCreateOptionsMenu(menu: Menu?): Boolean { val menuRes = when { - GitSettings.authMode == AuthMode.None -> R.menu.main_menu_no_auth + gitSettings.authMode == AuthMode.None -> R.menu.main_menu_no_auth PasswordRepository.isGitRepo() -> R.menu.main_menu_git else -> R.menu.main_menu_non_git } diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/proxy/ProxySelectorActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/proxy/ProxySelectorActivity.kt index e3761292..936104e3 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/proxy/ProxySelectorActivity.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/proxy/ProxySelectorActivity.kt @@ -13,6 +13,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.content.edit import androidx.core.os.postDelayed import androidx.core.widget.doOnTextChanged +import dagger.hilt.android.AndroidEntryPoint import dev.msfjarvis.aps.R import dev.msfjarvis.aps.databinding.ActivityProxySelectorBinding import dev.msfjarvis.aps.util.extensions.getEncryptedProxyPrefs @@ -21,12 +22,17 @@ import dev.msfjarvis.aps.util.extensions.viewBinding import dev.msfjarvis.aps.util.proxy.ProxyUtils import dev.msfjarvis.aps.util.settings.GitSettings import dev.msfjarvis.aps.util.settings.PreferenceKeys +import javax.inject.Inject private val IP_ADDRESS_REGEX = Patterns.IP_ADDRESS.toRegex() private val WEB_ADDRESS_REGEX = Patterns.WEB_URL.toRegex() +@AndroidEntryPoint class ProxySelectorActivity : AppCompatActivity() { + @Inject lateinit var gitSettings: GitSettings + @Inject lateinit var proxyUtils: ProxyUtils + private val binding by viewBinding(ActivityProxySelectorBinding::inflate) private val proxyPrefs by lazy(LazyThreadSafetyMode.NONE) { applicationContext.getEncryptedProxyPrefs() @@ -59,19 +65,19 @@ class ProxySelectorActivity : AppCompatActivity() { private fun saveSettings() { proxyPrefs.edit { binding.proxyHost.text?.toString()?.takeIf { it.isNotEmpty() }.let { - GitSettings.proxyHost = it + gitSettings.proxyHost = it } binding.proxyUser.text?.toString()?.takeIf { it.isNotEmpty() }.let { - GitSettings.proxyUsername = it + gitSettings.proxyUsername = it } binding.proxyPort.text?.toString()?.takeIf { it.isNotEmpty() }?.let { - GitSettings.proxyPort = it.toInt() + gitSettings.proxyPort = it.toInt() } binding.proxyPassword.text?.toString()?.takeIf { it.isNotEmpty() }.let { - GitSettings.proxyPassword = it + gitSettings.proxyPassword = it } } - ProxyUtils.setDefaultProxy() + proxyUtils.setDefaultProxy() Handler(Looper.getMainLooper()).postDelayed(500) { finish() } } } diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/settings/RepositorySettings.kt b/app/src/main/java/dev/msfjarvis/aps/ui/settings/RepositorySettings.kt index ba871f91..a9055408 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/settings/RepositorySettings.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/settings/RepositorySettings.kt @@ -6,6 +6,7 @@ package dev.msfjarvis.aps.ui.settings import android.content.Intent +import android.content.SharedPreferences import android.content.pm.ShortcutManager import android.os.Build import androidx.core.content.edit @@ -14,6 +15,10 @@ import androidx.fragment.app.FragmentActivity import com.github.michaelbull.result.onFailure import com.github.michaelbull.result.runCatching import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.android.EntryPointAccessors +import dagger.hilt.components.SingletonComponent import de.Maxr1998.modernpreferences.Preference import de.Maxr1998.modernpreferences.PreferenceScreen import de.Maxr1998.modernpreferences.helpers.checkBox @@ -22,13 +27,13 @@ import de.Maxr1998.modernpreferences.helpers.onClick import de.Maxr1998.modernpreferences.helpers.pref import dev.msfjarvis.aps.R import dev.msfjarvis.aps.data.repo.PasswordRepository +import dev.msfjarvis.aps.injection.prefs.GitPreferences import dev.msfjarvis.aps.ui.git.config.GitConfigActivity import dev.msfjarvis.aps.ui.git.config.GitServerConfigActivity import dev.msfjarvis.aps.ui.proxy.ProxySelectorActivity import dev.msfjarvis.aps.ui.sshkeygen.ShowSshKeyFragment import dev.msfjarvis.aps.ui.sshkeygen.SshKeyGenActivity import dev.msfjarvis.aps.ui.sshkeygen.SshKeyImportActivity -import dev.msfjarvis.aps.util.extensions.getEncryptedGitPrefs import dev.msfjarvis.aps.util.extensions.getString import dev.msfjarvis.aps.util.extensions.sharedPrefs import dev.msfjarvis.aps.util.extensions.snackbar @@ -37,9 +42,10 @@ import dev.msfjarvis.aps.util.settings.PreferenceKeys class RepositorySettings(private val activity: FragmentActivity) : SettingsProvider { - private val encryptedPreferences by lazy(LazyThreadSafetyMode.NONE) { - activity.getEncryptedGitPrefs() - } + private val hiltEntryPoint = EntryPointAccessors.fromApplication(activity.applicationContext, RepositorySettingsEntryPoint::class.java) + private val encryptedPreferences = hiltEntryPoint.encryptedPreferences() + private val gitSettings = hiltEntryPoint.gitSettings() + private fun launchActivity(clazz: Class) { activity.startActivity(Intent(activity, clazz)) @@ -74,7 +80,7 @@ class RepositorySettings(private val activity: FragmentActivity) : SettingsProvi } pref(PreferenceKeys.PROXY_SETTINGS) { titleRes = R.string.pref_edit_proxy_settings - visible = GitSettings.url?.startsWith("https") == true && PasswordRepository.isGitRepo() + visible = gitSettings.url?.startsWith("https") == true && PasswordRepository.isGitRepo() onClick { launchActivity(ProxySelectorActivity::class.java) true @@ -206,4 +212,11 @@ class RepositorySettings(private val activity: FragmentActivity) : SettingsProvi } } } + + @EntryPoint + @InstallIn(SingletonComponent::class) + interface RepositorySettingsEntryPoint { + fun gitSettings(): GitSettings + @GitPreferences fun encryptedPreferences(): SharedPreferences + } } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommandExecutor.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommandExecutor.kt index 7be06385..5d507dc8 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommandExecutor.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommandExecutor.kt @@ -10,6 +10,10 @@ import androidx.fragment.app.FragmentActivity import com.github.michaelbull.result.Result import com.github.michaelbull.result.runCatching import com.google.android.material.snackbar.Snackbar +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.android.EntryPointAccessors +import dagger.hilt.components.SingletonComponent import dev.msfjarvis.aps.R import dev.msfjarvis.aps.util.extensions.snackbar import dev.msfjarvis.aps.util.git.GitException.PullException @@ -30,6 +34,9 @@ class GitCommandExecutor( private val operation: GitOperation, ) { + private val hiltEntryPoint = EntryPointAccessors.fromApplication(activity.applicationContext, GitCommandExecutorEntryPoint::class.java) + private val gitSettings = hiltEntryPoint.gitSettings() + suspend fun execute(): Result { val snackbar = activity.snackbar( @@ -49,8 +56,8 @@ class GitCommandExecutor( // the previous status will eventually be used to avoid a commit if (nbChanges > 0) { withContext(Dispatchers.IO) { - val name = GitSettings.authorName.ifEmpty { "root" } - val email = GitSettings.authorEmail.ifEmpty { "localhost" } + val name = gitSettings.authorName.ifEmpty { "root" } + val email = gitSettings.authorEmail.ifEmpty { "localhost" } val identity = PersonIdent(name, email) command.setAuthor(identity).setCommitter(identity).call() } @@ -111,4 +118,10 @@ class GitCommandExecutor( } .also { snackbar.dismiss() } } + + @EntryPoint + @InstallIn(SingletonComponent::class) + interface GitCommandExecutorEntryPoint { + fun gitSettings(): GitSettings + } } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt index dbea37e8..5a9da290 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt @@ -14,6 +14,11 @@ import com.github.michaelbull.result.Result import com.github.michaelbull.result.onFailure import com.github.michaelbull.result.runCatching import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.android.AndroidEntryPoint +import dagger.hilt.android.EntryPointAccessors +import dagger.hilt.components.SingletonComponent import dev.msfjarvis.aps.R import dev.msfjarvis.aps.data.repo.PasswordRepository import dev.msfjarvis.aps.ui.sshkeygen.SshKeyGenActivity @@ -26,6 +31,8 @@ import dev.msfjarvis.aps.util.git.sshj.SshKey import dev.msfjarvis.aps.util.git.sshj.SshjSessionFactory import dev.msfjarvis.aps.util.settings.AuthMode import dev.msfjarvis.aps.util.settings.GitSettings +import javax.inject.Inject +import javax.inject.Singleton import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine import kotlinx.coroutines.Dispatchers @@ -53,10 +60,11 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { abstract val commands: Array> private val hostKeyFile = callingActivity.filesDir.resolve(".host_key") private var sshSessionFactory: SshjSessionFactory? = null + private val hiltEntryPoint = EntryPointAccessors.fromApplication(callingActivity.applicationContext, GitOperationEntryPoint::class.java) protected val repository = PasswordRepository.getRepository(null)!! protected val git = Git(repository) - protected val remoteBranch = GitSettings.branch + protected val remoteBranch = hiltEntryPoint.gitSettings().branch private val authActivity get() = callingActivity as ContinuationContainerActivity @@ -220,4 +228,11 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { /** Timeout in seconds before [TransportCommand] will abort a stalled IO operation. */ private const val CONNECT_TIMEOUT = 10 } + + // Using @EntryPoint seems to be our best option here, changing this to constructor injection would require a larger refactor. + @EntryPoint + @InstallIn(SingletonComponent::class) + interface GitOperationEntryPoint { + fun gitSettings(): GitSettings + } } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/proxy/ProxyUtils.kt b/app/src/main/java/dev/msfjarvis/aps/util/proxy/ProxyUtils.kt index e6eb7e43..d21ee24d 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/proxy/ProxyUtils.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/proxy/ProxyUtils.kt @@ -14,20 +14,20 @@ import java.net.Proxy import java.net.ProxySelector import java.net.SocketAddress import java.net.URI +import javax.inject.Inject +import javax.inject.Singleton /** Utility class for [Proxy] handling. */ -object ProxyUtils { - - private const val HTTP_PROXY_USER_PROPERTY = "http.proxyUser" - private const val HTTP_PROXY_PASSWORD_PROPERTY = "http.proxyPassword" +@Singleton +class ProxyUtils @Inject constructor(private val gitSettings: GitSettings) { /** Set the default [Proxy] and [Authenticator] for the app based on user provided settings. */ fun setDefaultProxy() { ProxySelector.setDefault( object : ProxySelector() { override fun select(uri: URI?): MutableList { - val host = GitSettings.proxyHost - val port = GitSettings.proxyPort + val host = gitSettings.proxyHost + val port = gitSettings.proxyPort return if (host == null || port == -1) { mutableListOf(Proxy.NO_PROXY) } else { @@ -42,8 +42,8 @@ object ProxyUtils { } } ) - val user = GitSettings.proxyUsername ?: "" - val password = GitSettings.proxyPassword ?: "" + val user = gitSettings.proxyUsername ?: "" + val password = gitSettings.proxyPassword ?: "" if (user.isEmpty() || password.isEmpty()) { System.clearProperty(HTTP_PROXY_USER_PROPERTY) System.clearProperty(HTTP_PROXY_PASSWORD_PROPERTY) @@ -63,4 +63,9 @@ object ProxyUtils { } ) } + + companion object { + private const val HTTP_PROXY_USER_PROPERTY = "http.proxyUser" + private const val HTTP_PROXY_PASSWORD_PROPERTY = "http.proxyPassword" + } } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/settings/GitSettings.kt b/app/src/main/java/dev/msfjarvis/aps/util/settings/GitSettings.kt index d3c85fa7..0d580142 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/settings/GitSettings.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/settings/GitSettings.kt @@ -4,16 +4,19 @@ */ package dev.msfjarvis.aps.util.settings +import android.content.SharedPreferences import androidx.core.content.edit import com.github.michaelbull.result.getOrElse import com.github.michaelbull.result.runCatching -import dev.msfjarvis.aps.Application import dev.msfjarvis.aps.data.repo.PasswordRepository -import dev.msfjarvis.aps.util.extensions.getEncryptedGitPrefs -import dev.msfjarvis.aps.util.extensions.getEncryptedProxyPrefs +import dev.msfjarvis.aps.injection.context.FilesDirPath +import dev.msfjarvis.aps.injection.prefs.GitPreferences +import dev.msfjarvis.aps.injection.prefs.ProxyPreferences +import dev.msfjarvis.aps.injection.prefs.SettingsPreferences import dev.msfjarvis.aps.util.extensions.getString -import dev.msfjarvis.aps.util.extensions.sharedPrefs import java.io.File +import javax.inject.Inject +import javax.inject.Singleton import org.eclipse.jgit.transport.URIish enum class Protocol(val pref: String) { @@ -48,29 +51,22 @@ enum class AuthMode(val pref: String) { } } -object GitSettings { +@Singleton +class GitSettings @Inject constructor( + @SettingsPreferences private val settings: SharedPreferences, + @GitPreferences private val encryptedSettings: SharedPreferences, + @ProxyPreferences private val proxySettings: SharedPreferences, + @FilesDirPath private val filesDirPath: String, +) { - private const val DEFAULT_BRANCH = "master" - - private val settings by lazy(LazyThreadSafetyMode.PUBLICATION) { - Application.instance.sharedPrefs - } - private val encryptedSettings by lazy(LazyThreadSafetyMode.PUBLICATION) { - Application.instance.getEncryptedGitPrefs() - } - private val proxySettings by lazy(LazyThreadSafetyMode.PUBLICATION) { - Application.instance.getEncryptedProxyPrefs() - } private val hostKeyPath by lazy(LazyThreadSafetyMode.NONE) { - "${Application.instance.filesDir}/.host_key" + "$filesDirPath/.host_key" } - var authMode get() = AuthMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH)) private set(value) { settings.edit { putString(PreferenceKeys.GIT_REMOTE_AUTH, value.pref) } } - var url get() = settings.getString(PreferenceKeys.GIT_REMOTE_URL) private set(value) { @@ -84,55 +80,46 @@ object GitSettings { encryptedSettings.edit { remove(PreferenceKeys.HTTPS_PASSWORD) } clearSavedHostKey() } - var authorName get() = settings.getString(PreferenceKeys.GIT_CONFIG_AUTHOR_NAME) ?: "" set(value) { settings.edit { putString(PreferenceKeys.GIT_CONFIG_AUTHOR_NAME, value) } } - var authorEmail get() = settings.getString(PreferenceKeys.GIT_CONFIG_AUTHOR_EMAIL) ?: "" set(value) { settings.edit { putString(PreferenceKeys.GIT_CONFIG_AUTHOR_EMAIL, value) } } - var branch get() = settings.getString(PreferenceKeys.GIT_BRANCH_NAME) ?: DEFAULT_BRANCH private set(value) { settings.edit { putString(PreferenceKeys.GIT_BRANCH_NAME, value) } } - var useMultiplexing get() = settings.getBoolean(PreferenceKeys.GIT_REMOTE_USE_MULTIPLEXING, true) set(value) { settings.edit { putBoolean(PreferenceKeys.GIT_REMOTE_USE_MULTIPLEXING, value) } } - var proxyHost get() = proxySettings.getString(PreferenceKeys.PROXY_HOST) set(value) { proxySettings.edit { putString(PreferenceKeys.PROXY_HOST, value) } } - var proxyPort get() = proxySettings.getInt(PreferenceKeys.PROXY_PORT, -1) set(value) { proxySettings.edit { putInt(PreferenceKeys.PROXY_PORT, value) } } - var proxyUsername get() = settings.getString(PreferenceKeys.PROXY_USERNAME) set(value) { proxySettings.edit { putString(PreferenceKeys.PROXY_USERNAME, value) } } - var proxyPassword get() = proxySettings.getString(PreferenceKeys.PROXY_PASSWORD) set(value) { proxySettings.edit { putString(PreferenceKeys.PROXY_PASSWORD, value) } } - var rebaseOnPull get() = settings.getBoolean(PreferenceKeys.REBASE_ON_PULL, true) set(value) { @@ -141,8 +128,7 @@ object GitSettings { sealed class UpdateConnectionSettingsResult { class MissingUsername(val newProtocol: Protocol) : UpdateConnectionSettingsResult() - class AuthModeMismatch(val newProtocol: Protocol, val validModes: List) : - UpdateConnectionSettingsResult() + class AuthModeMismatch(val newProtocol: Protocol, val validModes: List) : UpdateConnectionSettingsResult() object Valid : UpdateConnectionSettingsResult() object FailedToParseUrl : UpdateConnectionSettingsResult() } @@ -164,7 +150,6 @@ object GitSettings { } if (newAuthMode != AuthMode.None && parsedUrl.user.isNullOrBlank()) return UpdateConnectionSettingsResult.MissingUsername(newProtocol) - val validHttpsAuth = listOf(AuthMode.None, AuthMode.Password) val validSshAuth = listOf(AuthMode.OpenKeychain, AuthMode.Password, AuthMode.SshKey) when { @@ -189,4 +174,8 @@ object GitSettings { /** Returns true if a host key was previously saved */ fun hasSavedHostKey(): Boolean = File(hostKeyPath).exists() + + companion object { + private const val DEFAULT_BRANCH = "master" + } } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt b/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt index b9333617..b24914d0 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt @@ -6,7 +6,6 @@ package dev.msfjarvis.aps.util.settings -import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit import com.github.ajalt.timberkt.e @@ -14,20 +13,18 @@ import com.github.ajalt.timberkt.i import com.github.michaelbull.result.get import com.github.michaelbull.result.runCatching import dev.msfjarvis.aps.util.extensions.getString -import dev.msfjarvis.aps.util.extensions.sharedPrefs import dev.msfjarvis.aps.util.git.sshj.SshKey import java.io.File import java.net.URI -fun runMigrations(context: Context) { - val sharedPrefs = context.sharedPrefs - migrateToGitUrlBasedConfig(sharedPrefs) +fun runMigrations(filesDirPath: String, sharedPrefs: SharedPreferences, gitSettings: GitSettings) { + migrateToGitUrlBasedConfig(sharedPrefs, gitSettings) migrateToHideAll(sharedPrefs) - migrateToSshKey(context, sharedPrefs) + migrateToSshKey(filesDirPath, sharedPrefs) migrateToClipboardHistory(sharedPrefs) } -private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences) { +private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences, gitSettings: GitSettings) { val serverHostname = sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_SERVER) ?: return i { "Migrating to URL-based Git config" } val serverPort = sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_PORT) ?: "" @@ -76,10 +73,10 @@ private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences) { remove(PreferenceKeys.GIT_REMOTE_PROTOCOL) } if (url == null || - GitSettings.updateConnectionSettingsIfValid( - newAuthMode = GitSettings.authMode, + gitSettings.updateConnectionSettingsIfValid( + newAuthMode = gitSettings.authMode, newUrl = url, - newBranch = GitSettings.branch + newBranch = gitSettings.branch ) != GitSettings.UpdateConnectionSettingsResult.Valid ) { e { "Failed to migrate to URL-based Git config, generated URL is invalid" } @@ -95,8 +92,8 @@ private fun migrateToHideAll(sharedPrefs: SharedPreferences) { } } -private fun migrateToSshKey(context: Context, sharedPrefs: SharedPreferences) { - val privateKeyFile = File(context.filesDir, ".ssh_key") +private fun migrateToSshKey(filesDirPath: String, sharedPrefs: SharedPreferences) { + val privateKeyFile = File(filesDirPath, ".ssh_key") if (sharedPrefs.contains(PreferenceKeys.USE_GENERATED_KEY) && !SshKey.exists && privateKeyFile.exists()