aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/dev/msfjarvis/aps/ui/git
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2022-07-15 00:53:48 +0530
committerHarsh Shandilya <me@msfjarvis.dev>2022-07-15 01:13:47 +0530
commit549ee790d3e52bc62565ddf92e6a556e98b5195e (patch)
treed5758e5eb80093704e683c8da926838e18182588 /app/src/main/java/dev/msfjarvis/aps/ui/git
parent010c6e227c9cc27f4d01bc912311f977b2aeb3a7 (diff)
downloadHardenedPass-549ee790d3e52bc62565ddf92e6a556e98b5195e.tar.gz
HardenedPass-549ee790d3e52bc62565ddf92e6a556e98b5195e.zip
all: re-do package structure yet again
Diffstat (limited to 'app/src/main/java/dev/msfjarvis/aps/ui/git')
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/git/base/BaseGitActivity.kt185
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitConfigActivity.kt159
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitServerConfigActivity.kt305
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/git/log/GitLogActivity.kt49
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/git/log/GitLogAdapter.kt59
5 files changed, 0 insertions, 757 deletions
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
deleted file mode 100644
index 614d9a52..00000000
--- a/app/src/main/java/dev/msfjarvis/aps/ui/git/base/BaseGitActivity.kt
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-package dev.msfjarvis.aps.ui.git.base
-
-import android.content.SharedPreferences
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.edit
-import com.github.michaelbull.result.Err
-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.injection.prefs.GitPreferences
-import dev.msfjarvis.aps.util.extensions.sharedPrefs
-import dev.msfjarvis.aps.util.git.ErrorMessages
-import dev.msfjarvis.aps.util.git.operation.BreakOutOfDetached
-import dev.msfjarvis.aps.util.git.operation.CloneOperation
-import dev.msfjarvis.aps.util.git.operation.GcOperation
-import dev.msfjarvis.aps.util.git.operation.PullOperation
-import dev.msfjarvis.aps.util.git.operation.PushOperation
-import dev.msfjarvis.aps.util.git.operation.ResetToRemoteOperation
-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 logcat.asLog
-import logcat.logcat
-import net.schmizz.sshj.common.DisconnectReason
-import net.schmizz.sshj.common.SSHException
-import net.schmizz.sshj.transport.TransportException
-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]. */
- enum class GitOp {
- BREAK_OUT_OF_DETACHED,
- CLONE,
- PULL,
- PUSH,
- RESET,
- SYNC,
- GC,
- }
-
- @Inject lateinit var gitSettings: GitSettings
- @GitPreferences @Inject lateinit var gitPrefs: SharedPreferences
-
- /**
- * Attempt to launch the requested Git operation.
- * @param operation The type of git operation to launch
- */
- suspend fun launchGitOperation(operation: GitOp): Result<Unit, Throwable> {
- if (gitSettings.url == null) {
- return Err(IllegalStateException("Git url is not set!"))
- }
- 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.PUSH -> PushOperation(this)
- GitOp.SYNC -> SyncOperation(this, gitSettings.rebaseOnPull)
- GitOp.BREAK_OUT_OF_DETACHED -> BreakOutOfDetached(this)
- GitOp.RESET -> ResetToRemoteOperation(this)
- GitOp.GC -> GcOperation(this)
- }
- return (if (op.requiresAuth) {
- op.executeAfterAuthentication(gitSettings.authMode)
- } else {
- op.execute()
- })
- .mapError(::transformGitError)
- }
-
- fun finishOnSuccessHandler(@Suppress("UNUSED_PARAMETER") nothing: Unit) {
- finish()
- }
-
- suspend fun promptOnErrorHandler(err: Throwable, onPromptDone: () -> Unit = {}) {
- val error = rootCauseException(err)
- if (!isExplicitlyUserInitiatedError(error)) {
- gitPrefs.edit { remove(PreferenceKeys.HTTPS_PASSWORD) }
- sharedPrefs.edit { remove(PreferenceKeys.SSH_OPENKEYSTORE_KEYID) }
- logcat { error.asLog() }
- withContext(Dispatchers.Main) {
- MaterialAlertDialogBuilder(this@BaseGitActivity).run {
- setTitle(resources.getString(R.string.jgit_error_dialog_title))
- setMessage(ErrorMessages[error])
- setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ -> }
- setOnDismissListener { onPromptDone() }
- show()
- }
- }
- } else {
- onPromptDone()
- }
- }
-
- /**
- * Takes the result of [launchGitOperation] and applies any necessary transformations on the
- * [throwable] returned from it
- */
- private fun transformGitError(throwable: Throwable): Throwable {
- val err = rootCauseException(throwable)
- return when {
- err.message?.contains("cannot open additional channels") == true -> {
- 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."
- )
- }
- err.message?.contains("int org.eclipse.jgit.lib.AnyObjectId.w1") == true -> {
- IllegalStateException(
- "Your local repository appears to be an incomplete Git clone, please delete and re-clone from settings"
- )
- }
- err is TransportException &&
- err.disconnectReason == DisconnectReason.HOST_KEY_NOT_VERIFIABLE -> {
- SSHException(
- DisconnectReason.HOST_KEY_NOT_VERIFIABLE,
- "WARNING: The remote host key has changed. If this is expected, please go to Git server settings and clear the saved host key."
- )
- }
- else -> {
- err
- }
- }
- }
-
- /**
- * Check if a given [Throwable] is the result of an error caused by the user cancelling the
- * operation.
- */
- private fun isExplicitlyUserInitiatedError(throwable: Throwable): Boolean {
- var cause: Throwable? = throwable
- while (cause != null) {
- if (
- cause is SSHException && cause.disconnectReason == DisconnectReason.AUTH_CANCELLED_BY_USER
- )
- return true
- cause = cause.cause
- }
- return false
- }
-
- /**
- * Get the real root cause of a [Throwable] by traversing until known wrapping exceptions are no
- * longer found.
- */
- private fun rootCauseException(throwable: Throwable): Throwable {
- var rootCause = throwable
- // JGit's InvalidRemoteException and TransportException hide the more helpful SSHJ
- // exceptions.
- // Also, SSHJ's UserAuthException about exhausting available authentication methods hides
- // more useful exceptions.
- while (
- (rootCause is org.eclipse.jgit.errors.TransportException ||
- rootCause is org.eclipse.jgit.api.errors.TransportException ||
- rootCause is org.eclipse.jgit.api.errors.InvalidRemoteException ||
- (rootCause is UserAuthException &&
- rootCause.message == "Exhausted available authentication methods"))
- ) {
- rootCause = rootCause.cause ?: break
- }
- return rootCause
- }
-}
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
deleted file mode 100644
index 03c92313..00000000
--- a/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitConfigActivity.kt
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-package dev.msfjarvis.aps.ui.git.config
-
-import android.content.Intent
-import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
-import android.util.Patterns
-import android.view.MenuItem
-import androidx.core.os.postDelayed
-import androidx.lifecycle.lifecycleScope
-import com.github.michaelbull.result.fold
-import com.github.michaelbull.result.getOrElse
-import com.github.michaelbull.result.onFailure
-import com.github.michaelbull.result.runCatching
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.google.android.material.snackbar.Snackbar
-import dev.msfjarvis.aps.R
-import dev.msfjarvis.aps.data.repo.PasswordRepository
-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 kotlinx.coroutines.launch
-import logcat.LogPriority.ERROR
-import logcat.logcat
-import org.eclipse.jgit.lib.Constants
-import org.eclipse.jgit.lib.Repository
-import org.eclipse.jgit.lib.RepositoryState
-
-class GitConfigActivity : BaseGitActivity() {
-
- private val binding by viewBinding(ActivityGitConfigBinding::inflate)
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(binding.root)
- supportActionBar?.setDisplayHomeAsUpEnabled(true)
-
- 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()
- val name = binding.gitUserName.text.toString().trim()
- if (!email.matches(Patterns.EMAIL_ADDRESS.toRegex())) {
- MaterialAlertDialogBuilder(this)
- .setMessage(getString(R.string.invalid_email_dialog_text))
- .setPositiveButton(getString(R.string.dialog_ok), null)
- .show()
- } else {
- gitSettings.authorEmail = email
- gitSettings.authorName = name
- Snackbar.make(
- binding.root,
- getString(R.string.git_server_config_save_success),
- Snackbar.LENGTH_SHORT
- )
- .show()
- Handler(Looper.getMainLooper()).postDelayed(500) { finish() }
- }
- }
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- android.R.id.home -> {
- onBackPressed()
- true
- }
- else -> super.onOptionsItemSelected(item)
- }
- }
-
- /** Sets up the UI components of the tools section. */
- private fun setupTools() {
- val repo = PasswordRepository.repository
- if (repo != null) {
- binding.gitHeadStatus.text = headStatusMsg(repo)
- // enable the abort button only if we're rebasing or merging
- val needsAbort =
- repo.repositoryState.isRebasing || repo.repositoryState == RepositoryState.MERGING
- binding.gitAbortRebase.isEnabled = needsAbort
- binding.gitAbortRebase.alpha = if (needsAbort) 1.0f else 0.5f
- }
- binding.gitLog.setOnClickListener {
- runCatching { startActivity(Intent(this, GitLogActivity::class.java)) }
- .onFailure { ex -> logcat(ERROR) { "Failed to start GitLogActivity\n${ex}" } }
- }
- binding.gitAbortRebase.setOnClickListener {
- lifecycleScope.launch {
- launchGitOperation(GitOp.BREAK_OUT_OF_DETACHED)
- .fold(
- success = {
- MaterialAlertDialogBuilder(this@GitConfigActivity).run {
- setTitle(resources.getString(R.string.git_abort_and_push_title))
- setMessage(
- resources.getString(
- R.string.git_break_out_of_detached_success,
- gitSettings.branch,
- "conflicting-${gitSettings.branch}-...",
- )
- )
- setOnDismissListener { finish() }
- setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ -> }
- show()
- }
- },
- failure = { err -> promptOnErrorHandler(err) { finish() } },
- )
- }
- }
- binding.gitResetToRemote.setOnClickListener {
- lifecycleScope.launch {
- launchGitOperation(GitOp.RESET)
- .fold(
- success = ::finishOnSuccessHandler,
- failure = { err -> promptOnErrorHandler(err) { finish() } },
- )
- }
- }
- binding.gitGc.setOnClickListener {
- lifecycleScope.launch {
- launchGitOperation(GitOp.GC)
- .fold(
- success = ::finishOnSuccessHandler,
- failure = { err -> promptOnErrorHandler(err) { finish() } },
- )
- }
- }
- }
-
- /**
- * Returns a user-friendly message about the current state of HEAD.
- *
- * The state is recognized to be either pointing to a branch or detached.
- */
- private fun headStatusMsg(repo: Repository): String {
- return runCatching {
- val headRef = repo.getRef(Constants.HEAD)
- if (headRef.isSymbolic) {
- val branchName = headRef.target.name
- val shortBranchName = Repository.shortenRefName(branchName)
- getString(R.string.git_head_on_branch, shortBranchName)
- } else {
- val commitHash = headRef.objectId.abbreviate(8).name()
- getString(R.string.git_head_detached, commitHash)
- }
- }
- .getOrElse { ex ->
- logcat(ERROR) { "Error getting HEAD reference\n${ex}" }
- getString(R.string.git_head_missing)
- }
- }
-}
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
deleted file mode 100644
index 93f104fb..00000000
--- a/app/src/main/java/dev/msfjarvis/aps/ui/git/config/GitServerConfigActivity.kt
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-package dev.msfjarvis.aps.ui.git.config
-
-import android.content.Context
-import android.content.Intent
-import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
-import android.view.MenuItem
-import android.view.View
-import androidx.core.os.postDelayed
-import androidx.core.view.isVisible
-import androidx.core.widget.doOnTextChanged
-import androidx.lifecycle.lifecycleScope
-import com.github.michaelbull.result.fold
-import com.github.michaelbull.result.onFailure
-import com.github.michaelbull.result.runCatching
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.google.android.material.snackbar.Snackbar
-import dev.msfjarvis.aps.R
-import dev.msfjarvis.aps.data.repo.PasswordRepository
-import dev.msfjarvis.aps.databinding.ActivityGitCloneBinding
-import dev.msfjarvis.aps.ui.dialogs.BasicBottomSheet
-import dev.msfjarvis.aps.ui.git.base.BaseGitActivity
-import dev.msfjarvis.aps.util.extensions.snackbar
-import dev.msfjarvis.aps.util.extensions.viewBinding
-import dev.msfjarvis.aps.util.settings.AuthMode
-import dev.msfjarvis.aps.util.settings.GitSettings
-import dev.msfjarvis.aps.util.settings.Protocol
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import logcat.LogPriority.ERROR
-import logcat.asLog
-import logcat.logcat
-
-/**
- * Activity that encompasses both the initial clone as well as editing the server config for future
- * changes.
- */
-class GitServerConfigActivity : BaseGitActivity() {
-
- private val binding by viewBinding(ActivityGitCloneBinding::inflate)
-
- private lateinit var newAuthMode: AuthMode
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val isClone = intent?.extras?.getBoolean("cloning") ?: false
- if (isClone) {
- binding.saveButton.text = getString(R.string.clone_button)
- }
- setContentView(binding.root)
- supportActionBar?.setDisplayHomeAsUpEnabled(true)
-
- newAuthMode = gitSettings.authMode
-
- binding.authModeGroup.apply {
- when (newAuthMode) {
- AuthMode.SshKey -> check(binding.authModeSshKey.id)
- AuthMode.Password -> check(binding.authModePassword.id)
- AuthMode.OpenKeychain -> check(binding.authModeOpenKeychain.id)
- AuthMode.None -> check(View.NO_ID)
- }
- addOnButtonCheckedListener { _, checkedId, isChecked ->
- if (!isChecked) {
- newAuthMode = AuthMode.None
- return@addOnButtonCheckedListener
- }
- when (checkedId) {
- binding.authModeSshKey.id -> newAuthMode = AuthMode.SshKey
- binding.authModeOpenKeychain.id -> newAuthMode = AuthMode.OpenKeychain
- binding.authModePassword.id -> newAuthMode = AuthMode.Password
- View.NO_ID -> newAuthMode = AuthMode.None
- }
- }
- }
-
- binding.serverUrl.setText(
- gitSettings.url.also {
- if (it.isNullOrEmpty()) return@also
- setAuthModes(it.startsWith("http://") || it.startsWith("https://"))
- }
- )
- 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.setOnClickListener {
- gitSettings.clearSavedHostKey()
- Snackbar.make(
- binding.root,
- getString(R.string.clear_saved_host_key_success),
- Snackbar.LENGTH_LONG
- )
- .show()
- it.isVisible = false
- }
- binding.saveButton.setOnClickListener {
- val newUrl = binding.serverUrl.text.toString().trim()
- // If url is of type john_doe@example.org:12435/path/to/repo, then not adding `ssh://`
- // in the beginning will cause the port to be seen as part of the path. Let users know
- // about it and offer a quickfix.
- if (newUrl.contains(PORT_REGEX)) {
- if (newUrl.startsWith("https://")) {
- BasicBottomSheet.Builder(this)
- .setTitleRes(R.string.https_scheme_with_port_title)
- .setMessageRes(R.string.https_scheme_with_port_message)
- .setPositiveButtonClickListener {
- binding.serverUrl.setText(newUrl.replace(PORT_REGEX, "/"))
- }
- .build()
- .show(supportFragmentManager, "SSH_SCHEME_WARNING")
- return@setOnClickListener
- } else if (!newUrl.startsWith("ssh://")) {
- BasicBottomSheet.Builder(this)
- .setTitleRes(R.string.ssh_scheme_needed_title)
- .setMessageRes(R.string.ssh_scheme_needed_message)
- .setPositiveButtonClickListener {
- @Suppress("SetTextI18n") binding.serverUrl.setText("ssh://$newUrl")
- }
- .build()
- .show(supportFragmentManager, "SSH_SCHEME_WARNING")
- return@setOnClickListener
- }
- }
- if (newUrl.startsWith("git://")) {
- BasicBottomSheet.Builder(this)
- .setTitleRes(R.string.git_scheme_disallowed_title)
- .setMessageRes(R.string.git_scheme_disallowed_message)
- .setPositiveButtonClickListener {}
- .build()
- .show(supportFragmentManager, "SSH_SCHEME_WARNING")
- return@setOnClickListener
- }
- when (
- val updateResult =
- gitSettings.updateConnectionSettingsIfValid(
- newAuthMode = newAuthMode,
- newUrl = binding.serverUrl.text.toString().trim(),
- newBranch = binding.serverBranch.text.toString().trim()
- )
- ) {
- GitSettings.UpdateConnectionSettingsResult.FailedToParseUrl -> {
- Snackbar.make(
- binding.root,
- getString(R.string.git_server_config_save_error),
- Snackbar.LENGTH_LONG
- )
- .show()
- }
- is GitSettings.UpdateConnectionSettingsResult.MissingUsername -> {
- when (updateResult.newProtocol) {
- Protocol.Https ->
- BasicBottomSheet.Builder(this)
- .setTitleRes(R.string.ssh_scheme_needed_title)
- .setMessageRes(R.string.git_server_config_save_missing_username_https)
- .setPositiveButtonClickListener {}
- .build()
- .show(supportFragmentManager, "HTTPS_MISSING_USERNAME")
- Protocol.Ssh ->
- BasicBottomSheet.Builder(this)
- .setTitleRes(R.string.ssh_scheme_needed_title)
- .setMessageRes(R.string.git_server_config_save_missing_username_ssh)
- .setPositiveButtonClickListener {}
- .build()
- .show(supportFragmentManager, "SSH_MISSING_USERNAME")
- }
- }
- GitSettings.UpdateConnectionSettingsResult.Valid -> {
- if (isClone && PasswordRepository.repository == null) PasswordRepository.initialize()
- if (!isClone) {
- Snackbar.make(
- binding.root,
- getString(R.string.git_server_config_save_success),
- Snackbar.LENGTH_SHORT
- )
- .show()
- Handler(Looper.getMainLooper()).postDelayed(500) { finish() }
- } else {
- cloneRepository()
- }
- }
- is GitSettings.UpdateConnectionSettingsResult.AuthModeMismatch -> {
- val message =
- getString(
- R.string.git_server_config_save_auth_mode_mismatch,
- updateResult.newProtocol,
- updateResult.validModes.joinToString(", "),
- )
- Snackbar.make(binding.root, message, Snackbar.LENGTH_LONG).show()
- }
- }
- }
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- android.R.id.home -> {
- onBackPressed()
- true
- }
- else -> super.onOptionsItemSelected(item)
- }
- }
-
- private fun setAuthModes(isHttps: Boolean) =
- with(binding) {
- if (isHttps) {
- authModeSshKey.isVisible = false
- authModeOpenKeychain.isVisible = false
- authModePassword.isVisible = true
- if (authModeGroup.checkedButtonId != authModePassword.id) authModeGroup.check(View.NO_ID)
- } else {
- authModeSshKey.isVisible = true
- authModeOpenKeychain.isVisible = true
- authModePassword.isVisible = true
- if (authModeGroup.checkedButtonId == View.NO_ID) authModeGroup.check(authModeSshKey.id)
- }
- }
-
- /** Clones the repository, the directory exists, deletes it */
- private fun cloneRepository() {
- val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory())
- val localDirFiles = localDir.listFiles() ?: emptyArray()
- // Warn if non-empty folder unless it's a just-initialized store that has just a .git folder
- if (
- localDir.exists() &&
- localDirFiles.isNotEmpty() &&
- !(localDirFiles.size == 1 && localDirFiles[0].name == ".git")
- ) {
- MaterialAlertDialogBuilder(this)
- .setTitle(R.string.dialog_delete_title)
- .setMessage(resources.getString(R.string.dialog_delete_msg, localDir.toString()))
- .setCancelable(false)
- .setPositiveButton(R.string.dialog_delete) { dialog, _ ->
- runCatching {
- lifecycleScope.launch {
- val snackbar =
- snackbar(
- message = getString(R.string.delete_directory_progress_text),
- length = Snackbar.LENGTH_INDEFINITE
- )
- withContext(Dispatchers.IO) { localDir.deleteRecursively() }
- snackbar.dismiss()
- launchGitOperation(GitOp.CLONE)
- .fold(
- success = {
- setResult(RESULT_OK)
- finish()
- },
- failure = { err -> promptOnErrorHandler(err) { finish() } }
- )
- }
- }
- .onFailure { e ->
- e.printStackTrace()
- MaterialAlertDialogBuilder(this).setMessage(e.message).show()
- }
- dialog.cancel()
- }
- .setNegativeButton(R.string.dialog_do_not_delete) { dialog, _ -> dialog.cancel() }
- .show()
- } else {
- runCatching {
- // Silently delete & replace the lone .git folder if it exists
- if (localDir.exists() && localDirFiles.size == 1 && localDirFiles[0].name == ".git") {
- localDir.deleteRecursively()
- }
- }
- .onFailure { e ->
- logcat(ERROR) { e.asLog() }
- MaterialAlertDialogBuilder(this).setMessage(e.message).show()
- }
- lifecycleScope.launch {
- launchGitOperation(GitOp.CLONE)
- .fold(
- success = {
- setResult(RESULT_OK)
- finish()
- },
- failure = { promptOnErrorHandler(it) },
- )
- }
- }
- }
-
- companion object {
-
- private val PORT_REGEX = ":[0-9]{1,5}/".toRegex()
-
- fun createCloneIntent(context: Context): Intent {
- return Intent(context, GitServerConfigActivity::class.java).apply {
- putExtra("cloning", true)
- }
- }
- }
-}
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/git/log/GitLogActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/git/log/GitLogActivity.kt
deleted file mode 100644
index 4265717d..00000000
--- a/app/src/main/java/dev/msfjarvis/aps/ui/git/log/GitLogActivity.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.ui.git.log
-
-import android.os.Bundle
-import android.view.MenuItem
-import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.LinearLayoutManager
-import dev.msfjarvis.aps.databinding.ActivityGitLogBinding
-import dev.msfjarvis.aps.ui.git.base.BaseGitActivity
-import dev.msfjarvis.aps.util.extensions.viewBinding
-
-/**
- * Displays the repository's git commits in git-log fashion.
- *
- * It provides basic information about each commit by way of a non-interactive RecyclerView.
- */
-class GitLogActivity : BaseGitActivity() {
-
- private val binding by viewBinding(ActivityGitLogBinding::inflate)
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(binding.root)
- supportActionBar?.setDisplayHomeAsUpEnabled(true)
- createRecyclerView()
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- android.R.id.home -> {
- finish()
- true
- }
- else -> super.onOptionsItemSelected(item)
- }
- }
-
- private fun createRecyclerView() {
- binding.gitLogRecyclerView.apply {
- setHasFixedSize(true)
- addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
- adapter = GitLogAdapter()
- }
- }
-}
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/git/log/GitLogAdapter.kt b/app/src/main/java/dev/msfjarvis/aps/ui/git/log/GitLogAdapter.kt
deleted file mode 100644
index a3080fef..00000000
--- a/app/src/main/java/dev/msfjarvis/aps/ui/git/log/GitLogAdapter.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.ui.git.log
-
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import dev.msfjarvis.aps.databinding.GitLogRowLayoutBinding
-import dev.msfjarvis.aps.util.git.GitCommit
-import dev.msfjarvis.aps.util.git.GitLogModel
-import java.text.DateFormat
-import java.util.Date
-import logcat.LogPriority.ERROR
-import logcat.logcat
-
-private fun shortHash(hash: String): String {
- return hash.substring(0 until 8)
-}
-
-private fun stringFrom(date: Date): String {
- return DateFormat.getDateTimeInstance().format(date)
-}
-
-/** @see GitLogActivity */
-class GitLogAdapter : RecyclerView.Adapter<GitLogAdapter.ViewHolder>() {
-
- private val model = GitLogModel()
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val inflater = LayoutInflater.from(parent.context)
- val binding = GitLogRowLayoutBinding.inflate(inflater, parent, false)
- return ViewHolder(binding)
- }
-
- override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
- val commit = model.get(position)
- if (commit == null) {
- logcat(ERROR) { "There is no git commit for view holder at position $position." }
- return
- }
- viewHolder.bind(commit)
- }
-
- override fun getItemCount() = model.size
-
- class ViewHolder(private val binding: GitLogRowLayoutBinding) :
- RecyclerView.ViewHolder(binding.root) {
-
- fun bind(commit: GitCommit) =
- with(binding) {
- gitLogRowMessage.text = commit.shortMessage
- gitLogRowHash.text = shortHash(commit.hash)
- gitLogRowTime.text = stringFrom(commit.time)
- }
- }
-}