feat: wire up key import functionality

This commit is contained in:
Harsh Shandilya 2023-04-06 18:14:35 +05:30
parent a96f24ac96
commit c4edf7f0e6
No known key found for this signature in database
6 changed files with 105 additions and 25 deletions

View file

@ -9,7 +9,9 @@ import android.os.Bundle
import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import app.passwordstore.R
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class OnboardingActivity : AppCompatActivity(R.layout.activity_onboarding) {
override fun onCreate(savedInstanceState: Bundle?) {

View file

@ -5,21 +5,68 @@
package app.passwordstore.ui.onboarding.fragments
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import app.passwordstore.R
import app.passwordstore.data.repo.PasswordRepository
import app.passwordstore.databinding.FragmentKeySelectionBinding
import app.passwordstore.injection.prefs.SettingsPreferences
import app.passwordstore.ui.pgp.PGPKeyListActivity
import app.passwordstore.util.coroutines.DispatcherProvider
import app.passwordstore.util.extensions.commitChange
import app.passwordstore.util.extensions.finish
import app.passwordstore.util.extensions.snackbar
import app.passwordstore.util.extensions.viewBinding
import app.passwordstore.util.settings.PreferenceKeys
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import java.io.File
import javax.inject.Inject
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@AndroidEntryPoint
class KeySelectionFragment : Fragment(R.layout.fragment_key_selection) {
@Inject @SettingsPreferences lateinit var settings: SharedPreferences
@Inject lateinit var dispatcherProvider: DispatcherProvider
private val binding by viewBinding(FragmentKeySelectionBinding::bind)
private val gpgKeySelectAction =
registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == AppCompatActivity.RESULT_OK) {
val data = result.data ?: return@registerForActivityResult
val selectedKey =
data.getStringExtra(PGPKeyListActivity.EXTRA_SELECTED_KEY)
?: return@registerForActivityResult
lifecycleScope.launch {
withContext(dispatcherProvider.io()) {
val gpgIdentifierFile = File(PasswordRepository.getRepositoryDirectory(), ".gpg-id")
gpgIdentifierFile.writeText(selectedKey)
}
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
requireActivity()
.commitChange(getString(R.string.git_commit_gpg_id, getString(R.string.app_name)))
finish()
}
} else {
requireActivity()
.snackbar(
message = getString(R.string.gpg_key_select_mandatory),
length = Snackbar.LENGTH_LONG,
)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.selectKey.setOnClickListener {
// TODO(msfjarvis): Restore this functionality
// gpgKeySelectAction.launch(Intent(requireContext(), GetKeyIdsActivity::class.java))
gpgKeySelectAction.launch(PGPKeyListActivity.newSelectionActivity(requireContext()))
}
}

View file

@ -1,6 +1,7 @@
package app.passwordstore.ui.pgp
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@ -28,12 +29,14 @@ import androidx.compose.ui.unit.dp
import app.passwordstore.R
import app.passwordstore.crypto.GpgIdentifier
import app.passwordstore.ui.compose.theme.APSThemePreview
import app.passwordstore.util.extensions.conditional
@Composable
fun KeyList(
identifiers: List<GpgIdentifier>,
onItemClick: (identifier: GpgIdentifier) -> Unit,
modifier: Modifier = Modifier,
onKeySelected: ((identifier: GpgIdentifier) -> Unit)? = null,
) {
if (identifiers.isEmpty()) {
Column(
@ -50,7 +53,7 @@ fun KeyList(
} else {
LazyColumn(modifier = modifier) {
items(identifiers) { identifier ->
KeyItem(identifier = identifier, onItemClick = onItemClick)
KeyItem(identifier = identifier, onItemClick = onItemClick, onKeySelected = onKeySelected)
}
}
}
@ -61,6 +64,7 @@ private fun KeyItem(
identifier: GpgIdentifier,
onItemClick: (identifier: GpgIdentifier) -> Unit,
modifier: Modifier = Modifier,
onKeySelected: ((identifier: GpgIdentifier) -> Unit)? = null,
) {
var isDeleting by remember { mutableStateOf(false) }
DeleteConfirmationDialog(
@ -77,11 +81,15 @@ private fun KeyItem(
is GpgIdentifier.UserId -> identifier.email
}
Row(
modifier = modifier.padding(16.dp).fillMaxWidth(),
modifier =
modifier.padding(16.dp).fillMaxWidth().conditional(onKeySelected != null) {
clickable { onKeySelected?.invoke(identifier) }
},
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = label)
if (onKeySelected == null) {
IconButton(onClick = { isDeleting = true }) {
Icon(
painter = painterResource(R.drawable.ic_delete_24dp),
@ -90,6 +98,7 @@ private fun KeyItem(
}
}
}
}
@Suppress("NOTHING_TO_INLINE")
@Composable

View file

@ -1,5 +1,6 @@
package app.passwordstore.ui.pgp
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
@ -12,12 +13,10 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import app.passwordstore.R
import app.passwordstore.ui.APSAppBar
import app.passwordstore.ui.compose.theme.APSTheme
@ -39,6 +38,7 @@ class PGPKeyListActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val isSelecting = intent.extras?.getBoolean(EXTRA_KEY_SELECTION) ?: false
setContent {
val context = LocalContext.current
APSTheme(colors = decideColorScheme(context)) {
@ -62,21 +62,33 @@ class PGPKeyListActivity : ComponentActivity() {
}
}
) { paddingValues ->
PGPKeyList(viewModel = viewModel, modifier = Modifier.padding(paddingValues))
KeyList(
identifiers = viewModel.keys,
onItemClick = viewModel::deleteKey,
modifier = Modifier.padding(paddingValues),
onKeySelected =
if (isSelecting) {
{ identifier ->
val result = Intent()
result.putExtra(EXTRA_SELECTED_KEY, identifier.toString())
setResult(RESULT_OK, result)
finish()
}
} else null,
)
}
}
}
}
@Composable
fun PGPKeyList(
modifier: Modifier = Modifier,
viewModel: PGPKeyListViewModel = viewModel(),
) {
KeyList(
identifiers = viewModel.keys,
onItemClick = viewModel::deleteKey,
modifier = modifier,
)
companion object {
const val EXTRA_SELECTED_KEY = "SELECTED_KEY"
private const val EXTRA_KEY_SELECTION = "KEY_SELECTION_MODE"
fun newSelectionActivity(context: Context): Intent {
val intent = Intent(context, PGPKeyListActivity::class.java)
intent.putExtra(EXTRA_KEY_SELECTION, true)
return intent
}
}
}

View file

@ -22,6 +22,7 @@ import android.view.View
import android.view.autofill.AutofillManager
import androidx.activity.ComponentActivity
import androidx.annotation.RequiresApi
import androidx.compose.ui.Modifier
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
@ -153,3 +154,12 @@ fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): Ap
@Suppress("DEPRECATION") getApplicationInfo(packageName, flags)
}
}
/** Allows conditionally applying the given [modifier] if [isEnabled] is `true`. */
fun Modifier.conditional(isEnabled: Boolean, modifier: Modifier.() -> Modifier): Modifier {
return if (isEnabled) {
then(modifier())
} else {
this
}
}

View file

@ -43,6 +43,7 @@
<string name="git_commit_remove_text">Remove %1$s from store.</string>
<string name="git_commit_move_text">Rename %1$s to %2$s.</string>
<string name="git_commit_move_multiple_text">Move multiple passwords to %1$s.</string>
<string name="git_commit_gpg_id">Initialize GPG IDs in %1$s.</string>
<!-- PGPHandler -->
<string name="clipboard_copied_text">Copied to clipboard</string>
@ -318,9 +319,8 @@
<string name="git_break_out_of_detached_success">There was a conflict when trying to rebase. Your local %1$s branch was pushed to another branch named %2$s\n Use this branch to resolve conflict on your computer</string>
<string name="git_break_out_of_detached_unneeded">The repository is not rebasing, no need to push to another branch</string>
<!-- OpenKeychain not installed -->
<!-- GPG key selection in folder creation -->
<string name="gpg_key_select_mandatory">Selecting a GPG key is necessary to proceed</string>
<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>