Replicate key selection flow for directory creation (#999)
* Replicate key selection flow Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Review fixes Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Set --user 0 in adb options to prevent automatically installing to work profile Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Fix committing regression Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Update changelog Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
e0350043d0
commit
5715b59ed4
8 changed files with 80 additions and 22 deletions
|
@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Allow changing the branch used for Git operations
|
- Allow changing the branch used for Git operations
|
||||||
|
- Allow setting a subdirectory key when creating folders
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adbOptions.installOptions("--user 0")
|
||||||
|
|
||||||
buildFeatures.viewBinding = true
|
buildFeatures.viewBinding = true
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.eclipse.jgit.api.CommitCommand
|
||||||
import org.eclipse.jgit.api.PullCommand
|
import org.eclipse.jgit.api.PullCommand
|
||||||
import org.eclipse.jgit.api.PushCommand
|
import org.eclipse.jgit.api.PushCommand
|
||||||
import org.eclipse.jgit.api.RebaseResult
|
import org.eclipse.jgit.api.RebaseResult
|
||||||
import org.eclipse.jgit.api.StatusCommand
|
|
||||||
import org.eclipse.jgit.transport.RemoteRefUpdate
|
import org.eclipse.jgit.transport.RemoteRefUpdate
|
||||||
import org.eclipse.jgit.transport.SshSessionFactory
|
import org.eclipse.jgit.transport.SshSessionFactory
|
||||||
|
|
||||||
|
@ -43,22 +42,14 @@ class GitCommandExecutor(
|
||||||
message = activity.resources.getString(R.string.git_operation_running),
|
message = activity.resources.getString(R.string.git_operation_running),
|
||||||
length = Snackbar.LENGTH_INDEFINITE,
|
length = Snackbar.LENGTH_INDEFINITE,
|
||||||
)
|
)
|
||||||
var nbChanges = 0
|
|
||||||
var operationResult: Result = Result.Ok
|
var operationResult: Result = Result.Ok
|
||||||
for (command in operation.commands) {
|
for (command in operation.commands) {
|
||||||
try {
|
try {
|
||||||
when (command) {
|
when (command) {
|
||||||
is StatusCommand -> {
|
|
||||||
// in case we have changes, we want to keep track of it
|
|
||||||
val status = withContext(Dispatchers.IO) {
|
|
||||||
command.call()
|
|
||||||
}
|
|
||||||
nbChanges = status.changed.size + status.missing.size
|
|
||||||
}
|
|
||||||
is CommitCommand -> {
|
is CommitCommand -> {
|
||||||
// the previous status will eventually be used to avoid a commit
|
// the previous status will eventually be used to avoid a commit
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
if (nbChanges > 0) command.call()
|
command.call()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PullCommand -> {
|
is PullCommand -> {
|
||||||
|
|
|
@ -18,7 +18,6 @@ class SyncOperation(fileDir: File, callingActivity: AppCompatActivity) : GitOper
|
||||||
|
|
||||||
override val commands = arrayOf(
|
override val commands = arrayOf(
|
||||||
git.add().addFilepattern("."),
|
git.add().addFilepattern("."),
|
||||||
git.status(),
|
|
||||||
git.commit().setAll(true).setMessage("[Android Password Store] Sync"),
|
git.commit().setAll(true).setMessage("[Android Password Store] Sync"),
|
||||||
git.pull().setRebase(true).setRemote("origin"),
|
git.pull().setRebase(true).setRemote("origin"),
|
||||||
git.push().setPushAll().setRemote("origin"),
|
git.push().setPushAll().setRemote("origin"),
|
||||||
|
|
|
@ -5,15 +5,29 @@
|
||||||
package com.zeapo.pwdstore.ui.dialogs
|
package com.zeapo.pwdstore.ui.dialogs
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.google.android.material.checkbox.MaterialCheckBox
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.zeapo.pwdstore.PasswordStore
|
import com.zeapo.pwdstore.PasswordStore
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
|
import com.zeapo.pwdstore.crypto.BasePgpActivity
|
||||||
|
import com.zeapo.pwdstore.crypto.GetKeyIdsActivity
|
||||||
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
|
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getRepositoryDirectory
|
||||||
|
import com.zeapo.pwdstore.utils.commitChange
|
||||||
import com.zeapo.pwdstore.utils.requestInputFocusOnView
|
import com.zeapo.pwdstore.utils.requestInputFocusOnView
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import me.msfjarvis.openpgpktx.util.OpenPgpApi
|
||||||
|
|
||||||
class FolderCreationDialogFragment : DialogFragment() {
|
class FolderCreationDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
|
@ -21,26 +35,61 @@ class FolderCreationDialogFragment : DialogFragment() {
|
||||||
val alertDialogBuilder = MaterialAlertDialogBuilder(requireContext())
|
val alertDialogBuilder = MaterialAlertDialogBuilder(requireContext())
|
||||||
alertDialogBuilder.setTitle(R.string.title_create_folder)
|
alertDialogBuilder.setTitle(R.string.title_create_folder)
|
||||||
alertDialogBuilder.setView(R.layout.folder_dialog_fragment)
|
alertDialogBuilder.setView(R.layout.folder_dialog_fragment)
|
||||||
alertDialogBuilder.setPositiveButton(getString(R.string.button_create)) { _, _ ->
|
alertDialogBuilder.setPositiveButton(getString(R.string.button_create), null)
|
||||||
createDirectory(requireArguments().getString(CURRENT_DIR_EXTRA)!!)
|
|
||||||
}
|
|
||||||
alertDialogBuilder.setNegativeButton(getString(android.R.string.cancel)) { _, _ ->
|
alertDialogBuilder.setNegativeButton(getString(android.R.string.cancel)) { _, _ ->
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
val dialog = alertDialogBuilder.create()
|
val dialog = alertDialogBuilder.create()
|
||||||
dialog.requestInputFocusOnView<TextInputEditText>(R.id.folder_name_text)
|
dialog.requestInputFocusOnView<TextInputEditText>(R.id.folder_name_text)
|
||||||
|
dialog.setOnShowListener {
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||||
|
createDirectory(requireArguments().getString(CURRENT_DIR_EXTRA)!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDirectory(currentDir: String) {
|
private fun createDirectory(currentDir: String) {
|
||||||
val dialog = requireDialog()
|
val dialog = requireDialog()
|
||||||
val materialTextView = dialog.findViewById<TextInputEditText>(R.id.folder_name_text)
|
val folderNameView = dialog.findViewById<TextInputEditText>(R.id.folder_name_text)
|
||||||
val folderName = materialTextView.text.toString()
|
val folderNameViewContainer = dialog.findViewById<TextInputLayout>(R.id.folder_name_container)
|
||||||
val newFolder = File("$currentDir/$folderName")
|
val newFolder = File("$currentDir/${folderNameView.text}")
|
||||||
|
folderNameViewContainer.error = when {
|
||||||
|
newFolder.isFile -> getString(R.string.folder_creation_err_file_exists)
|
||||||
|
newFolder.isDirectory -> getString(R.string.folder_creation_err_folder_exists)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
if (folderNameViewContainer.error != null) return
|
||||||
newFolder.mkdirs()
|
newFolder.mkdirs()
|
||||||
(requireActivity() as PasswordStore).refreshPasswordList(newFolder)
|
(requireActivity() as PasswordStore).refreshPasswordList(newFolder)
|
||||||
|
if (dialog.findViewById<MaterialCheckBox>(R.id.set_gpg_key).isChecked) {
|
||||||
|
val gpgIdentifierFile = File(newFolder, ".gpg-id")
|
||||||
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
if (result.resultCode == AppCompatActivity.RESULT_OK) {
|
||||||
|
result.data?.getStringArrayExtra(OpenPgpApi.EXTRA_KEY_IDS)?.let { keyIds ->
|
||||||
|
gpgIdentifierFile.writeText(keyIds.joinToString("\n"))
|
||||||
|
val repo = PasswordRepository.getRepository(null)
|
||||||
|
if (repo != null) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val repoPath = getRepositoryDirectory().absolutePath
|
||||||
|
requireActivity().commitChange(
|
||||||
|
getString(
|
||||||
|
R.string.git_commit_gpg_id,
|
||||||
|
BasePgpActivity.getLongName(gpgIdentifierFile.parentFile!!.absolutePath, repoPath, gpgIdentifierFile.name)
|
||||||
|
),
|
||||||
|
finishActivityOnEnd = false,
|
||||||
|
)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.launch(Intent(requireContext(), GetKeyIdsActivity::class.java))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,6 @@ suspend fun FragmentActivity.commitChange(
|
||||||
object : GitOperation(getRepositoryDirectory(), this@commitChange) {
|
object : GitOperation(getRepositoryDirectory(), this@commitChange) {
|
||||||
override val commands = arrayOf(
|
override val commands = arrayOf(
|
||||||
git.add().addFilepattern("."),
|
git.add().addFilepattern("."),
|
||||||
git.status(),
|
|
||||||
git.commit().setAll(true).setMessage(message),
|
git.commit().setAll(true).setMessage(message),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,21 @@
|
||||||
~ SPDX-License-Identifier: GPL-3.0-only
|
~ SPDX-License-Identifier: GPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/folder_name_container"
|
||||||
style="@style/AppTheme.TextInputLayout"
|
style="@style/AppTheme.TextInputLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/crypto_name_hint">
|
android:hint="@string/crypto_name_hint"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/folder_name_text"
|
android:id="@+id/folder_name_text"
|
||||||
|
@ -22,4 +26,12 @@
|
||||||
android:inputType="textNoSuggestions|textVisiblePassword" />
|
android:inputType="textNoSuggestions|textVisiblePassword" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
</LinearLayout>
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/set_gpg_key"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:text="@string/new_folder_set_gpg_key"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/folder_name_container" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -367,6 +367,7 @@
|
||||||
<string name="short_key_ids_unsupported">A key ID in .gpg-id is too short, please use either long key IDs (16 characters) or fingerprints (40 characters)</string>
|
<string name="short_key_ids_unsupported">A key ID in .gpg-id is too short, please use either long key IDs (16 characters) or fingerprints (40 characters)</string>
|
||||||
<string name="invalid_filename_text">File name must not contain \'/\', set directory above</string>
|
<string name="invalid_filename_text">File name must not contain \'/\', set directory above</string>
|
||||||
<string name="directory_hint">Directory</string>
|
<string name="directory_hint">Directory</string>
|
||||||
|
<string name="new_folder_set_gpg_key">Set GPG key for directory</string>
|
||||||
|
|
||||||
<!-- GitException messages -->
|
<!-- GitException messages -->
|
||||||
<string name="git_unknown_error">Unknown error</string>
|
<string name="git_unknown_error">Unknown error</string>
|
||||||
|
@ -383,4 +384,8 @@
|
||||||
<string name="play_deeplink_template">https://play.google.com/store/apps/details?id=%1$s</string>
|
<string name="play_deeplink_template">https://play.google.com/store/apps/details?id=%1$s</string>
|
||||||
<string name="openkeychain_not_installed_fdroid">F-Droid</string>
|
<string name="openkeychain_not_installed_fdroid">F-Droid</string>
|
||||||
<string name="fdroid_deeplink_template">https://f-droid.org/en/packages/%1$s/</string>
|
<string name="fdroid_deeplink_template">https://f-droid.org/en/packages/%1$s/</string>
|
||||||
|
|
||||||
|
<!-- GPG key selection in folder creation -->
|
||||||
|
<string name="folder_creation_err_file_exists">A file by that name already exists</string>
|
||||||
|
<string name="folder_creation_err_folder_exists">A folder by that name already exists</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue