diff options
Diffstat (limited to 'app/src')
34 files changed, 2 insertions, 1825 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4859c0e..0429b2ac 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -95,12 +95,6 @@ android:label="@string/action_settings" android:parentActivityName=".ui.main.MainActivity" /> - <activity - android:name=".ui.crypto.PasswordCreationActivity" - android:exported="false" - android:label="@string/new_password_title" - android:windowSoftInputMode="adjustResize" /> - <service android:name=".util.services.ClipboardService" android:exported="false" @@ -124,9 +118,6 @@ </service> <activity - android:name=".ui.folderselect.SelectFolderActivity" - android:exported="false" /> - <activity android:name=".ui.sshkeygen.SshKeyImportActivity" android:exported="false" android:theme="@style/NoBackgroundThemeM3" diff --git a/app/src/main/java/app/passwordstore/injection/pwgen/DicewareModule.kt b/app/src/main/java/app/passwordstore/injection/pwgen/DicewareModule.kt index 8572e3b8..c9c4e928 100644 --- a/app/src/main/java/app/passwordstore/injection/pwgen/DicewareModule.kt +++ b/app/src/main/java/app/passwordstore/injection/pwgen/DicewareModule.kt @@ -13,7 +13,6 @@ import app.passwordstore.passgen.diceware.RandomIntGenerator import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.components.FragmentComponent import dagger.hilt.android.components.ViewModelComponent import dagger.hilt.android.qualifiers.ApplicationContext import java.io.InputStream @@ -21,7 +20,7 @@ import java.security.SecureRandom import javax.inject.Qualifier @Module -@InstallIn(FragmentComponent::class, ViewModelComponent::class) +@InstallIn(ViewModelComponent::class) object DicewareModule { @Provides diff --git a/app/src/main/java/app/passwordstore/ui/adapters/PasswordItemRecyclerAdapter.kt b/app/src/main/java/app/passwordstore/ui/adapters/PasswordItemRecyclerAdapter.kt deleted file mode 100644 index 54be64d6..00000000 --- a/app/src/main/java/app/passwordstore/ui/adapters/PasswordItemRecyclerAdapter.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ -package app.passwordstore.ui.adapters - -import android.text.SpannableString -import android.text.style.RelativeSizeSpan -import android.view.MotionEvent -import android.view.View -import androidx.appcompat.widget.AppCompatImageView -import androidx.appcompat.widget.AppCompatTextView -import androidx.recyclerview.selection.ItemDetailsLookup -import androidx.recyclerview.selection.Selection -import androidx.recyclerview.widget.RecyclerView -import app.passwordstore.R -import app.passwordstore.data.password.PasswordItem -import app.passwordstore.util.coroutines.DispatcherProvider -import app.passwordstore.util.viewmodel.SearchableRepositoryAdapter -import app.passwordstore.util.viewmodel.stableId -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.withContext - -open class PasswordItemRecyclerAdapter( - coroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, -) : - SearchableRepositoryAdapter<PasswordItemRecyclerAdapter.PasswordItemViewHolder>( - R.layout.password_row_layout, - ::PasswordItemViewHolder, - coroutineScope, - dispatcherProvider, - PasswordItemViewHolder::bind, - ) { - - fun makeSelectable(recyclerView: RecyclerView) { - makeSelectable(recyclerView, ::PasswordItemDetailsLookup) - } - - override fun onItemClicked( - listener: (holder: PasswordItemViewHolder, item: PasswordItem) -> Unit - ): PasswordItemRecyclerAdapter { - return super.onItemClicked(listener) as PasswordItemRecyclerAdapter - } - - override fun onSelectionChanged( - listener: (selection: Selection<String>) -> Unit - ): PasswordItemRecyclerAdapter { - return super.onSelectionChanged(listener) as PasswordItemRecyclerAdapter - } - - class PasswordItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - private val name: AppCompatTextView = itemView.findViewById(R.id.label) - private val childCount: AppCompatTextView = itemView.findViewById(R.id.child_count) - private val folderIndicator: AppCompatImageView = itemView.findViewById(R.id.folder_indicator) - var itemDetails: ItemDetailsLookup.ItemDetails<String>? = null - - suspend fun bind(item: PasswordItem, dispatcherProvider: DispatcherProvider) { - val parentPath = item.fullPathToParent.replace("(^/)|(/$)".toRegex(), "") - val source = - if (parentPath.isNotEmpty()) { - "$parentPath\n$item" - } else { - "$item" - } - val spannable = SpannableString(source) - spannable.setSpan(RelativeSizeSpan(0.7f), 0, parentPath.length, 0) - name.text = spannable - if (item.type == PasswordItem.TYPE_CATEGORY) { - folderIndicator.visibility = View.VISIBLE - val count = - withContext(dispatcherProvider.io()) { - item.file.listFiles { path -> path.isDirectory || path.extension == "gpg" }?.size ?: 0 - } - childCount.visibility = if (count > 0) View.VISIBLE else View.GONE - childCount.text = "$count" - } else { - childCount.visibility = View.GONE - folderIndicator.visibility = View.GONE - } - itemDetails = - object : ItemDetailsLookup.ItemDetails<String>() { - override fun getPosition() = absoluteAdapterPosition - - override fun getSelectionKey() = item.stableId - } - } - } - - class PasswordItemDetailsLookup(private val recyclerView: RecyclerView) : - ItemDetailsLookup<String>() { - - override fun getItemDetails(event: MotionEvent): ItemDetails<String>? { - val view = recyclerView.findChildViewUnder(event.x, event.y) ?: return null - return (recyclerView.getChildViewHolder(view) as PasswordItemViewHolder).itemDetails - } - } -} diff --git a/app/src/main/java/app/passwordstore/ui/crypto/BasePGPActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/BasePGPActivity.kt index ba49a62c..ccd3bf08 100644 --- a/app/src/main/java/app/passwordstore/ui/crypto/BasePGPActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/crypto/BasePGPActivity.kt @@ -29,7 +29,6 @@ import app.passwordstore.util.extensions.clipboard import app.passwordstore.util.extensions.getString import app.passwordstore.util.extensions.sharedPrefs import app.passwordstore.util.extensions.snackbar -import app.passwordstore.util.extensions.unsafeLazy import app.passwordstore.util.services.ClipboardService import app.passwordstore.util.settings.Constants import app.passwordstore.util.settings.PreferenceKeys @@ -44,12 +43,6 @@ import kotlinx.coroutines.withContext @AndroidEntryPoint open class BasePGPActivity : AppCompatActivity() { - /** Full path to the repository */ - val repoPath by unsafeLazy { intent.getStringExtra("REPO_PATH")!! } - - /** Full path to the password file being worked on */ - val fullPath by unsafeLazy { intent.getStringExtra("FILE_PATH")!! } - /** Action to invoke if [keyImportAction] succeeds. */ private var onKeyImport: (() -> Unit)? = null private val keyImportAction = @@ -103,7 +96,6 @@ open class BasePGPActivity : AppCompatActivity() { companion object { const val EXTRA_FILE_PATH = "FILE_PATH" - const val EXTRA_REPO_PATH = "REPO_PATH" /** Gets the relative path to the repository */ fun getRelativePath(fullPath: String, repositoryPath: String): String = diff --git a/app/src/main/java/app/passwordstore/ui/crypto/EditPasswordScreen.kt b/app/src/main/java/app/passwordstore/ui/crypto/EditPasswordScreen.kt deleted file mode 100644 index d8610307..00000000 --- a/app/src/main/java/app/passwordstore/ui/crypto/EditPasswordScreen.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.ui.crypto - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import app.passwordstore.R -import app.passwordstore.data.passfile.PasswordEntry -import app.passwordstore.ui.APSAppBar -import app.passwordstore.ui.compose.PasswordField -import app.passwordstore.ui.compose.theme.APSTheme -import app.passwordstore.ui.compose.theme.SpacingLarge -import app.passwordstore.ui.compose.theme.SpacingMedium -import app.passwordstore.util.time.UserClock -import app.passwordstore.util.totp.UriTotpFinder - -/** Composable to show allow editing an existing [PasswordEntry]. */ -@Composable -fun EditPasswordScreen( - entryName: String, - entry: PasswordEntry, - onNavigateUp: () -> Unit, - @Suppress("UNUSED_PARAMETER") onSave: (PasswordEntry) -> Unit, - modifier: Modifier = Modifier, -) { - Scaffold( - topBar = { - APSAppBar( - title = entryName, - navigationIcon = painterResource(R.drawable.ic_arrow_back_black_24dp), - onNavigationIconClick = onNavigateUp, - backgroundColor = MaterialTheme.colorScheme.surface, - ) - } - ) { paddingValues -> - Box(modifier = modifier.padding(paddingValues)) { - Column( - modifier = - Modifier.padding(vertical = SpacingMedium, horizontal = SpacingLarge).fillMaxSize() - ) { - if (entry.password != null) { - PasswordField( - value = entry.password!!, - label = stringResource(R.string.password), - initialVisibility = false, - modifier = Modifier.padding(bottom = SpacingMedium).fillMaxWidth(), - ) - } - ExtraContent(entry = entry) - } - } - } -} - -@Composable -private fun ExtraContent(entry: PasswordEntry, modifier: Modifier = Modifier) { - TextField( - value = entry.extraContentString, - onValueChange = {}, - label = { Text("Extra content") }, - modifier = modifier.fillMaxWidth(), - ) -} - -@Preview -@Composable -private fun EditPasswordScreenPreview() { - APSTheme { - EditPasswordScreen( - entryName = "Test Entry", - entry = createTestEntry(), - onNavigateUp = {}, - onSave = {}, - ) - } -} - -private fun createTestEntry() = - PasswordEntry( - UserClock(), - UriTotpFinder(), - """ - |My Password - |otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30 - |login: msfjarvis - |URL: example.com - """ - .trimMargin() - .encodeToByteArray(), - ) diff --git a/app/src/main/java/app/passwordstore/ui/crypto/PasswordCreationActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/PasswordCreationActivity.kt deleted file mode 100644 index 7652c98e..00000000 --- a/app/src/main/java/app/passwordstore/ui/crypto/PasswordCreationActivity.kt +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.ui.crypto - -import android.content.Context -import android.content.Intent -import android.content.pm.PackageManager -import android.graphics.Bitmap -import android.graphics.ImageDecoder -import android.os.Build -import android.os.Bundle -import android.provider.MediaStore -import android.text.InputType -import android.view.Menu -import android.view.MenuItem -import android.view.View -import androidx.activity.result.contract.ActivityResultContracts -import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult -import androidx.core.content.edit -import androidx.core.view.isVisible -import androidx.core.widget.doAfterTextChanged -import androidx.lifecycle.lifecycleScope -import app.passwordstore.R -import app.passwordstore.data.passfile.PasswordEntry -import app.passwordstore.databinding.PasswordCreationActivityBinding -import app.passwordstore.ui.dialogs.DicewarePasswordGeneratorDialogFragment -import app.passwordstore.ui.dialogs.OtpImportDialogFragment -import app.passwordstore.ui.dialogs.PasswordGeneratorDialogFragment -import app.passwordstore.util.autofill.AutofillPreferences -import app.passwordstore.util.extensions.asLog -import app.passwordstore.util.extensions.base64 -import app.passwordstore.util.extensions.commitChange -import app.passwordstore.util.extensions.getString -import app.passwordstore.util.extensions.isInsideRepository -import app.passwordstore.util.extensions.snackbar -import app.passwordstore.util.extensions.unsafeLazy -import app.passwordstore.util.extensions.viewBinding -import app.passwordstore.util.settings.DirectoryStructure -import app.passwordstore.util.settings.PreferenceKeys -import com.github.michaelbull.result.getOrElse -import com.github.michaelbull.result.onFailure -import com.github.michaelbull.result.onSuccess -import com.github.michaelbull.result.runCatching -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.google.zxing.BinaryBitmap -import com.google.zxing.LuminanceSource -import com.google.zxing.RGBLuminanceSource -import com.google.zxing.common.HybridBinarizer -import com.google.zxing.integration.android.IntentIntegrator -import com.google.zxing.integration.android.IntentIntegrator.QR_CODE -import com.google.zxing.qrcode.QRCodeReader -import dagger.hilt.android.AndroidEntryPoint -import java.io.ByteArrayOutputStream -import java.io.IOException -import java.nio.file.Paths -import javax.inject.Inject -import kotlin.io.path.absolutePathString -import kotlin.io.path.createDirectories -import kotlin.io.path.deleteIfExists -import kotlin.io.path.exists -import kotlin.io.path.isSameFileAs -import kotlin.io.path.nameWithoutExtension -import kotlin.io.path.pathString -import kotlin.io.path.relativeTo -import kotlin.io.path.writeBytes -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import logcat.LogPriority.ERROR -import logcat.asLog -import logcat.logcat - -@AndroidEntryPoint -class PasswordCreationActivity : BasePGPActivity() { - - private val binding by viewBinding(PasswordCreationActivityBinding::inflate) - @Inject lateinit var passwordEntryFactory: PasswordEntry.Factory - - private val suggestedName by unsafeLazy { intent.getStringExtra(EXTRA_FILE_NAME) } - private val suggestedUsername by unsafeLazy { intent.getStringExtra(EXTRA_USERNAME) } - private val suggestedPass by unsafeLazy { intent.getStringExtra(EXTRA_PASSWORD) } - private val suggestedExtra by unsafeLazy { intent.getStringExtra(EXTRA_EXTRA_CONTENT) } - private val shouldGeneratePassword by unsafeLazy { - intent.getBooleanExtra(EXTRA_GENERATE_PASSWORD, false) - } - private val editing by unsafeLazy { intent.getBooleanExtra(EXTRA_EDITING, false) } - private var oldCategory: String? = null - private var copy: Boolean = false - - private val otpImportAction = - registerForActivityResult(StartActivityForResult()) { result -> - if (result.resultCode == RESULT_OK) { - binding.otpImportButton.isVisible = false - val intentResult = IntentIntegrator.parseActivityResult(RESULT_OK, result.data) - val contents = "${intentResult.contents}\n" - val currentExtras = binding.extraContent.text.toString() - if (currentExtras.isNotEmpty() && currentExtras.last() != '\n') - binding.extraContent.append("\n$contents") - else binding.extraContent.append(contents) - snackbar(message = getString(R.string.otp_import_success)) - } else { - snackbar(message = getString(R.string.otp_import_failure_generic)) - } - } - - private val imageImportAction = - registerForActivityResult(ActivityResultContracts.GetContent()) { imageUri -> - if (imageUri == null) { - snackbar(message = getString(R.string.otp_import_failure_no_selection)) - return@registerForActivityResult - } - val bitmap = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, imageUri)) - .copy(Bitmap.Config.ARGB_8888, true) - } else { - @Suppress("DEPRECATION") MediaStore.Images.Media.getBitmap(contentResolver, imageUri) - } - val intArray = IntArray(bitmap.width * bitmap.height) - // copy pixel data from the Bitmap into the 'intArray' array - bitmap.getPixels(intArray, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) - val source: LuminanceSource = RGBLuminanceSource(bitmap.width, bitmap.height, intArray) - val binaryBitmap = BinaryBitmap(HybridBinarizer(source)) - - val reader = QRCodeReader() - runCatching { - val result = reader.decode(binaryBitmap) - val text = result.text - val currentExtras = binding.extraContent.text.toString() - if (currentExtras.isNotEmpty() && currentExtras.last() != '\n') - binding.extraContent.append("\n$text") - else binding.extraContent.append(text) - snackbar(message = getString(R.string.otp_import_success)) - binding.otpImportButton.isVisible = false - } - .onFailure { snackbar(message = getString(R.string.otp_import_failure_generic)) } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - title = - if (editing) getString(R.string.edit_password) else getString(R.string.new_password_title) - with(binding) { - setContentView(root) - generatePassword.setOnClickListener { generatePassword() } - otpImportButton.setOnClickListener { - supportFragmentManager.setFragmentResultListener( - OTP_RESULT_REQUEST_KEY, - this@PasswordCreationActivity, - ) { requestKey, bundle -> - if (requestKey == OTP_RESULT_REQUEST_KEY) { - val contents = bundle.getString(RESULT) - val currentExtras = binding.extraContent.text.toString() - if (currentExtras.isNotEmpty() && currentExtras.last() != '\n') - binding.extraContent.append("\n$contents") - else binding.extraContent.append(contents) - } - } - val hasCamera = packageManager?.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) == true - if (hasCamera) { - val items = - arrayOf( - getString(R.string.otp_import_qr_code), - getString(R.string.otp_import_from_file), - getString(R.string.otp_import_manual_entry), - ) - MaterialAlertDialogBuilder(this@PasswordCreationActivity) - .setItems(items) { _, index -> - when (index) { - 0 -> - otpImportAction.launch( - IntentIntegrator(this@PasswordCreationActivity) - .setOrientationLocked(false) - .setBeepEnabled(false) - .setDesiredBarcodeFormats(QR_CODE) - .createScanIntent() - ) - 1 -> imageImportAction.launch("image/*") - 2 -> OtpImportDialogFragment().show(supportFragmentManager, "OtpImport") - } - } - .show() - } else { - OtpImportDialogFragment().show(supportFragmentManager, "OtpImport") - } - } - - directoryInputLayout.apply { - if (suggestedName != null || suggestedPass != null || shouldGeneratePassword) { - isEnabled = true - } else { - setBackgroundColor(getColor(android.R.color.transparent)) - } - val path = getRelativePath(fullPath, repoPath) - // Keep empty path field visible if it is editable. - if (path.isEmpty() && !isEnabled) visibility = View.GONE - else { - directory.setText(path) - oldCategory = path - } - } - if (suggestedName != null) { - filename.setText(suggestedName) - } else { - filename.requestFocus() - } - - if ( - AutofillPreferences.directoryStructure(this@PasswordCreationActivity) == - DirectoryStructure.EncryptedUsername || suggestedUsername != null - ) { - usernameInputLayout.visibility = View.VISIBLE - if (suggestedUsername != null) username.setText(suggestedUsername) - else if (suggestedName != null) username.requestFocus() - } - - // Allow the user to quickly switch between storing the username as the filename or - // in the encrypted extras. This only makes sense if the directory structure is - // FileBased. - if ( - suggestedName == null && - AutofillPreferences.directoryStructure(this@PasswordCreationActivity) == - DirectoryStructure.FileBased - ) { - encryptUsername.apply { - visibility = View.VISIBLE - setOnClickListener { - if (isChecked) { - // User wants to enable username encryption, so we use the filename - // as username and insert it into the username input field. - val login = filename.text.toString() - filename.text?.clear() - username.setText(login) - usernameInputLayout.apply { visibility = View.VISIBLE } - } else { - // User wants to disable username encryption, so we take the username - // from the username text field and insert it into the filename input field. - val login = username.text.toString() - username.text?.clear() - filename.setText(login) - usernameInputLayout.apply { visibility = View.GONE } - } - } - } - } - suggestedPass?.let { - password.setText(it) - password.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD - } - suggestedExtra?.let { extraContent.setText(it) } - if (shouldGeneratePassword) { - generatePassword() - password.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD - } - } - listOf(binding.filename, binding.username, binding.extraContent).forEach { - it.doAfterTextChanged { updateViewState() } - } - updateViewState() - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.pgp_handler_new_password, menu) - return true - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - android.R.id.home -> { - setResult(RESULT_CANCELED) - onBackPressedDispatcher.onBackPressed() - } - R.id.save_password -> { - copy = false - requireKeysExist { encrypt() } - } - R.id.save_and_copy_password -> { - copy = true - requireKeysExist { encrypt() } - } - else -> return super.onOptionsItemSelected(item) - } - return true - } - - private fun generatePassword() { - supportFragmentManager.setFragmentResultListener(PASSWORD_RESULT_REQUEST_KEY, this) { - requestKey, - bundle -> - if (requestKey == PASSWORD_RESULT_REQUEST_KEY) { - binding.password.setText(bundle.getString(RESULT)) - } - } - when (settings.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) ?: KEY_PWGEN_TYPE_DICEWARE) { - KEY_PWGEN_TYPE_CLASSIC -> - PasswordGeneratorDialogFragment().show(supportFragmentManager, "generator") - KEY_PWGEN_TYPE_DICEWARE -> - DicewarePasswordGeneratorDialogFragment().show(supportFragmentManager, "generator") - } - } - - private fun updateViewState() = - with(binding) { - encryptUsername.apply { - if (visibility != View.VISIBLE) return@apply - val hasUsernameInFileName = filename.text.toString().isNotBlank() - val usernameIsEncrypted = username.text.toString().isNotEmpty() - isEnabled = hasUsernameInFileName xor usernameIsEncrypted - isChecked = usernameIsEncrypted - } - // Use PasswordEntry to parse extras for OTP - val entry = - passwordEntryFactory.create("PLACEHOLDER\n${extraContent.text}".encodeToByteArray()) - otpImportButton.isVisible = !entry.hasTotp() - } - - /** Encrypts the password and the extra content */ - private fun encrypt() { - with(binding) { - val oldName = suggestedName - val editName = filename.text.toString().trim() - var editUsername = username.text.toString() - val editPass = password.text.toString() - val editExtra = extraContent.text.toString() - - if (editName.isEmpty()) { - snackbar(message = resources.getString(R.string.file_toast_text)) - return@with - } else if (editName.contains('/')) { - snackbar(message = resources.getString(R.string.invalid_filename_text)) - return@with - } - - if (!editUsername.isEmpty()) { - editUsername = "\nusername: $editUsername" - } - - if (editPass.isEmpty() && editExtra.isEmpty()) { - snackbar(message = resources.getString(R.string.empty_toast_text)) - return@with - } - - if (copy) { - copyPasswordToClipboard(editPass) - } - - // pass enters the key ID into `.gpg-id`. - val gpgIdentifiers = getPGPIdentifiers(directory.text.toString()) ?: return@with - val content = "$editPass$editUsername\n$editExtra" - val path = - when { - // If we allowed the user to edit the relative path, we have to consider it here - // instead of fullPath. - directoryInputLayout.isEnabled -> { - val editRelativePath = directory.text.toString().trim() - if (editRelativePath.isEmpty()) { - snackbar(message = resources.getString(R.string.path_toast_text)) - return - } - val passwordDirectory = Paths.get(repoPath, editRelativePath.trim('/')) - passwordDirectory.createDirectories() - if (!passwordDirectory.exists()) { - snackbar( - message = - "Failed to create directory ${passwordDirectory.relativeTo(Paths.get(repoPath)).pathString}" - ) - return - } - - "${passwordDirectory.pathString}/$editName.gpg" - } - else -> "$fullPath/$editName.gpg" - } - - lifecycleScope.launch(dispatcherProvider.main()) { - runCatching { - val result = - withContext(dispatcherProvider.io()) { - val outputStream = ByteArrayOutputStream() - repository.encrypt(gpgIdentifiers, content.byteInputStream(), outputStream) - } - .getOrElse { e -> - logcat(ERROR) { e.asLog("Failed to encrypt password file") } - MaterialAlertDialogBuilder(this@PasswordCreationActivity) - .setTitle(R.string.password_creation_file_fail_title) - .setMessage( - getString(R.string.password_creation_encrypt_fail_message, e.message) - ) - .setPositiveButton(android.R.string.ok, null) - .show() - return@runCatching - } - val passwordFile = Paths.get(path) - // If we're not editing, this file should not already exist! - // Additionally, if we were editing and the incoming and outgoing - // filenames differ, it means we renamed. Ensure that the target - // doesn't already exist to prevent an accidental overwrite. - if ( - (!editing || (editing && suggestedName != passwordFile.nameWithoutExtension)) && - passwordFile.exists() - ) { - snackbar(message = getString(R.string.password_creation_duplicate_error)) - return@runCatching - } - - if (!passwordFile.toFile().isInsideRepository()) { - snackbar(message = getString(R.string.message_error_destination_outside_repo)) - return@runCatching - } - - withContext(dispatcherProvider.io()) { passwordFile.writeBytes(result.toByteArray()) } - - // associate the new password name with the last name's timestamp in history - val preference = getSharedPreferences("recent_password_history", Context.MODE_PRIVATE) - val oldFilePathHash = "$repoPath/${oldCategory?.trim('/')}/$suggestedName.gpg".base64() - val timestamp = preference.getString(oldFilePathHash) - if (timestamp != null) { - preference.edit { - remove(oldFilePathHash) - putString(passwordFile.absolutePathString().base64(), timestamp) - } - } - - val returnIntent = Intent() - returnIntent.putExtra(RETURN_EXTRA_CREATED_FILE, path) - returnIntent.putExtra(RETURN_EXTRA_NAME, editName) - returnIntent.putExtra(RETURN_EXTRA_LONG_NAME, getLongName(fullPath, repoPath, editName)) - - if (shouldGeneratePassword) { - val directoryStructure = AutofillPreferences.directoryStructure(applicationContext) - val entry = passwordEntryFactory.create(content.encodeToByteArray()) - returnIntent.putExtra(RETURN_EXTRA_PASSWORD, entry.password) - val username = - entry.username ?: directoryStructure.getUsernameFor(passwordFile.toFile()) - returnIntent.putExtra(RETURN_EXTRA_USERNAME, username) - } - - if ( - directoryInputLayout.isVisible && - directoryInputLayout.isEnabled && - oldName != editName - ) { - val oldPath = Paths.get(repoPath, oldCategory?.trim('/') ?: "", "$oldName.gpg") - if (!oldPath.isSameFileAs(passwordFile) && !oldPath.deleteIfExists()) { - setResult(RESULT_CANCELED) - MaterialAlertDialogBuilder(this@PasswordCreationActivity) - .setTitle(R.string.password_creation_file_fail_title) - .setMessage( - getString(R.string.password_creation_file_delete_fail_message, oldName) - ) - .setCancelable(false) - .setPositiveButton(android.R.string.ok) { _, _ -> finish() } - .show() - return@runCatching - } - } - - val commitMessageRes = - if (editing) R.string.git_commit_edit_text else R.string.git_commit_add_text - lifecycleScope.launch { - commitChange( - resources.getString(commitMessageRes, getLongName(fullPath, repoPath, editName)) - ) - .onSuccess { - setResult(RESULT_OK, returnIntent) - finish() - } - } - } - .onFailure { e -> - if (e is IOException) { - logcat(ERROR) { e.asLog("Failed to write password file") } - setResult(RESULT_CANCELED) - MaterialAlertDialogBuilder(this@PasswordCreationActivity) - .setTitle(getString(R.string.password_creation_file_fail_title)) - .setMessage(getString(R.string.password_creation_file_write_fail_message)) - .setCancelable(false) - .setPositiveButton(android.R.string.ok) { _, _ -> finish() } - .show() - } else { - logcat(ERROR) { e.asLog() } - } - } - } - } - } - - companion object { - - private const val KEY_PWGEN_TYPE_CLASSIC = "classic" - private const val KEY_PWGEN_TYPE_DICEWARE = "diceware" - const val PASSWORD_RESULT_REQUEST_KEY = "PASSWORD_GENERATOR" - const val OTP_RESULT_REQUEST_KEY = "OTP_IMPORT" - const val RESULT = "RESULT" - const val RETURN_EXTRA_CREATED_FILE = "CREATED_FILE" - const val RETURN_EXTRA_NAME = "NAME" - const val RETURN_EXTRA_LONG_NAME = "LONG_NAME" - const val RETURN_EXTRA_USERNAME = "USERNAME" - const val RETURN_EXTRA_PASSWORD = "PASSWORD" - const val EXTRA_FILE_NAME = "FILENAME" - const val EXTRA_USERNAME = "USERNAME" - const val EXTRA_PASSWORD = "PASSWORD" - const val EXTRA_EXTRA_CONTENT = "EXTRA_CONTENT" - const val EXTRA_GENERATE_PASSWORD = "GENERATE_PASSWORD" - const val EXTRA_EDITING = "EDITING" - } -} diff --git a/app/src/main/java/app/passwordstore/ui/dialogs/DicewarePasswordGeneratorDialogFragment.kt b/app/src/main/java/app/passwordstore/ui/dialogs/DicewarePasswordGeneratorDialogFragment.kt deleted file mode 100644 index 2605e0ef..00000000 --- a/app/src/main/java/app/passwordstore/ui/dialogs/DicewarePasswordGeneratorDialogFragment.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.ui.dialogs - -import android.app.AlertDialog -import android.app.Dialog -import android.content.SharedPreferences -import android.graphics.Typeface -import android.os.Bundle -import androidx.core.content.edit -import androidx.core.os.bundleOf -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.setFragmentResult -import androidx.lifecycle.lifecycleScope -import app.passwordstore.R -import app.passwordstore.databinding.FragmentPwgenDicewareBinding -import app.passwordstore.injection.prefs.PasswordGeneratorPreferences -import app.passwordstore.passgen.diceware.DicewarePassphraseGenerator -import app.passwordstore.ui.crypto.PasswordCreationActivity -import app.passwordstore.util.extensions.getString -import app.passwordstore.util.settings.PreferenceKeys.DICEWARE_LENGTH -import app.passwordstore.util.settings.PreferenceKeys.DICEWARE_SEPARATOR -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject -import kotlinx.coroutines.flow.merge -import kotlinx.coroutines.launch -import reactivecircus.flowbinding.android.widget.afterTextChanges - -@AndroidEntryPoint -class DicewarePasswordGeneratorDialogFragment : DialogFragment() { - - @Inject lateinit var dicewareGenerator: DicewarePassphraseGenerator - @Inject @PasswordGeneratorPreferences lateinit var prefs: SharedPreferences - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val builder = MaterialAlertDialogBuilder(requireContext()) - - val binding = FragmentPwgenDicewareBinding.inflate(layoutInflater) - builder.setView(binding.root) - - binding.passwordSeparatorText.setText(prefs.getString(DICEWARE_SEPARATOR) ?: "-") - binding.passwordLengthText.setText(prefs.getInt(DICEWARE_LENGTH, 5).toString()) - binding.passwordText.typeface = Typeface.MONOSPACE - - lifecycleScope.launch { - merge( - binding.passwordLengthText.afterTextChanges(), - binding.passwordSeparatorText.afterTextChanges(), - ) - .collect { _ -> generatePassword(binding) } - } - return builder - .run { - setTitle(R.string.pwgen_title) - setPositiveButton(R.string.dialog_ok) { _, _ -> - setFragmentResult( - PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY, - bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}"), - ) - } - setNeutralButton(R.string.dialog_cancel) { _, _ -> } - setNegativeButton(R.string.pwgen_generate, null) - create() - } - .apply { - setOnShowListener { - generatePassword(binding) - getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener { generatePassword(binding) } - } - } - } - - private fun generatePassword(binding: FragmentPwgenDicewareBinding) { - val length = binding.passwordLengthText.text?.toString()?.toIntOrNull() ?: 5 - val separator = binding.passwordSeparatorText.text?.toString()?.getOrNull(0) ?: '-' - setPreferences(length, separator) - binding.passwordText.text = dicewareGenerator.generatePassphrase(length, separator) - } - - private fun setPreferences(length: Int, separator: Char) { - prefs.edit { - putInt(DICEWARE_LENGTH, length) - putString(DICEWARE_SEPARATOR, separator.toString()) - } - } -} diff --git a/app/src/main/java/app/passwordstore/ui/dialogs/OtpImportDialogFragment.kt b/app/src/main/java/app/passwordstore/ui/dialogs/OtpImportDialogFragment.kt deleted file mode 100644 index 1a75175b..00000000 --- a/app/src/main/java/app/passwordstore/ui/dialogs/OtpImportDialogFragment.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.ui.dialogs - -import android.app.Dialog -import android.net.Uri -import android.os.Bundle -import android.view.WindowManager -import androidx.core.os.bundleOf -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.setFragmentResult -import app.passwordstore.databinding.FragmentManualOtpEntryBinding -import app.passwordstore.ui.crypto.PasswordCreationActivity -import com.google.android.material.dialog.MaterialAlertDialogBuilder - -class OtpImportDialogFragment : DialogFragment() { - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val builder = MaterialAlertDialogBuilder(requireContext()) - val binding = FragmentManualOtpEntryBinding.inflate(layoutInflater) - builder.setView(binding.root) - builder.setPositiveButton(android.R.string.ok) { _, _ -> - setFragmentResult( - PasswordCreationActivity.OTP_RESULT_REQUEST_KEY, - bundleOf(PasswordCreationActivity.RESULT to getTOTPUri(binding)), - ) - } - val dialog = builder.create() - dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) - return dialog - } - - private fun getTOTPUri(binding: FragmentManualOtpEntryBinding): String { - val secret = binding.secret.text.toString() - val account = binding.account.text.toString() - if (secret.isBlank()) return "" - val builder = Uri.Builder() - builder.scheme("otpauth") - builder.authority("totp") - builder.appendQueryParameter("secret", secret) - if (account.isNotBlank()) builder.appendQueryParameter("issuer", account) - return builder.build().toString() - } -} diff --git a/app/src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt b/app/src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt deleted file mode 100644 index d4a2372b..00000000 --- a/app/src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ -package app.passwordstore.ui.dialogs - -import android.app.AlertDialog -import android.app.Dialog -import android.content.Context -import android.graphics.Typeface -import android.os.Bundle -import android.widget.CheckBox -import android.widget.EditText -import android.widget.Toast -import androidx.annotation.IdRes -import androidx.appcompat.widget.AppCompatTextView -import androidx.core.content.edit -import androidx.core.os.bundleOf -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.setFragmentResult -import androidx.lifecycle.lifecycleScope -import app.passwordstore.R -import app.passwordstore.databinding.FragmentPwgenBinding -import app.passwordstore.passgen.random.MaxIterationsExceededException -import app.passwordstore.passgen.random.NoCharactersIncludedException -import app.passwordstore.passgen.random.PasswordGenerator -import app.passwordstore.passgen.random.PasswordLengthTooShortException -import app.passwordstore.passgen.random.PasswordOption -import app.passwordstore.ui.crypto.PasswordCreationActivity -import app.passwordstore.util.settings.PreferenceKeys -import com.github.michaelbull.result.getOrElse -import com.github.michaelbull.result.runCatching -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.coroutines.flow.merge -import kotlinx.coroutines.launch -import reactivecircus.flowbinding.android.widget.afterTextChanges -import reactivecircus.flowbinding.android.widget.checkedChanges - -class PasswordGeneratorDialogFragment : DialogFragment() { - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val prefs = requireContext().getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE) - val builder = MaterialAlertDialogBuilder(requireContext()) - - val binding = FragmentPwgenBinding.inflate(layoutInflater) - builder.setView(binding.root) - - binding.numerals.isChecked = !prefs.getBoolean(PasswordOption.NoDigits.key, false) - binding.symbols.isChecked = prefs.getBoolean(PasswordOption.AtLeastOneSymbol.key, false) - binding.uppercase.isChecked = !prefs.getBoolean(PasswordOption.NoUppercaseLetters.key, false) - binding.lowercase.isChecked = !prefs.getBoolean(PasswordOption.NoLowercaseLetters.key, false) - binding.ambiguous.isChecked = !prefs.getBoolean(PasswordOption.NoAmbiguousCharacters.key, false) - binding.pronounceable.isChecked = !prefs.getBoolean(PasswordOption.FullyRandom.key, true) - binding.lengthNumber.setText(prefs.getInt(PreferenceKeys.LENGTH, 20).toString()) - binding.passwordText.typeface = Typeface.MONOSPACE - - lifecycleScope.launch { - merge( - binding.numerals.checkedChanges().skipInitialValue(), - binding.symbols.checkedChanges().skipInitialValue(), - binding.uppercase.checkedChanges().skipInitialValue(), - binding.lowercase.checkedChanges().skipInitialValue(), - binding.ambiguous.checkedChanges().skipInitialValue(), - binding.pronounceable.checkedChanges().skipInitialValue(), - binding.lengthNumber.afterTextChanges().skipInitialValue(), - ) - .collect { generate(binding.passwordText) } - } - - return builder - .run { - setTitle(R.string.pwgen_title) - setPositiveButton(R.string.dialog_ok) { _, _ -> - setFragmentResult( - PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY, - bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}"), - ) - } - setNeutralButton(R.string.dialog_cancel) { _, _ -> } - setNegativeButton(R.string.pwgen_generate, null) - create() - } - .apply { - setOnShowListener { - generate(binding.passwordText) - getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener { - generate(binding.passwordText) - } - } - } - } - - private fun generate(passwordField: AppCompatTextView) { - val passwordOptions = getSelectedOptions() - val passwordLength = getLength() - setPrefs(requireContext(), passwordOptions, passwordLength) - passwordField.text = - runCatching { PasswordGenerator.generate(passwordOptions, passwordLength) } - .getOrElse { exception -> - val errorText = - when (exception) { - is MaxIterationsExceededException -> - requireContext().getString(R.string.pwgen_max_iterations_exceeded) - is NoCharactersIncludedException -> - requireContext().getString(R.string.pwgen_no_chars_error) - is PasswordLengthTooShortException -> - requireContext().getString(R.string.pwgen_length_too_short_error) - else -> requireContext().getString(R.string.pwgen_some_error_occurred) - } - Toast.makeText(requireActivity(), errorText, Toast.LENGTH_SHORT).show() - "" - } - } - - private fun isChecked(@IdRes id: Int): Boolean { - return requireDialog().findViewById<CheckBox>(id).isChecked - } - - private fun getSelectedOptions(): List<PasswordOption> { - return listOfNotNull( - PasswordOption.NoDigits.takeIf { !isChecked(R.id.numerals) }, - PasswordOption.AtLeastOneSymbol.takeIf { isChecked(R.id.symbols) }, - PasswordOption.NoUppercaseLetters.takeIf { !isChecked(R.id.uppercase) }, - PasswordOption.NoAmbiguousCharacters.takeIf { !isChecked(R.id.ambiguous) }, - PasswordOption.FullyRandom.takeIf { !isChecked(R.id.pronounceable) }, - PasswordOption.NoLowercaseLetters.takeIf { !isChecked(R.id.lowercase) }, - ) - } - - private fun getLength(): Int { - val lengthText = requireDialog().findViewById<EditText>(R.id.lengthNumber).text.toString() - return lengthText.toIntOrNull()?.takeIf { it >= 0 } ?: PasswordGenerator.DEFAULT_LENGTH - } - - /** - * Enables the [PasswordOption]s in [options] and sets [targetLength] as the length for generated - * passwords. - */ - private fun setPrefs(ctx: Context, options: List<PasswordOption>, targetLength: Int): Boolean { - ctx.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE).edit { - for (possibleOption in PasswordOption.entries) { - putBoolean(possibleOption.key, possibleOption in options) - } - putInt("length", targetLength) - } - return true - } -} diff --git a/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderActivity.kt b/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderActivity.kt deleted file mode 100644 index 2139d7d2..00000000 --- a/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderActivity.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ -package app.passwordstore.ui.folderselect - -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.commit -import app.passwordstore.R -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class SelectFolderActivity : AppCompatActivity(R.layout.select_folder_layout) { - - private lateinit var passwordList: SelectFolderFragment - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - passwordList = SelectFolderFragment() - supportActionBar?.show() - supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) - supportFragmentManager.commit { replace(R.id.pgp_handler_linearlayout, passwordList) } - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.pgp_handler_select_folder, menu) - return true - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - android.R.id.home -> { - setResult(RESULT_CANCELED) - onBackPressedDispatcher.onBackPressed() - } - R.id.crypto_select -> selectFolder() - else -> return super.onOptionsItemSelected(item) - } - return true - } - - private fun selectFolder() { - intent.putExtra("SELECTED_FOLDER_PATH", passwordList.currentDir.absolutePath) - setResult(RESULT_OK, intent) - finish() - } -} diff --git a/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt b/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt deleted file mode 100644 index acf4b56d..00000000 --- a/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ -package app.passwordstore.ui.folderselect - -import android.content.Context -import android.os.Bundle -import android.view.View -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.lifecycle.flowWithLifecycle -import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.LinearLayoutManager -import app.passwordstore.R -import app.passwordstore.data.password.PasswordItem -import app.passwordstore.data.repo.PasswordRepository -import app.passwordstore.databinding.PasswordRecyclerViewBinding -import app.passwordstore.ui.adapters.PasswordItemRecyclerAdapter -import app.passwordstore.util.coroutines.DispatcherProvider -import app.passwordstore.util.extensions.viewBinding -import app.passwordstore.util.viewmodel.ListMode -import app.passwordstore.util.viewmodel.SearchableRepositoryViewModel -import com.github.michaelbull.result.onFailure -import com.github.michaelbull.result.runCatching -import dagger.hilt.android.AndroidEntryPoint -import java.io.File -import javax.inject.Inject -import kotlinx.coroutines.launch -import me.zhanghai.android.fastscroll.FastScrollerBuilder - -@AndroidEntryPoint -class SelectFolderFragment : Fragment(R.layout.password_recycler_view) { - - @Inject lateinit var dispatcherProvider: DispatcherProvider - private val binding by viewBinding(PasswordRecyclerViewBinding::bind) - private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter - private lateinit var listener: OnFragmentInteractionListener - - private val model: SearchableRepositoryViewModel by activityViewModels() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.fab.hide() - recyclerAdapter = - PasswordItemRecyclerAdapter(lifecycleScope, dispatcherProvider).onItemClicked { _, item -> - listener.onFragmentInteraction(item) - } - binding.passRecycler.apply { - layoutManager = LinearLayoutManager(requireContext()) - itemAnimator = null - adapter = recyclerAdapter - } - - FastScrollerBuilder(binding.passRecycler).build() - registerForContextMenu(binding.passRecycler) - - model.navigateTo( - PasswordRepository.getRepositoryDirectory(), - listMode = ListMode.DirectoriesOnly, - pushPreviousLocation = false, - ) - lifecycleScope.launch { - model.searchResult.flowWithLifecycle(lifecycle).collect { result -> - recyclerAdapter.submitList(result.passwordItems) - } - } - } - - override fun onAttach(context: Context) { - super.onAttach(context) - runCatching { - listener = - object : OnFragmentInteractionListener { - override fun onFragmentInteraction(item: PasswordItem) { - if (item.type == PasswordItem.TYPE_CATEGORY) { - model.navigateTo(item.file, listMode = ListMode.DirectoriesOnly) - (requireActivity() as AppCompatActivity) - .supportActionBar - ?.setDisplayHomeAsUpEnabled(true) - } - } - } - } - .onFailure { - throw ClassCastException("$context must implement OnFragmentInteractionListener") - } - } - - val currentDir: File - get() = model.currentDir.value - - interface OnFragmentInteractionListener { - - fun onFragmentInteraction(item: PasswordItem) - } -} diff --git a/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt b/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt index a13484c6..bad55de4 100644 --- a/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt +++ b/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt @@ -95,18 +95,13 @@ fun FragmentActivity.isPermissionGranted(permission: String): Boolean { return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED } -/** - * Show a [Snackbar] in a [FragmentActivity] and correctly anchor it to a - * [com.google.android.material.floatingactionbutton.FloatingActionButton] if one exists in the - * [view] - */ +/** Show a [Snackbar] in a [FragmentActivity]. */ fun FragmentActivity.snackbar( view: View = findViewById(android.R.id.content), message: String, length: Int = Snackbar.LENGTH_SHORT, ): Snackbar { val snackbar = Snackbar.make(view, message, length) - snackbar.anchorView = findViewById(R.id.fab) snackbar.show() return snackbar } diff --git a/app/src/main/res/drawable/ic_done_24dp.xml b/app/src/main/res/drawable/ic_done_24dp.xml deleted file mode 100644 index f8b6cef6..00000000 --- a/app/src/main/res/drawable/ic_done_24dp.xml +++ /dev/null @@ -1,15 +0,0 @@ -<!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:tint="?attr/colorControlNormal" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="#FFFFFF" - android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" /> -</vector> diff --git a/app/src/main/res/drawable/ic_save_24dp.xml b/app/src/main/res/drawable/ic_save_24dp.xml deleted file mode 100644 index 8a4276c4..00000000 --- a/app/src/main/res/drawable/ic_save_24dp.xml +++ /dev/null @@ -1,15 +0,0 @@ -<!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:tint="?attr/colorControlNormal" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="#FFFFFF" - android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM19,19L5,19L5,5h11.17L19,7.83L19,19zM12,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM6,6h9v4L6,10z" /> -</vector> diff --git a/app/src/main/res/drawable/ic_save_copy_24dp.xml b/app/src/main/res/drawable/ic_save_copy_24dp.xml deleted file mode 100644 index 06419aac..00000000 --- a/app/src/main/res/drawable/ic_save_copy_24dp.xml +++ /dev/null @@ -1,15 +0,0 @@ -<!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:tint="?attr/colorControlNormal" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="#FFFFFF" - android:pathData="M19,5L7,5A2,2 0,0 0,5 7L5,21a2,2 0,0 0,2 2L21,23a2,2 0,0 0,2 -2L23,9ZM21,21L7,21L7,7L18.17,7L21,9.83ZM14,14a3,3 0,1 0,3 3A3,3 0,0 0,14 14ZM8,8h9v4L8,12ZM15,1L3,1A2,2 0,0 0,1 3L1,17L3,17L3,3L15,3Z" /> -</vector> diff --git a/app/src/main/res/layout/fragment_manual_otp_entry.xml b/app/src/main/res/layout/fragment_manual_otp_entry.xml deleted file mode 100644 index 7d7ea832..00000000 --- a/app/src/main/res/layout/fragment_manual_otp_entry.xml +++ /dev/null @@ -1,53 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<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_height="match_parent"> - - <com.google.android.material.textfield.TextInputLayout - android:id="@+id/secret_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="@string/otp_import_manual_hint_secret" - android:paddingStart="16dp" - android:paddingTop="16dp" - android:paddingEnd="16dp" - app:hintEnabled="true" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/secret" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:inputType="textPassword" /> - - <requestFocus /> - - </com.google.android.material.textfield.TextInputLayout> - - <com.google.android.material.textfield.TextInputLayout - android:id="@+id/account_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="@string/otp_import_manual_hint_account" - android:paddingStart="16dp" - android:paddingTop="16dp" - android:paddingEnd="16dp" - android:paddingBottom="16dp" - app:hintEnabled="true" - app:layout_constraintTop_toBottomOf="@id/secret_layout"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/account" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - - </com.google.android.material.textfield.TextInputLayout> - -</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_pwgen.xml b/app/src/main/res/layout/fragment_pwgen.xml deleted file mode 100644 index 02eadff5..00000000 --- a/app/src/main/res/layout/fragment_pwgen.xml +++ /dev/null @@ -1,115 +0,0 @@ -<!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingLeft="24dp" - android:paddingTop="20dp" - android:paddingRight="24dp" - android:paddingBottom="20dp" - tools:context=".MainActivityFragment"> - - <androidx.appcompat.widget.AppCompatTextView - android:id="@+id/passwordText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textIsSelectable="true" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:baselineAligned="false" - android:orientation="horizontal" - android:weightSum="2"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="vertical"> - - <androidx.appcompat.widget.AppCompatTextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:text="@string/pwgen_include" - android:textAppearance="?android:attr/textAppearanceSmall" /> - - <CheckBox - android:id="@+id/numerals" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/pwgen_numerals" /> - - - <CheckBox - android:id="@+id/symbols" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/pwgen_symbols" /> - - <CheckBox - android:id="@+id/uppercase" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/pwgen_uppercase" /> - - <CheckBox - android:id="@+id/lowercase" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/pwgen_lowercase" /> - - </LinearLayout> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="vertical"> - - <androidx.appcompat.widget.AppCompatTextView - android:id="@+id/length" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:labelFor="@id/lengthNumber" - android:text="@string/pwgen_length" - android:textAppearance="?android:attr/textAppearanceSmall" /> - - <EditText - android:id="@+id/lengthNumber" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:autofillHints="notApplicable" - android:ems="10" - android:inputType="number" /> - - <CheckBox - android:id="@+id/pronounceable" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/pwgen_pronounceable" /> - - <CheckBox - android:id="@+id/ambiguous" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/pwgen_ambiguous" /> - - </LinearLayout> - </LinearLayout> - </LinearLayout> -</ScrollView> diff --git a/app/src/main/res/layout/fragment_pwgen_diceware.xml b/app/src/main/res/layout/fragment_pwgen_diceware.xml deleted file mode 100644 index b8627670..00000000 --- a/app/src/main/res/layout/fragment_pwgen_diceware.xml +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<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_height="wrap_content" - android:orientation="vertical" - android:paddingLeft="24dp" - android:paddingTop="20dp" - android:paddingRight="24dp" - android:paddingBottom="20dp"> - - <androidx.appcompat.widget.AppCompatTextView - android:id="@+id/password_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceMedium" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - <com.google.android.material.textfield.TextInputLayout - android:id="@+id/password_length" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:layout_marginEnd="4dp" - android:hint="@string/pwgen_length" - android:labelFor="@id/password_length_text" - app:hintAnimationEnabled="true" - app:hintEnabled="true" - app:layout_constraintEnd_toStartOf="@id/password_separator" - app:layout_constraintHorizontal_weight="0.5" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/password_text"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/password_length_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="number" - android:maxLength="2" /> - </com.google.android.material.textfield.TextInputLayout> - - <com.google.android.material.textfield.TextInputLayout - android:id="@+id/password_separator" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginStart="4dp" - android:layout_marginTop="8dp" - android:hint="@string/pwgen_separator" - android:labelFor="@id/password_separator_text" - app:hintAnimationEnabled="true" - app:hintEnabled="true" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_weight="0.5" - app:layout_constraintStart_toEndOf="@id/password_length" - app:layout_constraintTop_toBottomOf="@id/password_text"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/password_separator_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:autofillHints="" - android:importantForAutofill="no" - android:inputType="text" - android:maxLength="1" /> - </com.google.android.material.textfield.TextInputLayout> - -</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/password_creation_activity.xml b/app/src/main/res/layout/password_creation_activity.xml deleted file mode 100644 index c0692753..00000000 --- a/app/src/main/res/layout/password_creation_activity.xml +++ /dev/null @@ -1,147 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - - -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:fillViewport="false" - tools:context="app.passwordstore.ui.crypto.PasswordCreationActivity"> - - <androidx.constraintlayout.widget.ConstraintLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:padding="@dimen/activity_horizontal_margin"> - - <com.google.android.material.textfield.TextInputLayout - android:id="@+id/directory_input_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_margin="8dp" - android:enabled="false" - android:hint="@string/directory_hint" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/directory" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:imeOptions="actionNext" - android:inputType="textNoSuggestions" - android:nextFocusForward="@id/password" - tools:text="CATEGORY HERE" /> - </com.google.android.material.textfield.TextInputLayout> - - <com.google.android.material.textfield.TextInputLayout - android:id="@+id/name_input_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_margin="8dp" - android:hint="@string/crypto_name_hint" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/directory_input_layout"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/filename" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:imeOptions="actionNext" - android:inputType="textNoSuggestions" - android:nextFocusForward="@id/username" /> - </com.google.android.material.textfield.TextInputLayout> - - <com.google.android.material.textfield.TextInputLayout - android:visibility="gone" - tools:visibility="visible" - android:id="@+id/username_input_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_margin="8dp" - android:hint="@string/crypto_username_hint" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/name_input_layout"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/username" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:imeOptions="actionNext" - android:inputType="textNoSuggestions" - android:nextFocusForward="@id/password" /> - </com.google.android.material.textfield.TextInputLayout> - - <com.google.android.material.textfield.TextInputLayout - android:id="@+id/password_input_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_margin="8dp" - android:hint="@string/crypto_pass_label" - app:endIconMode="password_toggle" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/username_input_layout"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/password" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:imeOptions="actionDone" - android:inputType="textVisiblePassword" /> - </com.google.android.material.textfield.TextInputLayout> - - <com.google.android.material.button.MaterialButton - android:id="@+id/generate_password" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_margin="8dp" - android:text="@string/pwd_generate_button" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/password_input_layout" /> - - <com.google.android.material.textfield.TextInputLayout - android:id="@+id/extra_input_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_margin="8dp" - android:hint="@string/crypto_extra_label" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/generate_password"> - - <com.google.android.material.textfield.TextInputEditText - android:id="@+id/extra_content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="textMultiLine|textVisiblePassword" /> - - </com.google.android.material.textfield.TextInputLayout> - - <com.google.android.material.button.MaterialButton - android:id="@+id/otp_import_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_margin="8dp" - android:text="@string/add_otp" - app:icon="@drawable/ic_qr_code_scanner" - app:iconTint="?attr/colorOnSecondary" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/extra_input_layout" /> - - <com.google.android.material.switchmaterial.SwitchMaterial - android:id="@+id/encrypt_username" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_margin="8dp" - android:text="@string/crypto_encrypt_username_label" - android:visibility="gone" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/otp_import_button" - tools:visibility="visible" /> - </androidx.constraintlayout.widget.ConstraintLayout> -</ScrollView> diff --git a/app/src/main/res/layout/password_recycler_view.xml b/app/src/main/res/layout/password_recycler_view.xml deleted file mode 100644 index c2b5114f..00000000 --- a/app/src/main/res/layout/password_recycler_view.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:clipChildren="false" - android:clipToPadding="false" - android:orientation="vertical"> - - <androidx.swiperefreshlayout.widget.SwipeRefreshLayout - android:id="@+id/swipe_refresher" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <me.zhanghai.android.fastscroll.FixOnItemTouchListenerRecyclerView - android:id="@+id/pass_recycler" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scrollbars="none" - tools:itemCount="20" - tools:listitem="@layout/password_row_layout" /> - </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> - - <com.google.android.material.floatingactionbutton.FloatingActionButton - android:id="@+id/fab" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_alignParentBottom="true" - android:layout_gravity="bottom|end" - android:layout_margin="@dimen/fab_compat_margin" - android:contentDescription="@string/password_list_fab_content_description" - android:src="@drawable/ic_add_48dp" /> -</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/app/src/main/res/layout/password_row_layout.xml b/app/src/main/res/layout/password_row_layout.xml deleted file mode 100644 index 5c042839..00000000 --- a/app/src/main/res/layout/password_row_layout.xml +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="@drawable/password_row_background" - android:paddingTop="12dp" - android:paddingBottom="12dp"> - - <androidx.appcompat.widget.AppCompatTextView - android:id="@+id/label" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:layout_marginStart="@dimen/activity_horizontal_margin" - android:textSize="18sp" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@id/child_count" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - tools:text="FILE_NAME" /> - - <androidx.appcompat.widget.AppCompatTextView - android:id="@+id/child_count" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="8dp" - android:textSize="18sp" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@id/folder_indicator" - app:layout_constraintTop_toTopOf="parent" - tools:text="12" /> - - <androidx.appcompat.widget.AppCompatImageView - android:id="@+id/folder_indicator" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/activity_horizontal_margin" - android:contentDescription="@null" - android:src="@drawable/ic_keyboard_arrow_right_24dp" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - -</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/select_folder_layout.xml b/app/src/main/res/layout/select_folder_layout.xml deleted file mode 100644 index 78b03579..00000000 --- a/app/src/main/res/layout/select_folder_layout.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - - <LinearLayout - android:id="@+id/pgp_handler_linearlayout" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" /> -</LinearLayout> diff --git a/app/src/main/res/menu/pgp_handler_new_password.xml b/app/src/main/res/menu/pgp_handler_new_password.xml deleted file mode 100644 index 6c61fb55..00000000 --- a/app/src/main/res/menu/pgp_handler_new_password.xml +++ /dev/null @@ -1,20 +0,0 @@ -<!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:pwstore="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - tools:context=".ui.crypto.PgpActivity"> - <item - android:id="@+id/save_password" - android:icon="@drawable/ic_save_24dp" - android:title="@string/crypto_save" - pwstore:showAsAction="ifRoom" /> - <item - android:id="@+id/save_and_copy_password" - android:icon="@drawable/ic_save_copy_24dp" - android:title="@string/crypto_save_and_copy" - pwstore:showAsAction="ifRoom" /> -</menu> diff --git a/app/src/main/res/menu/pgp_handler_select_folder.xml b/app/src/main/res/menu/pgp_handler_select_folder.xml deleted file mode 100644 index d9505814..00000000 --- a/app/src/main/res/menu/pgp_handler_select_folder.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - ~ SPDX-License-Identifier: GPL-3.0-only - --> - -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:pwstore="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - tools:context="app.passwordstore.SelectFolderActivity"> - <item - android:id="@+id/crypto_select" - android:icon="@drawable/ic_done_24dp" - android:title="@string/crypto_select" - pwstore:showAsAction="ifRoom" /> -</menu> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d13ab19f..a9fa4b00 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -39,7 +39,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">In die Zwischenablage kopiert</string> <string name="file_toast_text">Bitte setzen Sie einen Dateinamen.</string> - <string name="path_toast_text">Bitte setzen Sie einen Pfad.</string> <string name="empty_toast_text">Sie können kein leeres Passwort oder leere Extra-Angaben setzen.</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Es ist ein Fehler während der Git-Operation aufgetreten.</string> @@ -63,7 +62,6 @@ <string name="crypto_name_hint">Name</string> <string name="crypto_pass_label">Passwort</string> <string name="crypto_extra_label">Zusätzliche Angaben</string> - <string name="crypto_encrypt_username_label">Benutzername verschlüsseln</string> <string name="crypto_select">Auswählen</string> <string name="crypto_save">Speichern</string> <string name="crypto_save_and_copy">Speichern und kopieren</string> @@ -125,7 +123,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">Passwort erstellen</string> <string name="pwgen_generate">Erstellen</string> - <string name="pwgen_include">Einschließen</string> <string name="pwgen_length">Länge</string> <string name="pwgen_numerals">Nummern</string> <string name="pwgen_symbols">Symbole</string> @@ -173,7 +170,6 @@ <string name="git_log">Commit-Log anzeigen</string> <string name="show_password_pref_title">Zeige das Passwort.</string> <string name="show_password_pref_summary">Soll das entschlüsselte Passwort sichtbar sein? Dies deaktiviert nicht das Kopieren.</string> - <string name="pwd_generate_button">Erstellen</string> <string name="send_plaintext_password_to">Passwort unverschlüsselt senden an…</string> <string name="app_icon_hint">App-Icon</string> <!-- Oreo Autofill --> @@ -207,7 +203,6 @@ <string name="oreo_autofill_enable_dialog_installed_browsers">Autofill-Unterstützung mit installierten Browsern:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">Der private SSH-Schlüssel konnte nicht geöffnet werden. Bitte überprüfen Sie, ob die Datei existiert.</string> - <string name="new_password_title">Neues Passwort</string> <string name="clear_saved_passphrase_ssh">Gespeicherte Passphrase für lokalen SSH-Schlüssel löschen</string> <string name="clear_saved_passphrase_https">Gespeichertes HTTPS-Passwort löschen</string> <string name="git_operation_remember_passphrase">Schlüsselpasswort merken</string> @@ -276,7 +271,6 @@ <string name="invalid_gpg_id">.gpg-id wurde gefunden, enthält jedoch ungültige Schlüssel-ID, Fingerabdruck oder Benutzer-ID.</string> <string name="short_gpg_id">.gpg-id wurde gefunden, enthält jedoch eine kurze Hex-ID, die nicht unterstützt wird.</string> <string name="invalid_filename_text">Dateiname darf kein \'/\' enthalten; Verzeichnis oben setzen</string> - <string name="directory_hint">Ordner</string> <!-- GitException messages --> <string name="git_unknown_error">Unbekannter Fehler</string> <string name="git_pull_rebase_fail_error">Pull fehlgeschlagen. Sie befinden sich in einem abgelösten Head. Speichern Sie die Änderungen in \"Einstellungen > Lokale Git-Konfiguration & Dienstprogramme\" auf das Remote-Repository in einem neuen Branch und lösen Sie den Konflikt auf Ihrem Computer auf.</string> @@ -319,11 +313,9 @@ <string name="clear_saved_host_key_success">Host-Schlüssel erfolgreich gelöscht!</string> <string name="otp_import_qr_code">QR-Code scannen</string> <string name="otp_import_from_file">Wählen Sie ein Bild.</string> - <string name="otp_import_manual_entry">Manuell eingeben</string> <string name="otp_import_manual_hint_secret">Schlüssel</string> <string name="otp_import_manual_hint_account">Benutzer-Konto</string> <string name="place_shortcut_on_home_screen">Verknüpfung auf dem Home-Screen erstellen</string> - <string name="password_list_fab_content_description">Neues Passwort oder neuen Ordner erstellen</string> <string name="pgp_key_import_failed">Fehler beim Import des PGP-Schlüssels</string> <string name="pgp_key_import_failed_replace_message">Ein bestehender Schlüssel mit dieser ID wurde gefunden. Möchten Sie ihn ersetzen?</string> <string name="pgp_key_import_succeeded">PGP-Schlüssel erfolgreich importiert</string> diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0cfb345c..d41048f8 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -38,7 +38,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">Copié dans le presse-papiers</string> <string name="file_toast_text">Veuillez fournir un nom de fichier</string> - <string name="path_toast_text">Veuillez fournir un chemin d\'accès au fichier</string> <string name="empty_toast_text">Vous ne pouvez pas utiliser un mot de passe vide ou des données supplémentaires vide</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Une erreur c\'est produite lors d\'une opération Git</string> @@ -62,7 +61,6 @@ <string name="crypto_name_hint">Nom</string> <string name="crypto_pass_label">Mot de passe</string> <string name="crypto_extra_label">Extra</string> - <string name="crypto_encrypt_username_label">Chiffrer le nom d\'utilisateur</string> <string name="crypto_select">Sélectionner</string> <string name="crypto_save">Sauvegarder</string> <string name="crypto_save_and_copy">Enregistrer et copier</string> @@ -113,7 +111,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">Générer un mot de passe</string> <string name="pwgen_generate">Générer</string> - <string name="pwgen_include">Inclure</string> <string name="pwgen_length">Longueur</string> <string name="pwgen_numerals">Chiffres</string> <string name="pwgen_symbols">Symboles</string> @@ -161,7 +158,6 @@ <string name="git_log">Afficher l\'historique des commits</string> <string name="show_password_pref_title">Montrer le mot de passe</string> <string name="show_password_pref_summary">Contrôle la visibilité des mots de passe une fois déchifrées, ceci n\'empêche pas de copier le mot de passe</string> - <string name="pwd_generate_button">Générer</string> <string name="send_plaintext_password_to">Envoyer le mot de passe en clair via…</string> <string name="app_icon_hint">Icône de l\'application</string> <!-- Oreo Autofill --> @@ -195,7 +191,6 @@ <string name="oreo_autofill_enable_dialog_installed_browsers">Prise en charge du remplissage automatique avec les navigateurs installés:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">Impossible d\'ouvrir la clef ssh, merci de vérifier que le ficher existe</string> - <string name="new_password_title">Nouveau mot de passe</string> <string name="clear_saved_passphrase_ssh">Effacer le mot de passe enregistrée pour la clé SSH locale</string> <string name="clear_saved_passphrase_https">Effacer le mot de passe HTTPS enregistré</string> <string name="git_operation_remember_passphrase">Se rappeler de la phrase secrète dans la configuration de l\'application (peu sûr)</string> @@ -261,7 +256,6 @@ <string name="otp_import_failure_generic">Impossible d\'importer la configuration TOTP</string> <string name="exporting_passwords">Exportation des mots de passe…</string> <string name="invalid_filename_text">Le nom du fichier ne doit pas contenir \'/\', définir le répertoire parent</string> - <string name="directory_hint">Dossier</string> <!-- GitException messages --> <string name="git_unknown_error">Erreur inconnue</string> <string name="git_pull_rebase_fail_error">Tirer a échoué, vous êtes dans un \'head\' détaché. En utilisant \"settings > git utils\", enregistrez vos modifications sur le dépôt distant dans une nouvelle branche et résolvez le conflit sur votre ordinateur.</string> @@ -300,10 +294,8 @@ <string name="clear_saved_host_key_success">La clé d\'hôte a été effacée avec succès!</string> <string name="otp_import_qr_code">Scanner le code QR</string> <string name="otp_import_from_file">Choisissez une image</string> - <string name="otp_import_manual_entry">Saisir manuellement</string> <string name="otp_import_manual_hint_secret">Secret</string> <string name="otp_import_manual_hint_account">Compte</string> - <string name="password_list_fab_content_description">Créer un nouveau mot de passe ou dossier</string> <string name="pgp_key_import_failed">Impossible d\'importer la clé PGP</string> <string name="pgp_key_import_succeeded">Clé PGP importée avec succès</string> <string name="pgp_key_import_succeeded_message">La clé d\'identification de la clé importée est donné ci-dessous, veuillez la vérifier pour qu\'elle soit correcte :\n%1$s</string> diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 589208ab..3fb321e7 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -39,7 +39,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">Copiado ao portapapeis</string> <string name="file_toast_text">Debes proporcionar un nome de ficheiro</string> - <string name="path_toast_text">Por favor indica a ruta ao ficheiro</string> <string name="empty_toast_text">Non podes deixar baleiro o contrasinal ou o contido extra</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Algo fallou na operación de Git</string> @@ -63,7 +62,6 @@ <string name="crypto_name_hint">Nome</string> <string name="crypto_pass_label">Contrasinal</string> <string name="crypto_extra_label">Contido extra</string> - <string name="crypto_encrypt_username_label">Cifrar identificador</string> <string name="crypto_select">Seleccionar</string> <string name="crypto_save">Gardar</string> <string name="crypto_save_and_copy">Gardar e copiar</string> @@ -126,7 +124,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">Crear contrasinal</string> <string name="pwgen_generate">Crear</string> - <string name="pwgen_include">Incluír</string> <string name="pwgen_length">Lonxitude</string> <string name="pwgen_numerals">Números</string> <string name="pwgen_symbols">Símbolos</string> @@ -174,7 +171,6 @@ <string name="git_log">Mostrar rexistro dos cambios</string> <string name="show_password_pref_title">Mostrar contrasinal</string> <string name="show_password_pref_summary">Controlar a visibilidade do contrasinal unha vez descifrado, esto non desactiva o copiado do contrasinal</string> - <string name="pwd_generate_button">Crear</string> <string name="send_plaintext_password_to">Enviar contrasinal como texto plano usando…</string> <string name="app_icon_hint">Icona da app</string> <!-- Oreo Autofill --> @@ -209,7 +205,6 @@ a app desde unha fonte de confianza, como a Play Store, Amazon Appstore, F-Droid <string name="oreo_autofill_enable_dialog_installed_browsers">Soporte de autocompletado cos navegadores:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">Non se pode abrir a chave privada ssh, comproba que existe tal ficheiro</string> - <string name="new_password_title">Novo contrasinal</string> <string name="clear_saved_passphrase_ssh">Baleirar a frase de paso gardada para a chave SSH local</string> <string name="clear_saved_passphrase_https">Baleirar contrasinal HTTPS gardado</string> <string name="git_operation_remember_passphrase">Lembrar frase de paso da chave</string> @@ -278,7 +273,6 @@ a app desde unha fonte de confianza, como a Play Store, Amazon Appstore, F-Droid <string name="invalid_gpg_id">Atopouse .gpg-id, pero contén un ID de chave, impresión dixital ou ID de usuaria non válidos</string> <string name="short_gpg_id">Atopouse .gpg-id, pero contén un ID hex curto, ao que non damos soporte</string> <string name="invalid_filename_text">O nome do ficheiro non pode conter \'/\', establece un directorio superior</string> - <string name="directory_hint">Directorio</string> <!-- GitException messages --> <string name="git_unknown_error">Fallo descoñecido</string> <string name="git_pull_rebase_fail_error">Fallou a acción pull, estás nun head diferente. Utiliza \"axustes > utilidades git\", garda os cambios no remoto nunha nova rama e resolve o conflicto nun ordenador.</string> @@ -321,11 +315,9 @@ a app desde unha fonte de confianza, como a Play Store, Amazon Appstore, F-Droid <string name="clear_saved_host_key_success">Eliminouse correctamente a chave gardada do host!</string> <string name="otp_import_qr_code">Escanear código QR</string> <string name="otp_import_from_file">Elixe unha imaxe</string> - <string name="otp_import_manual_entry">Escribir manualmente</string> <string name="otp_import_manual_hint_secret">Segredo</string> <string name="otp_import_manual_hint_account">Conta</string> <string name="place_shortcut_on_home_screen">Crear atallo na pantalla de inicio</string> - <string name="password_list_fab_content_description">Crear novo contrasinal ou cartafol</string> <string name="pgp_key_import_failed">Fallou a importación da chave PGP</string> <string name="pgp_key_import_failed_replace_message">Atopouse unha chave existente con este ID, queres substituíla?</string> <string name="pgp_key_import_succeeded">Chave PGP importada correctamente</string> diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 91cd28aa..c14efa33 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -38,7 +38,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">Copiato negli appunti</string> <string name="file_toast_text">Inserisci un nome per il file</string> - <string name="path_toast_text">Inserisci il percorso del file</string> <string name="empty_toast_text">Non puoi usare una password vuota o dei contenuti extra vuoti</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Si è verificato un errore durante un\'operazione Git</string> @@ -62,7 +61,6 @@ <string name="crypto_name_hint">Nome</string> <string name="crypto_pass_label">Password</string> <string name="crypto_extra_label">Contenuto extra</string> - <string name="crypto_encrypt_username_label">Crittografa nome utente</string> <string name="crypto_select">Seleziona</string> <string name="crypto_save">Salva</string> <string name="crypto_save_and_copy">Salva e Copia</string> @@ -108,7 +106,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">Genera Password</string> <string name="pwgen_generate">Genera</string> - <string name="pwgen_include">Includi</string> <string name="pwgen_length">Lunghezza</string> <string name="pwgen_numerals">Numeri</string> <string name="pwgen_symbols">Simboli</string> @@ -156,7 +153,6 @@ <string name="git_log">Mostra registro dei commit</string> <string name="show_password_pref_title">Mostra la password</string> <string name="show_password_pref_summary">Controlla la visibilità delle password una volta decrittografate. Questo non disabilita la copia negli appunti.</string> - <string name="pwd_generate_button">Genera</string> <string name="send_plaintext_password_to">Invia password come testo semplice usando…</string> <string name="app_icon_hint">Icona app</string> <!-- Oreo Autofill --> @@ -190,7 +186,6 @@ <string name="oreo_autofill_enable_dialog_installed_browsers">Supporto alla compilazione automatica nei browser installati:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">Impossibile aprire la chiave privata SSH, controlla che il file esista</string> - <string name="new_password_title">Nuova password</string> <string name="clear_saved_passphrase_ssh">Cancella la frase segreta salvata per la chiave SSH locale</string> <string name="clear_saved_passphrase_https">Cancella la password HTTPS salvata</string> <string name="git_operation_remember_passphrase">Ricorda la frase segreta della chiave</string> @@ -256,7 +251,6 @@ <string name="otp_import_failure_generic">Impossibile importare la configurazione di TOTP</string> <string name="exporting_passwords">Esportazione delle password…</string> <string name="invalid_filename_text">Il nome del file non deve contenere \'/\', imposta la directory qui sopra</string> - <string name="directory_hint">Directory</string> <!-- GitException messages --> <string name="git_unknown_error">Errore sconosciuto</string> <string name="git_pull_rebase_fail_error">Pull non riuscito, sei in detached HEAD. Da \"Impostazioni > Utilità Git\" esegui il push delle modifiche sul remote in un nuovo branch e risolvi il conflitto dal computer.</string> @@ -293,7 +287,6 @@ <string name="clear_saved_host_key">Cancella la chiave host salvata</string> <string name="clear_saved_host_key_success">Chiave host cancellata con successo!</string> <string name="otp_import_from_file">Scegli un\'immagine</string> - <string name="password_list_fab_content_description">Crea nuova password o cartella</string> <string name="git_commit_gpg_id">Inizializza gli ID GPG in %1$s.</string> <string name="crypto_username_hint">Nome utente</string> <string name="otp_label_format">OTP (scade tra %ds)</string> @@ -327,7 +320,6 @@ <string name="git_scheme_disallowed_message">Il protocollo git di git-daemon non cifra il trasporto e non è adatto a operazioni sicure.</string> <string name="activity_proxy_label">Impostazioni proxy</string> <string name="otp_import_qr_code">Scansiona codice QR</string> - <string name="otp_import_manual_entry">Inserisci manualmente</string> <string name="otp_import_manual_hint_secret">Segreto</string> <string name="otp_import_manual_hint_account">Account</string> <string name="place_shortcut_on_home_screen">Aggiungi scorciatoia alla schermata Home</string> diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index 7f63ad8b..3efbed68 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -37,7 +37,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">클립보드로 복사됨</string> <string name="file_toast_text">파일 이름이 필요합니다</string> - <string name="path_toast_text">파일 경로가 필요합니다</string> <string name="empty_toast_text">비어있는 비밀번호나 추가 정보를 사용할 수 없습니다</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Git 동작 중 문제가 발생하였습니다</string> @@ -61,7 +60,6 @@ <string name="crypto_name_hint">이름</string> <string name="crypto_pass_label">비밀번호</string> <string name="crypto_extra_label">추가 내용</string> - <string name="crypto_encrypt_username_label">암호화 계정 이름</string> <string name="crypto_select">선택</string> <string name="crypto_save">저장</string> <string name="crypto_save_and_copy">저장 및 복사</string> @@ -121,7 +119,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">암호 생성</string> <string name="pwgen_generate">생성</string> - <string name="pwgen_include">포함</string> <string name="pwgen_length">길이</string> <string name="pwgen_numerals">숫자만</string> <string name="pwgen_symbols">특수문자</string> @@ -169,7 +166,6 @@ <string name="git_log">커밋 로그 보기</string> <string name="show_password_pref_title">비밀번호 표시하기</string> <string name="show_password_pref_summary">암호가 해독된 후 비밀번호의 공개 여부를 제어합니다. 그렇다고 해서 클립보드 복사가 비활성화되지는 않습니다.</string> - <string name="pwd_generate_button">생성</string> <string name="send_plaintext_password_to">비밀번호를 일반 텍스트로 보내는 중…</string> <string name="app_icon_hint">앱 아이콘</string> <!-- Oreo Autofill --> @@ -203,7 +199,6 @@ <string name="oreo_autofill_enable_dialog_installed_browsers">자동 완성 지원 하는 설치된 브라우저:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">SSH 개인 키를 열 수 없습니다. 파일이 존재하는지 확인하세요</string> - <string name="new_password_title">새 암호</string> <string name="clear_saved_passphrase_ssh">로컬 SSH 키의 저장된 비밀번호 지우기</string> <string name="clear_saved_passphrase_https">저장된 HTTPS 비밀번호 지우기</string> <string name="git_operation_remember_passphrase">키 암호 기억하기</string> @@ -274,7 +269,6 @@ username@example.com:…</string> <string name="invalid_gpg_id">.gpg-id를 찾았지만 잘못된 키 ID, 지문 또는 사용자 ID가 포함되어 있습니다</string> <string name="short_gpg_id">.gpg-id를 찾았지만, 지원되지 않는 짧은 16진수 ID가 포함되어 있습니다.</string> <string name="invalid_filename_text">파일 이름에 \'/\'가 포함되어서는 안됩니다. 위의 디렉터리를 설정하세요</string> - <string name="directory_hint">디렉토리</string> <!-- GitException messages --> <string name="git_unknown_error">알 수 없는 오류</string> <string name="git_pull_rebase_fail_error">풀이 실패하여 head가 분리된 상태입니다. \"설정 > git 기능\"을 사용하여 원격 저장소에 변경 내용을 새 브랜치에 저장하고 컴퓨터에서 충돌을 해결하세요.</string> @@ -317,11 +311,9 @@ username@example.com:…</string> <string name="clear_saved_host_key_success">저장된 호스트 키를 성공적으로 지웠습니다!</string> <string name="otp_import_qr_code">QR코드 스캔</string> <string name="otp_import_from_file">이미지 선택</string> - <string name="otp_import_manual_entry">직접 입력</string> <string name="otp_import_manual_hint_secret">비밀</string> <string name="otp_import_manual_hint_account">계정</string> <string name="place_shortcut_on_home_screen">홈 화면에 추가</string> - <string name="password_list_fab_content_description">새 비밀번호 또는 폴더 만들기</string> <string name="pgp_key_import_failed">PGP 키를 가져오지 못했습니다</string> <string name="pgp_key_import_failed_replace_message">이 ID를 가진 기존 키가 발견되었습니다. 교체하시겠습니까?</string> <string name="pgp_key_import_succeeded">PGP 키를 성공적으로 가져왔습니다</string> diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index a2068e65..65f14ce5 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -37,7 +37,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">Skopiowano do schowka</string> <string name="file_toast_text">Podaj nazwę pliku</string> - <string name="path_toast_text">Podaj ścieżkę do pliku</string> <string name="empty_toast_text">Nie możesz użyć pustego hasła lub pustej dodatkowej zawartości</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Wystąpił błąd podczas operacji Git</string> @@ -61,7 +60,6 @@ <string name="crypto_name_hint">Nazwa</string> <string name="crypto_pass_label">Hasło</string> <string name="crypto_extra_label">Treść dodatkowa</string> - <string name="crypto_encrypt_username_label">Szyfruj nazwę użytkownika</string> <string name="crypto_select">Wybierz</string> <string name="crypto_save">Zapisz</string> <string name="crypto_save_and_copy">Zapisz i skopiuj</string> @@ -122,7 +120,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">Generuj hasło</string> <string name="pwgen_generate">Wygeneruj</string> - <string name="pwgen_include">Załącz</string> <string name="pwgen_length">Długość</string> <string name="pwgen_numerals">Cyfry</string> <string name="pwgen_symbols">Symbole</string> @@ -170,7 +167,6 @@ <string name="git_log">Pokaż dziennik commitów</string> <string name="show_password_pref_title">Pokaż hasło</string> <string name="show_password_pref_summary">Kontroluj widoczność haseł po odszyfrowaniu. To nie wyłącza kopiowania do schowka.</string> - <string name="pwd_generate_button">Generuj</string> <string name="send_plaintext_password_to">Wyślij niezaszyfrowane hasło, używając…</string> <string name="app_icon_hint">Ikona aplikacji</string> <!-- Oreo Autofill --> @@ -202,7 +198,6 @@ <string name="oreo_autofill_enable_dialog_installed_browsers">Obsługa autouzupełniania w zainstalowanych przeglądarkach:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">Nie można otworzyć klucza prywatnego ssh, sprawdź czy plik istnieje</string> - <string name="new_password_title">Nowe hasło</string> <string name="clear_saved_passphrase_ssh">Wyczyść zapisane hasło dla lokalnego klucza SSH</string> <string name="clear_saved_passphrase_https">Wyczyść zapisane hasło HTTPS</string> <string name="git_operation_remember_passphrase">Zapamiętaj hasło klucza</string> @@ -268,7 +263,6 @@ <string name="invalid_gpg_id">Znaleziono .gpg-id, ale zawiera nieprawidłowy identyfikator klucza, odcisk palca lub identyfikator użytkownika</string> <string name="short_gpg_id">Znaleziono .gpg-id, ale zawarty w nim skrócony identyfikator nie jest obsługiwany</string> <string name="invalid_filename_text">Nazwa pliku nie może zawierać \'/\', ustaw katalog powyżej</string> - <string name="directory_hint">Katalog</string> <!-- GitException messages --> <string name="git_unknown_error">Nieznany błąd</string> <string name="git_pull_rebase_fail_error">Zaciąganie zmian nie powiodło się, nie jesteś na żadnej gałęzi (detached head). Używając \"Ustawienia > narzędzia Git\", wyślij lokalne zmiany do zdalnego repozytorium na nowej gałęzi i rozwiąż konflikt na komputerze.</string> @@ -309,11 +303,9 @@ <string name="clear_saved_host_key_success">Pomyślnie wyczyszczono zapisany klucz hosta!</string> <string name="otp_import_qr_code">Skanuj kod QR</string> <string name="otp_import_from_file">Wybierz obraz</string> - <string name="otp_import_manual_entry">Wprowadź ręcznie</string> <string name="otp_import_manual_hint_secret">Sekret</string> <string name="otp_import_manual_hint_account">Konto</string> <string name="place_shortcut_on_home_screen">Utwórz skrót na pulpicie</string> - <string name="password_list_fab_content_description">Utwórz nowe hasło lub folder</string> <string name="pgp_key_import_failed">Nie udało się zaimportować klucza PGP</string> <string name="pgp_key_import_failed_replace_message">Znaleziono istniejący klucz z tym identyfikatorem, czy chcesz go zastąpić?</string> <string name="pgp_key_import_succeeded">Pomyślnie zaimportowano klucz PGP</string> diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 909fd33e..86ebfb24 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -39,7 +39,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">Copiado para a área de transferência</string> <string name="file_toast_text">Por favor, informe um nome de arquivo</string> - <string name="path_toast_text">Por favor, forneça o caminho do arquivo</string> <string name="empty_toast_text">Você não pode usar uma senha vazia ou conteúdo extra vazio</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Ocorreu um erro durante uma operação do Git</string> @@ -63,7 +62,6 @@ <string name="crypto_name_hint">Nome</string> <string name="crypto_pass_label">Senha</string> <string name="crypto_extra_label">Conteúdo extra</string> - <string name="crypto_encrypt_username_label">Criptografar nome de usuário</string> <string name="crypto_select">Selecionar</string> <string name="crypto_save">Salvar</string> <string name="crypto_save_and_copy">Salvar e Copiar</string> @@ -125,7 +123,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">Gerar Senha</string> <string name="pwgen_generate">Gerar</string> - <string name="pwgen_include">Incluir</string> <string name="pwgen_length">Tamanho</string> <string name="pwgen_numerals">Numerais</string> <string name="pwgen_symbols">Símbolos</string> @@ -173,7 +170,6 @@ <string name="git_log">Mostrar log de commit</string> <string name="show_password_pref_title">Mostrar a senha</string> <string name="show_password_pref_summary">Controle a visibilidade das senhas quando descriptografadas. Isso não desativa a cópia para a área de transferência.</string> - <string name="pwd_generate_button">Gerar</string> <string name="send_plaintext_password_to">Enviar senha como texto simples usando…</string> <string name="app_icon_hint">Ícone do aplicativo</string> <!-- Oreo Autofill --> @@ -207,7 +203,6 @@ <string name="oreo_autofill_enable_dialog_installed_browsers">Suporte ao preenchimento automático com navegadores instalados:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">Não foi possível abrir a chave privada ssh, por favor verifique se o arquivo existe</string> - <string name="new_password_title">Nova senha</string> <string name="clear_saved_passphrase_ssh">Limpar a frase secreta salva para chave SSH local</string> <string name="clear_saved_passphrase_https">Limpar senha HTTPS salva</string> <string name="git_operation_remember_passphrase">Lembrar senha da chave</string> @@ -276,7 +271,6 @@ <string name="invalid_gpg_id">Encontrado .gpg-id, mas contém um ID de chave, fingerprint ou ID de usuário inválidos</string> <string name="short_gpg_id">Encontrado .gpg-id, mas contém uma ID hexadecimal curta, que não é suportada</string> <string name="invalid_filename_text">Nome do arquivo não deve conter \'/\', defina o diretório acima</string> - <string name="directory_hint">Diretório</string> <!-- GitException messages --> <string name="git_unknown_error">Erro desconhecido</string> <string name="git_pull_rebase_fail_error">O pull falhou, você está em uma Head avulsa. Usando \"configurações > utils\" do git, salve suas alterações no remoto em uma nova branch e resolva o conflito no seu computador.</string> @@ -319,11 +313,9 @@ <string name="clear_saved_host_key_success">Chave de host limpa com sucesso!</string> <string name="otp_import_qr_code">Escanear QR code</string> <string name="otp_import_from_file">Selecione uma imagem</string> - <string name="otp_import_manual_entry">Inserir manualmente</string> <string name="otp_import_manual_hint_secret">Segredo</string> <string name="otp_import_manual_hint_account">Conta</string> <string name="place_shortcut_on_home_screen">Criar atalho na tela inicial</string> - <string name="password_list_fab_content_description">Criar nova senha ou pasta</string> <string name="pgp_key_import_failed">Falha ao importar a chave PGP</string> <string name="pgp_key_import_failed_replace_message">Uma chave existente com esse ID foi encontrada, você deseja substituí-lo?</string> <string name="pgp_key_import_succeeded">Chave PGP importada com sucesso</string> diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2ef59d70..8873b34f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -43,7 +43,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">Скопировано в буфер обмена</string> <string name="file_toast_text">Пожалуйста, укажите имя файла</string> - <string name="path_toast_text">Пожалуйста, задайте путь к файлу</string> <string name="empty_toast_text">Вы не можете использовать пустой пароль или пустое поле информации</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Произошла ошибка выполнения операции Git</string> @@ -67,7 +66,6 @@ <string name="crypto_name_hint">название</string> <string name="crypto_pass_label">Пароль</string> <string name="crypto_extra_label">Дополнительно</string> - <string name="crypto_encrypt_username_label">Зашифровать имя пользователя</string> <string name="crypto_select">Выбрать</string> <string name="crypto_save">Сохранить</string> <string name="crypto_save_and_copy">Сохранить и скопировать</string> @@ -118,7 +116,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">Сгенерировать пароль</string> <string name="pwgen_generate">Сгенерировать</string> - <string name="pwgen_include">Включая</string> <string name="pwgen_length">Длина</string> <string name="pwgen_numerals">Цифры</string> <string name="pwgen_symbols">Символы</string> @@ -166,7 +163,6 @@ <string name="git_log">Показать журнал изменений</string> <string name="show_password_pref_title">Показывать пароли</string> <string name="show_password_pref_summary">Видимость расшифрованных паролей, не влияет на копирование в буфер.</string> - <string name="pwd_generate_button">Сгенерировать</string> <string name="send_plaintext_password_to">Поделиться паролем в открытом виде с помощью</string> <string name="app_icon_hint">Иконка приложения</string> <!-- Oreo Autofill --> @@ -200,7 +196,6 @@ <string name="oreo_autofill_enable_dialog_installed_browsers">Поддержка автозаполнения установленными браузерами:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">Невозможно открыть приватный ключ ssh, пожалуйста проверьте, что файл существует</string> - <string name="new_password_title">Новый пароль</string> <string name="clear_saved_passphrase_ssh">Очистить сохраненную кодовую фразу для локального SSH ключа</string> <string name="clear_saved_passphrase_https">Удалить сохраненный пароль HTTPS</string> <string name="git_operation_remember_passphrase">Запомнить кодовую фразу</string> @@ -268,7 +263,6 @@ <string name="exporting_passwords">Экспорт паролей…</string> <string name="invalid_gpg_id">Найден .gpg-id, но он содержит неверный ID ключа, fingerprint или ID пользователя</string> <string name="invalid_filename_text">Имя файла не должно содержать \'/\', укажите директорию выше</string> - <string name="directory_hint">Директория</string> <!-- GitException messages --> <string name="git_unknown_error">Неизвестная ошибка</string> <string name="git_pull_rebase_fail_error">Не удалось получить изменения, вы находитесь в состоянии \"оторванной головы\". Используйте \"настройки > утилиты git\", сохраните ваши изменения в новую удаленную ветку и разрешите конфликты на своем компьютере.</string> @@ -311,10 +305,8 @@ <string name="clear_saved_host_key_success">Сохраненный ключ хоста был успешно удален!</string> <string name="otp_import_qr_code">Отсканировать QR-код</string> <string name="otp_import_from_file">Выберите изображение</string> - <string name="otp_import_manual_entry">Ввести вручную</string> <string name="otp_import_manual_hint_account">Учетная запись</string> <string name="place_shortcut_on_home_screen">Разместить ярлык на рабочем столе</string> - <string name="password_list_fab_content_description">Создать новый пароль или папку</string> <string name="pgp_key_import_failed">Не удалось импортировать PGP-ключ</string> <string name="pgp_key_import_succeeded">PGP ключ успешно импортирован</string> </resources> diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 55fbeefa..746b74d2 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -38,7 +38,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">复制到剪切板</string> <string name="file_toast_text">请提供文件名</string> - <string name="path_toast_text">请提供文件路径</string> <string name="empty_toast_text">您不能使用空密码或空额外内容</string> <!-- Git Async Task --> <string name="jgit_error_dialog_title">Git操作过程中发生错误</string> @@ -62,7 +61,6 @@ <string name="crypto_name_hint">名称</string> <string name="crypto_pass_label">密码</string> <string name="crypto_extra_label">附加内容</string> - <string name="crypto_encrypt_username_label">加密用户名</string> <string name="crypto_select">选择</string> <string name="crypto_save">保存</string> <string name="crypto_save_and_copy">保存并复制</string> @@ -121,7 +119,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">生成密码</string> <string name="pwgen_generate">生成</string> - <string name="pwgen_include">包含</string> <string name="pwgen_length">长度</string> <string name="pwgen_numerals">数字</string> <string name="pwgen_symbols">标识</string> @@ -174,7 +171,6 @@ <string name="git_log">显示提交日志</string> <string name="show_password_pref_title">显示密码</string> <string name="show_password_pref_summary">控制密码解密后的可见性,这不会禁用复制到剪贴板</string> - <string name="pwd_generate_button">生成</string> <string name="send_plaintext_password_to">使用明文发送密码…</string> <string name="app_icon_hint">应用图标</string> <!-- Oreo Autofill --> @@ -209,7 +205,6 @@ <string name="oreo_autofill_enable_dialog_installed_browsers">已安装支持自动填充的浏览器:</string> <!-- Autofill --> <string name="ssh_key_does_not_exist">无法打开SSH私钥,请检查文件是否存在</string> - <string name="new_password_title">新密码</string> <string name="clear_saved_passphrase_ssh">清除本地已保存的SSH密钥密码</string> <string name="clear_saved_passphrase_https">清除保存的HTTPS密码</string> <string name="git_operation_remember_passphrase">记住密钥密码</string> @@ -278,7 +273,6 @@ personal.com</string> <string name="invalid_gpg_id">找到了 .gpg-id,但它包含无效的密钥ID、指纹或用户ID</string> <string name="short_gpg_id">找到 .gpg-id 但它包含一个不受支持的短十六进制ID。</string> <string name="invalid_filename_text">文件名不能包含\'/\'</string> - <string name="directory_hint">目录</string> <!-- GitException messages --> <string name="git_unknown_error">未知错误</string> <string name="git_pull_merge_fail_error">合并失败,你处于冲突状态。</string> @@ -324,11 +318,9 @@ GPG <string name="clear_saved_host_key_success">已成功清除已保存的主机密钥!</string> <string name="otp_import_qr_code">扫描二维码</string> <string name="otp_import_from_file">选择图像</string> - <string name="otp_import_manual_entry">手动输入</string> <string name="otp_import_manual_hint_secret">安全码 (Secret)</string> <string name="otp_import_manual_hint_account">账户</string> <string name="place_shortcut_on_home_screen">在主屏幕上放置快捷方式</string> - <string name="password_list_fab_content_description">创建新密码或文件夹</string> <string name="pgp_key_import_failed">导入 PGP 密钥失败</string> <string name="pgp_key_import_failed_replace_message">发现了 ID 相同的现有密钥,您要替换它吗?</string> <string name="pgp_key_import_succeeded">成功导入 PGP 密钥</string> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 34b11662..239cb219 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -47,7 +47,6 @@ <!-- PGPHandler --> <string name="clipboard_copied_text">Copied to clipboard</string> <string name="file_toast_text">Please provide a file name</string> - <string name="path_toast_text">Please provide a file path</string> <string name="empty_toast_text">You cannot use an empty password or empty extra content</string> <!-- Git Async Task --> @@ -79,7 +78,6 @@ <string name="crypto_username_hint">Username</string> <string name="crypto_pass_label">Password</string> <string name="crypto_extra_label">Extra content</string> - <string name="crypto_encrypt_username_label">Encrypt username</string> <string name="crypto_select">Select</string> <string name="crypto_save">Save</string> <string name="crypto_save_and_copy">Save and Copy</string> @@ -148,7 +146,6 @@ <!-- PasswordGenerator fragment --> <string name="pwgen_title">Generate Password</string> <string name="pwgen_generate">Generate</string> - <string name="pwgen_include">Include</string> <string name="pwgen_length">Length</string> <string name="pwgen_numerals">Numerals</string> <string name="pwgen_symbols">Symbols</string> @@ -201,7 +198,6 @@ <string name="git_log">Show commit log</string> <string name="show_password_pref_title">Show the password</string> <string name="show_password_pref_summary">Control the visibility of the passwords once decrypted. This does not disable copying to clipboard.</string> - <string name="pwd_generate_button">Generate</string> <string name="send_plaintext_password_to">Send password as plaintext using…</string> <string name="app_icon_hint">App icon</string> @@ -239,7 +235,6 @@ <!-- Autofill --> <string name="ssh_key_does_not_exist">Unable to open the ssh private key, please check that the file exists</string> - <string name="new_password_title">New password</string> <string name="clear_saved_passphrase_ssh">Clear saved passphrase for local SSH key</string> <string name="clear_saved_passphrase_https">Clear saved HTTPS password</string> <string name="git_operation_remember_passphrase">Remember key passphrase</string> @@ -311,7 +306,6 @@ <string name="invalid_gpg_id">Found .gpg-id, but it contains an invalid key ID, fingerprint or user ID</string> <string name="short_gpg_id">Found .gpg-id, but it contains a short hex ID, which is not supported</string> <string name="invalid_filename_text">File name must not contain \'/\', set directory above</string> - <string name="directory_hint">Directory</string> <!-- GitException messages --> <string name="git_unknown_error">Unknown error</string> @@ -360,11 +354,9 @@ <string name="clear_saved_host_key_success">Successfully cleared saved host key!</string> <string name="otp_import_qr_code">Scan QR code</string> <string name="otp_import_from_file">Choose an image</string> - <string name="otp_import_manual_entry">Enter manually</string> <string name="otp_import_manual_hint_secret">Secret</string> <string name="otp_import_manual_hint_account">Account</string> <string name="place_shortcut_on_home_screen">Place shortcut on home screen</string> - <string name="password_list_fab_content_description">Create new password or folder</string> <string name="pgp_key_import_failed">Failed to import PGP key</string> <string name="pgp_key_import_failed_replace_message">An existing key with this ID was found, do you want to replace it?</string> <string name="pgp_key_import_succeeded">Successfully imported PGP key</string> |
