Rework settings to use ModernAndroidPreferences (#1236)

Co-authored-by: Fabian Henneke <fabian@hen.ne.ke>
This commit is contained in:
Harsh Shandilya 2021-01-12 11:19:28 +05:30 committed by GitHub
parent 91e00d897f
commit 8bd156dea6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 1197 additions and 1108 deletions

View file

@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file.
### Changed
- Accessibility autofill has been removed completely due to being buggy, insecure and lacking in features. Upgrade to Android 8 or preferably later to gain access to our advanced Autofill implementation.
- The settings UI has been completely re-done to dramatically improve discoverability and navigation for users
## [1.13.1] - 2020-10-23

View file

@ -73,6 +73,7 @@ dependencies {
implementation(Dependencies.FirstParty.zxing_android_embedded)
implementation(Dependencies.ThirdParty.bouncycastle)
implementation(Dependencies.ThirdParty.commons_codec)
implementation(Dependencies.ThirdParty.eddsa)
implementation(Dependencies.ThirdParty.fastscroll)
@ -80,10 +81,10 @@ dependencies {
exclude(group = "org.apache.httpcomponents", module = "httpclient")
}
implementation(Dependencies.ThirdParty.kotlin_result)
implementation(Dependencies.ThirdParty.sshj)
implementation(Dependencies.ThirdParty.bouncycastle)
implementation(Dependencies.ThirdParty.modern_android_prefs)
implementation(Dependencies.ThirdParty.plumber)
implementation(Dependencies.ThirdParty.ssh_auth)
implementation(Dependencies.ThirdParty.sshj)
implementation(Dependencies.ThirdParty.timber)
implementation(Dependencies.ThirdParty.timberkt)

View file

@ -33,7 +33,8 @@
android:name=".ui.onboarding.activity.OnboardingActivity"
android:configChanges="orientation|screenSize" />
<activity android:name=".ui.proxy.ProxySelectorActivity"
<activity
android:name=".ui.proxy.ProxySelectorActivity"
android:windowSoftInputMode="adjustResize" />
<activity
@ -70,8 +71,13 @@
android:label="@string/title_activity_git_log" />
<activity
android:name=".ui.settings.UserPreference"
android:label="@string/action_settings" />
android:name=".ui.settings.SettingsActivity"
android:label="@string/action_settings"
android:parentActivityName=".ui.passwords.PasswordStore" />
<activity
android:name=".ui.settings.DirectorySelectionActivity"
android:theme="@style/NoBackgroundTheme" />
<activity
android:name=".ui.crypto.PasswordCreationActivity"
@ -104,6 +110,10 @@
</service>
<activity android:name=".ui.folderselect.SelectFolderActivity" />
<activity
android:name=".ui.sshkeygen.SshKeyImportActivity"
android:theme="@style/NoBackgroundTheme"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".ui.sshkeygen.SshKeyGenActivity"
android:label="@string/pref_ssh_keygen_title"

View file

@ -19,9 +19,9 @@ import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.ui.settings.UserPreference
import dev.msfjarvis.aps.databinding.FragmentRepoLocationBinding
import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.ui.settings.DirectorySelectionActivity
import dev.msfjarvis.aps.util.settings.PasswordSortOrder
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import dev.msfjarvis.aps.util.extensions.finish
@ -31,11 +31,13 @@ import dev.msfjarvis.aps.util.extensions.listFilesRecursively
import dev.msfjarvis.aps.util.extensions.performTransactionWithBackStack
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.extensions.viewBinding
import android.content.Intent
import java.io.File
class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
private val settings by lazy(LazyThreadSafetyMode.NONE) { requireActivity().applicationContext.sharedPrefs }
private val directorySelectIntent by lazy(LazyThreadSafetyMode.NONE) { Intent(requireContext(), DirectorySelectionActivity::class.java) }
private val binding by viewBinding(FragmentRepoLocationBinding::bind)
private val sortOrder: PasswordSortOrder
get() = PasswordSortOrder.getSortOrder(settings)
@ -57,7 +59,7 @@ class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
}
private val externalDirPermGrantedAction = createPermGrantedAction {
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
externalDirectorySelectAction.launch(directorySelectIntent)
}
private val repositoryUsePermGrantedAction = createPermGrantedAction {
@ -65,7 +67,7 @@ class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
}
private val repositoryChangePermGrantedAction = createPermGrantedAction {
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
repositoryInitAction.launch(directorySelectIntent)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -102,7 +104,7 @@ class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
} else {
// Unlikely we have storage permissions without user ever selecting a directory,
// but let's not assume.
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
externalDirectorySelectAction.launch(directorySelectIntent)
}
} else {
MaterialAlertDialogBuilder(requireActivity())
@ -119,7 +121,7 @@ class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
repositoryChangePermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
} else {
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
repositoryInitAction.launch(directorySelectIntent)
}
}
.show()

View file

@ -11,8 +11,8 @@ import android.view.View
import androidx.annotation.Keep
import androidx.fragment.app.Fragment
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.ui.settings.UserPreference
import dev.msfjarvis.aps.databinding.FragmentWelcomeBinding
import dev.msfjarvis.aps.ui.settings.SettingsActivity
import dev.msfjarvis.aps.util.extensions.performTransactionWithBackStack
import dev.msfjarvis.aps.util.extensions.viewBinding
@ -25,6 +25,6 @@ class WelcomeFragment : Fragment(R.layout.fragment_welcome) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.letsGo.setOnClickListener { parentFragmentManager.performTransactionWithBackStack(CloneFragment.newInstance()) }
binding.settingsButton.setOnClickListener { startActivity(Intent(requireContext(), UserPreference::class.java)) }
binding.settingsButton.setOnClickListener { startActivity(Intent(requireContext(), SettingsActivity::class.java)) }
}
}

View file

@ -42,7 +42,6 @@ import dev.msfjarvis.aps.ui.main.LaunchActivity
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.viewmodel.SearchableRepositoryViewModel
import dev.msfjarvis.aps.ui.folderselect.SelectFolderActivity
import dev.msfjarvis.aps.ui.settings.UserPreference
import dev.msfjarvis.aps.util.autofill.AutofillMatcher
import dev.msfjarvis.aps.ui.crypto.BasePgpActivity.Companion.getLongName
import dev.msfjarvis.aps.ui.crypto.DecryptActivity
@ -55,6 +54,8 @@ import dev.msfjarvis.aps.ui.dialogs.FolderCreationDialogFragment
import dev.msfjarvis.aps.ui.onboarding.activity.OnboardingActivity
import dev.msfjarvis.aps.data.password.PasswordItem
import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.ui.settings.DirectorySelectionActivity
import dev.msfjarvis.aps.ui.settings.SettingsActivity
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import dev.msfjarvis.aps.util.extensions.base64
import dev.msfjarvis.aps.util.extensions.commitChange
@ -300,7 +301,7 @@ class PasswordStore : BaseGitActivity() {
when (id) {
R.id.user_pref -> {
runCatching {
startActivity(Intent(this, UserPreference::class.java))
startActivity(Intent(this, SettingsActivity::class.java))
}.onFailure { e ->
e.printStackTrace()
}
@ -377,7 +378,7 @@ class PasswordStore : BaseGitActivity() {
private fun checkLocalRepository() {
val repo = PasswordRepository.initialize()
if (repo == null) {
directorySelectAction.launch(UserPreference.createDirectorySelectionIntent(this))
directorySelectAction.launch(Intent(this, DirectorySelectionActivity::class.java))
} else {
checkLocalRepository(PasswordRepository.getRepositoryDirectory())
}

View file

@ -0,0 +1,126 @@
/*
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import de.Maxr1998.modernpreferences.PreferenceScreen
import de.Maxr1998.modernpreferences.helpers.editText
import de.Maxr1998.modernpreferences.helpers.onClick
import de.Maxr1998.modernpreferences.helpers.singleChoice
import de.Maxr1998.modernpreferences.helpers.switch
import de.Maxr1998.modernpreferences.preferences.SwitchPreference
import de.Maxr1998.modernpreferences.preferences.choice.SelectionItem
import dev.msfjarvis.aps.BuildConfig
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.extensions.autofillManager
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.appcompat.widget.AppCompatTextView
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import com.github.androidpasswordstore.autofillparser.BrowserAutofillSupportLevel
import com.github.androidpasswordstore.autofillparser.getInstalledBrowsersWithAutofillSupportLevel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class AutofillSettings(private val activity: FragmentActivity) : SettingsProvider {
private val isAutofillServiceEnabled: Boolean
get() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false
return activity.autofillManager?.hasEnabledAutofillServices() == true
}
@RequiresApi(Build.VERSION_CODES.O)
private fun showAutofillDialog(pref: SwitchPreference) {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_RESUME -> {
pref.checked = isAutofillServiceEnabled
}
else -> {
}
}
}
MaterialAlertDialogBuilder(activity).run {
setTitle(R.string.pref_autofill_enable_title)
@SuppressLint("InflateParams")
val layout =
activity.layoutInflater.inflate(R.layout.oreo_autofill_instructions, null)
val supportedBrowsersTextView =
layout.findViewById<AppCompatTextView>(R.id.supportedBrowsers)
supportedBrowsersTextView.text =
getInstalledBrowsersWithAutofillSupportLevel(context).joinToString(
separator = "\n"
) {
val appLabel = it.first
val supportDescription = when (it.second) {
BrowserAutofillSupportLevel.None -> activity.getString(R.string.oreo_autofill_no_support)
BrowserAutofillSupportLevel.FlakyFill -> activity.getString(R.string.oreo_autofill_flaky_fill_support)
BrowserAutofillSupportLevel.PasswordFill -> activity.getString(R.string.oreo_autofill_password_fill_support)
BrowserAutofillSupportLevel.PasswordFillAndSaveIfNoAccessibility -> activity.getString(R.string.oreo_autofill_password_fill_and_conditional_save_support)
BrowserAutofillSupportLevel.GeneralFill -> activity.getString(R.string.oreo_autofill_general_fill_support)
BrowserAutofillSupportLevel.GeneralFillAndSave -> activity.getString(R.string.oreo_autofill_general_fill_and_save_support)
}
"$appLabel: $supportDescription"
}
setView(layout)
setPositiveButton(R.string.dialog_ok) { _, _ ->
val intent = Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE).apply {
data = Uri.parse("package:${BuildConfig.APPLICATION_ID}")
}
activity.startActivity(intent)
}
setNegativeButton(R.string.dialog_cancel, null)
setOnDismissListener { pref.checked = isAutofillServiceEnabled }
activity.lifecycle.addObserver(observer)
show()
}
}
override fun provideSettings(builder: PreferenceScreen.Builder) {
builder.apply {
switch(PreferenceKeys.AUTOFILL_ENABLE) {
titleRes = R.string.pref_autofill_enable_title
visible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
defaultValue = isAutofillServiceEnabled
onClick {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return@onClick true
if (isAutofillServiceEnabled) {
activity.autofillManager?.disableAutofillServices()
} else {
showAutofillDialog(this)
}
false
}
}
val values = activity.resources.getStringArray(R.array.oreo_autofill_directory_structure_values)
val titles = activity.resources.getStringArray(R.array.oreo_autofill_directory_structure_entries)
val items = values.zip(titles).map { SelectionItem(it.first, it.second, null) }
singleChoice(PreferenceKeys.OREO_AUTOFILL_DIRECTORY_STRUCTURE, items) {
initialSelection = DirectoryStructure.DEFAULT.value
dependency = PreferenceKeys.AUTOFILL_ENABLE
titleRes = R.string.oreo_autofill_preference_directory_structure
}
editText(PreferenceKeys.OREO_AUTOFILL_DEFAULT_USERNAME) {
dependency = PreferenceKeys.AUTOFILL_ENABLE
titleRes = R.string.preference_default_username_title
summaryProvider = { activity.getString(R.string.preference_default_username_summary) }
}
editText(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES) {
dependency = PreferenceKeys.AUTOFILL_ENABLE
titleRes = R.string.preference_custom_public_suffixes_title
summaryProvider = { activity.getString(R.string.preference_custom_public_suffixes_summary) }
textInputHintRes = R.string.preference_custom_public_suffixes_hint
}
}
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.provider.DocumentsContract
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.edit
import com.github.ajalt.timberkt.d
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class DirectorySelectionActivity : AppCompatActivity() {
@Suppress("DEPRECATION")
private val directorySelectAction = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri: Uri? ->
if (uri == null) return@registerForActivityResult
d { "Selected repository URI is $uri" }
// TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile
val docId = DocumentsContract.getTreeDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val path = if (split.size > 1) split[1] else split[0]
val repoPath = "${Environment.getExternalStorageDirectory()}/$path"
val prefs = sharedPrefs
d { "Selected repository path is $repoPath" }
if (Environment.getExternalStorageDirectory().path == repoPath) {
MaterialAlertDialogBuilder(this)
.setTitle(resources.getString(R.string.sdcard_root_warning_title))
.setMessage(resources.getString(R.string.sdcard_root_warning_message))
.setPositiveButton(resources.getString(R.string.sdcard_root_warning_remove_everything)) { _, _ ->
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, uri.path) }
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
}
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, repoPath) }
setResult(RESULT_OK)
finish()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
directorySelectAction.launch(null)
}
}

View file

@ -0,0 +1,104 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import de.Maxr1998.modernpreferences.PreferenceScreen
import de.Maxr1998.modernpreferences.helpers.checkBox
import de.Maxr1998.modernpreferences.helpers.onClick
import de.Maxr1998.modernpreferences.helpers.singleChoice
import de.Maxr1998.modernpreferences.preferences.choice.SelectionItem
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.auth.BiometricAuthenticator
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import android.content.pm.ShortcutManager
import android.os.Build
import androidx.core.content.edit
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
class GeneralSettings(private val activity: FragmentActivity) : SettingsProvider {
override fun provideSettings(builder: PreferenceScreen.Builder) {
builder.apply {
val themeValues = activity.resources.getStringArray(R.array.app_theme_values)
val themeOptions = activity.resources.getStringArray(R.array.app_theme_options)
val themeItems = themeValues.zip(themeOptions).map { SelectionItem(it.first, it.second, null) }
singleChoice(PreferenceKeys.APP_THEME, themeItems) {
initialSelection = activity.resources.getString(R.string.app_theme_def)
titleRes = R.string.pref_app_theme_title
}
val sortValues = activity.resources.getStringArray(R.array.sort_order_values)
val sortOptions = activity.resources.getStringArray(R.array.sort_order_entries)
val sortItems = sortValues.zip(sortOptions).map { SelectionItem(it.first, it.second, null) }
singleChoice(PreferenceKeys.SORT_ORDER, sortItems) {
initialSelection = sortValues[0]
titleRes = R.string.pref_sort_order_title
}
checkBox(PreferenceKeys.FILTER_RECURSIVELY) {
titleRes = R.string.pref_recursive_filter_title
summaryRes = R.string.pref_recursive_filter_summary
defaultValue = true
}
checkBox(PreferenceKeys.SEARCH_ON_START) {
titleRes = R.string.pref_search_on_start_title
summaryRes = R.string.pref_search_on_start_summary
defaultValue = false
}
checkBox(PreferenceKeys.SHOW_HIDDEN_CONTENTS) {
titleRes = R.string.pref_show_hidden_title
summaryRes = R.string.pref_show_hidden_summary
defaultValue = false
}
checkBox(PreferenceKeys.BIOMETRIC_AUTH) {
titleRes = R.string.pref_biometric_auth_title
defaultValue = false
}.apply {
val canAuthenticate = BiometricAuthenticator.canAuthenticate(activity)
if (!canAuthenticate) {
enabled = false
checked = false
summaryRes = R.string.pref_biometric_auth_summary_error
} else {
summaryRes = R.string.pref_biometric_auth_summary
onClick {
enabled = false
val isChecked = checked
activity.sharedPrefs.edit {
BiometricAuthenticator.authenticate(activity) { result ->
when (result) {
is BiometricAuthenticator.Result.Success -> {
// Apply the changes
putBoolean(PreferenceKeys.BIOMETRIC_AUTH, checked)
enabled = true
}
else -> {
// If any error occurs, revert back to the previous state. This
// catch-all clause includes the cancellation case.
putBoolean(PreferenceKeys.BIOMETRIC_AUTH, !checked)
checked = !isChecked
enabled = true
}
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
activity.getSystemService<ShortcutManager>()?.apply {
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
}
}
false
}
}
}
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import de.Maxr1998.modernpreferences.PreferenceScreen
import de.Maxr1998.modernpreferences.helpers.checkBox
import de.Maxr1998.modernpreferences.helpers.onClick
import de.Maxr1998.modernpreferences.helpers.pref
import dev.msfjarvis.aps.BuildConfig
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.services.PasswordExportService
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.FragmentActivity
class MiscSettings(activity: FragmentActivity) : SettingsProvider {
private val storeExportAction = activity.registerForActivityResult(object : ActivityResultContracts.OpenDocumentTree() {
override fun createIntent(context: Context, input: Uri?): Intent {
return super.createIntent(context, input).apply {
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
}
}
}) { uri: Uri? ->
if (uri == null) return@registerForActivityResult
val targetDirectory = DocumentFile.fromTreeUri(activity.applicationContext, uri)
if (targetDirectory != null) {
val service = Intent(activity.applicationContext, PasswordExportService::class.java).apply {
action = PasswordExportService.ACTION_EXPORT_PASSWORD
putExtra("uri", uri)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
activity.startForegroundService(service)
} else {
activity.startService(service)
}
}
}
override fun provideSettings(builder: PreferenceScreen.Builder) {
builder.apply {
pref(PreferenceKeys.EXPORT_PASSWORDS) {
titleRes = R.string.prefs_export_passwords_title
summaryRes = R.string.prefs_export_passwords_summary
onClick {
storeExportAction.launch(null)
true
}
}
checkBox(PreferenceKeys.CLEAR_CLIPBOARD_20X) {
defaultValue = false
titleRes = R.string.pref_clear_clipboard_title
summaryRes = R.string.pref_clear_clipboard_summary
}
checkBox(PreferenceKeys.ENABLE_DEBUG_LOGGING) {
defaultValue = false
titleRes = R.string.pref_debug_logging_title
summaryRes = R.string.pref_debug_logging_summary
visible = !BuildConfig.DEBUG
}
}
}
}

View file

@ -0,0 +1,119 @@
/*
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import de.Maxr1998.modernpreferences.Preference
import de.Maxr1998.modernpreferences.PreferenceScreen
import de.Maxr1998.modernpreferences.helpers.categoryHeader
import de.Maxr1998.modernpreferences.helpers.checkBox
import de.Maxr1998.modernpreferences.helpers.editText
import de.Maxr1998.modernpreferences.helpers.onCheckedChange
import de.Maxr1998.modernpreferences.helpers.onClick
import de.Maxr1998.modernpreferences.helpers.onSelectionChange
import de.Maxr1998.modernpreferences.helpers.singleChoice
import de.Maxr1998.modernpreferences.preferences.CheckBoxPreference
import de.Maxr1998.modernpreferences.preferences.choice.SelectionItem
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.pwgenxkpwd.XkpwdDictionary
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import android.text.InputType
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.edit
import androidx.fragment.app.FragmentActivity
import java.io.File
class PasswordSettings(private val activity: FragmentActivity) : SettingsProvider {
private val sharedPrefs by lazy(LazyThreadSafetyMode.NONE) { activity.sharedPrefs }
private val storeCustomXkpwdDictionaryAction = activity.registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
if (uri == null) return@registerForActivityResult
Toast.makeText(
activity,
activity.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
Toast.LENGTH_SHORT
).show()
sharedPrefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
val inputStream = activity.contentResolver.openInputStream(uri)
val customDictFile = File(activity.filesDir.toString(), XkpwdDictionary.XKPWD_CUSTOM_DICT_FILE).outputStream()
inputStream?.copyTo(customDictFile, 1024)
inputStream?.close()
customDictFile.close()
}
override fun provideSettings(builder: PreferenceScreen.Builder) {
builder.apply {
val customDictPref = CheckBoxPreference(PreferenceKeys.PREF_KEY_IS_CUSTOM_DICT).apply {
titleRes = R.string.pref_xkpwgen_custom_wordlist_enabled_title
summaryRes = R.string.pref_xkpwgen_custom_dict_summary_off
summaryOnRes = R.string.pref_xkpwgen_custom_dict_summary_on
visible = sharedPrefs.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) == "xkpasswd"
onCheckedChange {
requestRebind()
true
}
}
val customDictPathPref = Preference(PreferenceKeys.PREF_KEY_CUSTOM_DICT).apply {
dependency = PreferenceKeys.PREF_KEY_IS_CUSTOM_DICT
titleRes = R.string.pref_xkpwgen_custom_dict_picker_title
summary = sharedPrefs.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
?: activity.resources.getString(R.string.pref_xkpwgen_custom_dict_picker_summary)
visible = sharedPrefs.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) == "xkpasswd"
onClick {
storeCustomXkpwdDictionaryAction.launch(arrayOf("*/*"))
true
}
}
val values = activity.resources.getStringArray(R.array.pwgen_provider_values)
val labels = activity.resources.getStringArray(R.array.pwgen_provider_labels)
val items = values.zip(labels).map { SelectionItem(it.first, it.second, null) }
singleChoice(
PreferenceKeys.PREF_KEY_PWGEN_TYPE,
items,
) {
initialSelection = "classic"
titleRes = R.string.pref_password_generator_type_title
onSelectionChange { selection ->
val xkpasswdEnabled = selection == "xkpasswd"
customDictPathPref.visible = xkpasswdEnabled
customDictPref.visible = xkpasswdEnabled
customDictPref.requestRebind()
customDictPathPref.requestRebind()
true
}
}
// We initialize them early and add them manually to be able to manually force a rebind
// when the password generator type is changed.
addPreferenceItem(customDictPref)
addPreferenceItem(customDictPathPref)
editText(PreferenceKeys.GENERAL_SHOW_TIME) {
titleRes = R.string.pref_clipboard_timeout_title
summaryProvider = { activity.getString(R.string.pref_clipboard_timeout_summary) }
textInputType = InputType.TYPE_CLASS_NUMBER
}
checkBox(PreferenceKeys.SHOW_PASSWORD) {
titleRes = R.string.show_password_pref_title
summaryRes = R.string.show_password_pref_summary
defaultValue = true
}
checkBox(PreferenceKeys.SHOW_EXTRA_CONTENT) {
titleRes = R.string.show_extra_content_pref_title
summaryRes = R.string.show_extra_content_pref_summary
defaultValue = true
}
checkBox(PreferenceKeys.COPY_ON_DECRYPT) {
titleRes = R.string.pref_copy_title
summaryRes = R.string.pref_copy_summary
defaultValue = false
}
}
}
}

View file

@ -0,0 +1,198 @@
/*
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import de.Maxr1998.modernpreferences.Preference
import de.Maxr1998.modernpreferences.PreferenceScreen
import de.Maxr1998.modernpreferences.helpers.checkBox
import de.Maxr1998.modernpreferences.helpers.onCheckedChange
import de.Maxr1998.modernpreferences.helpers.onClick
import de.Maxr1998.modernpreferences.helpers.pref
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.ui.git.config.GitConfigActivity
import dev.msfjarvis.aps.ui.git.config.GitServerConfigActivity
import dev.msfjarvis.aps.ui.proxy.ProxySelectorActivity
import dev.msfjarvis.aps.ui.sshkeygen.ShowSshKeyFragment
import dev.msfjarvis.aps.ui.sshkeygen.SshKeyGenActivity
import dev.msfjarvis.aps.ui.sshkeygen.SshKeyImportActivity
import dev.msfjarvis.aps.util.extensions.getEncryptedGitPrefs
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.extensions.snackbar
import dev.msfjarvis.aps.util.settings.GitSettings
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import android.content.Intent
import android.content.pm.ShortcutManager
import android.os.Build
import androidx.core.content.edit
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class RepositorySettings(private val activity: FragmentActivity) : SettingsProvider {
private val encryptedPreferences by lazy(LazyThreadSafetyMode.NONE) { activity.getEncryptedGitPrefs() }
private fun <T : FragmentActivity> launchActivity(clazz: Class<T>) {
activity.startActivity(Intent(activity, clazz))
}
private fun selectExternalGitRepository() {
MaterialAlertDialogBuilder(activity)
.setTitle(activity.resources.getString(R.string.external_repository_dialog_title))
.setMessage(activity.resources.getString(R.string.external_repository_dialog_text))
.setPositiveButton(R.string.dialog_ok) { _, _ ->
launchActivity(DirectorySelectionActivity::class.java)
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
}
override fun provideSettings(builder: PreferenceScreen.Builder) {
builder.apply {
pref(PreferenceKeys.GIT_SERVER_INFO) {
titleRes = R.string.pref_edit_git_server_settings
visible = PasswordRepository.isGitRepo()
onClick {
launchActivity(GitServerConfigActivity::class.java)
true
}
}
pref(PreferenceKeys.PROXY_SETTINGS) {
titleRes = R.string.pref_edit_proxy_settings
visible = GitSettings.url?.startsWith("https") == true && PasswordRepository.isGitRepo()
onClick {
launchActivity(ProxySelectorActivity::class.java)
true
}
}
pref(PreferenceKeys.GIT_CONFIG) {
titleRes = R.string.pref_edit_git_config
visible = PasswordRepository.isGitRepo()
onClick {
launchActivity(GitConfigActivity::class.java)
true
}
}
pref(PreferenceKeys.SSH_KEY) {
titleRes = R.string.pref_import_ssh_key_title
visible = PasswordRepository.isGitRepo()
onClick {
launchActivity(SshKeyImportActivity::class.java)
true
}
}
pref(PreferenceKeys.SSH_KEYGEN) {
titleRes = R.string.pref_ssh_keygen_title
onClick {
launchActivity(SshKeyGenActivity::class.java)
true
}
}
pref(PreferenceKeys.SSH_SEE_KEY) {
titleRes = R.string.pref_ssh_see_key_title
visible = PasswordRepository.isGitRepo()
onClick {
ShowSshKeyFragment().show(activity.supportFragmentManager, "public_key")
true
}
}
pref(PreferenceKeys.CLEAR_SAVED_PASS) {
fun Preference.updatePref() {
val sshPass = encryptedPreferences.getString(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE)
val httpsPass = encryptedPreferences.getString(PreferenceKeys.HTTPS_PASSWORD)
if (sshPass == null && httpsPass == null) {
visible = false
return
}
when {
httpsPass != null -> titleRes = R.string.clear_saved_passphrase_https
sshPass != null -> titleRes = R.string.clear_saved_passphrase_ssh
}
visible = true
requestRebind()
}
onClick {
updatePref()
true
}
updatePref()
}
pref(PreferenceKeys.SSH_OPENKEYSTORE_CLEAR_KEY_ID) {
titleRes = R.string.pref_title_openkeystore_clear_keyid
visible = activity.sharedPrefs.getString(PreferenceKeys.SSH_OPENKEYSTORE_KEYID)?.isNotEmpty()
?: false
onClick {
activity.sharedPrefs.edit { putString(PreferenceKeys.SSH_OPENKEYSTORE_KEYID, null) }
visible = false
true
}
}
val deleteRepoPref = pref(PreferenceKeys.GIT_DELETE_REPO) {
titleRes = R.string.pref_git_delete_repo_title
summaryRes = R.string.pref_git_delete_repo_summary
visible = !activity.sharedPrefs.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)
onClick {
val repoDir = PasswordRepository.getRepositoryDirectory()
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.pref_dialog_delete_title)
.setMessage(activity.getString(R.string.dialog_delete_msg, repoDir))
.setCancelable(false)
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
runCatching {
PasswordRepository.getRepositoryDirectory().deleteRecursively()
PasswordRepository.closeRepository()
}.onFailure {
it.message?.let { message ->
activity.snackbar(message = message)
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
activity.getSystemService<ShortcutManager>()?.apply {
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
}
}
activity.sharedPrefs.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) }
dialogInterface.cancel()
activity.finish()
}
.setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
.show()
true
}
}
checkBox(PreferenceKeys.GIT_EXTERNAL) {
titleRes = R.string.pref_external_repository_title
summaryRes = R.string.pref_external_repository_summary
onCheckedChange { checked ->
deleteRepoPref.visible = !checked
deleteRepoPref.requestRebind()
PasswordRepository.closeRepository()
activity.sharedPrefs.edit { putBoolean(PreferenceKeys.REPO_CHANGED, true) }
true
}
}
pref(PreferenceKeys.GIT_EXTERNAL_REPO) {
val externalRepo = activity.sharedPrefs.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
if (externalRepo != null) {
summary = externalRepo
} else {
summaryRes = R.string.pref_select_external_repository_summary_no_repo_selected
}
titleRes = R.string.pref_select_external_repository_title
dependency = PreferenceKeys.GIT_EXTERNAL
onClick {
selectExternalGitRepository()
true
}
}
}
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import de.Maxr1998.modernpreferences.PreferencesAdapter
import de.Maxr1998.modernpreferences.helpers.screen
import de.Maxr1998.modernpreferences.helpers.subScreen
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.databinding.ActivityPreferenceRecyclerviewBinding
import dev.msfjarvis.aps.util.extensions.viewBinding
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
class SettingsActivity : AppCompatActivity() {
private val miscSettings = MiscSettings(this)
private val autofillSettings = AutofillSettings(this)
private val passwordSettings = PasswordSettings(this)
private val repositorySettings = RepositorySettings(this)
private val generalSettings = GeneralSettings(this)
private val binding by viewBinding(ActivityPreferenceRecyclerviewBinding::inflate)
private val preferencesAdapter: PreferencesAdapter
get() = binding.preferenceRecyclerView.adapter as PreferencesAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val screen = screen(this) {
subScreen {
titleRes = R.string.pref_category_general_title
iconRes = R.drawable.app_settings_alt_24px
generalSettings.provideSettings(this)
}
subScreen {
titleRes = R.string.pref_category_autofill_title
iconRes = R.drawable.ic_wysiwyg_24px
autofillSettings.provideSettings(this)
}
subScreen {
titleRes = R.string.pref_category_passwords_title
iconRes = R.drawable.ic_lock_open_24px
passwordSettings.provideSettings(this)
}
subScreen {
titleRes = R.string.pref_category_repository_title
iconRes = R.drawable.ic_call_merge_24px
repositorySettings.provideSettings(this)
}
subScreen {
titleRes = R.string.pref_category_misc_title
iconRes = R.drawable.ic_miscellaneous_services_24px
miscSettings.provideSettings(this)
}
}
val adapter = PreferencesAdapter(screen)
adapter.onScreenChangeListener = PreferencesAdapter.OnScreenChangeListener { subScreen, entering ->
supportActionBar?.title = if (!entering) {
getString(R.string.action_settings)
} else {
getString(subScreen.titleRes)
}
}
savedInstanceState?.getParcelable<PreferencesAdapter.SavedState>("adapter")
?.let(adapter::loadSavedState)
binding.preferenceRecyclerView.adapter = adapter
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelable("adapter", preferencesAdapter.getSavedState())
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> if (!preferencesAdapter.goBack()) {
super.onOptionsItemSelected(item)
} else {
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onBackPressed() {
if (!preferencesAdapter.goBack())
super.onBackPressed()
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import de.Maxr1998.modernpreferences.PreferenceScreen
/**
* Used to generate a uniform API for all settings UI classes.
*/
interface SettingsProvider {
/**
* Inserts the settings items for the class into the given [builder].
*/
fun provideSettings(builder: PreferenceScreen.Builder)
}

View file

@ -1,674 +0,0 @@
/*
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.settings
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.ShortcutManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.Settings
import android.text.TextUtils
import android.view.MenuItem
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts.OpenDocument
import androidx.activity.result.contract.ActivityResultContracts.OpenDocumentTree
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.edit
import androidx.core.content.getSystemService
import androidx.documentfile.provider.DocumentFile
import androidx.preference.CheckBoxPreference
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import com.github.ajalt.timberkt.Timber.tag
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.w
import com.github.androidpasswordstore.autofillparser.BrowserAutofillSupportLevel
import com.github.androidpasswordstore.autofillparser.getInstalledBrowsersWithAutofillSupportLevel
import com.github.michaelbull.result.getOr
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dev.msfjarvis.aps.BuildConfig
import dev.msfjarvis.aps.util.services.PasswordExportService
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.ui.crypto.BasePgpActivity
import dev.msfjarvis.aps.ui.git.config.GitConfigActivity
import dev.msfjarvis.aps.ui.git.config.GitServerConfigActivity
import dev.msfjarvis.aps.util.git.sshj.SshKey
import dev.msfjarvis.aps.util.pwgenxkpwd.XkpwdDictionary
import dev.msfjarvis.aps.ui.sshkeygen.ShowSshKeyFragment
import dev.msfjarvis.aps.ui.sshkeygen.SshKeyGenActivity
import dev.msfjarvis.aps.ui.proxy.ProxySelectorActivity
import dev.msfjarvis.aps.util.auth.BiometricAuthenticator
import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import dev.msfjarvis.aps.util.extensions.autofillManager
import dev.msfjarvis.aps.util.extensions.getEncryptedGitPrefs
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import java.io.File
typealias ClickListener = Preference.OnPreferenceClickListener
typealias ChangeListener = Preference.OnPreferenceChangeListener
class UserPreference : AppCompatActivity() {
private lateinit var prefsFragment: PrefsFragment
private var fromIntent = false
@Suppress("DEPRECATION")
private val directorySelectAction = registerForActivityResult(OpenDocumentTree()) { uri: Uri? ->
if (uri == null) return@registerForActivityResult
tag(TAG).d { "Selected repository URI is $uri" }
// TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile
val docId = DocumentsContract.getTreeDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val path = if (split.size > 1) split[1] else split[0]
val repoPath = "${Environment.getExternalStorageDirectory()}/$path"
val prefs = sharedPrefs
tag(TAG).d { "Selected repository path is $repoPath" }
if (Environment.getExternalStorageDirectory().path == repoPath) {
MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.sdcard_root_warning_title))
.setMessage(getString(R.string.sdcard_root_warning_message))
.setPositiveButton("Remove everything") { _, _ ->
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, uri.path) }
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
}
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, repoPath) }
if (fromIntent) {
setResult(RESULT_OK)
finish()
}
}
private val sshKeyImportAction = registerForActivityResult(OpenDocument()) { uri: Uri? ->
if (uri == null) return@registerForActivityResult
runCatching {
SshKey.import(uri)
Toast.makeText(this, resources.getString(R.string.ssh_key_success_dialog_title), Toast.LENGTH_LONG).show()
setResult(RESULT_OK)
finish()
}.onFailure { e ->
MaterialAlertDialogBuilder(this)
.setTitle(resources.getString(R.string.ssh_key_error_dialog_title))
.setMessage(e.message)
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
.show()
}
}
private val storeExportAction = registerForActivityResult(object : OpenDocumentTree() {
override fun createIntent(context: Context, input: Uri?): Intent {
return super.createIntent(context, input).apply {
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
}
}
}) { uri: Uri? ->
if (uri == null) return@registerForActivityResult
val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
if (targetDirectory != null) {
val service = Intent(applicationContext, PasswordExportService::class.java).apply {
action = PasswordExportService.ACTION_EXPORT_PASSWORD
putExtra("uri", uri)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(service)
} else {
startService(service)
}
}
}
private val storeCustomXkpwdDictionaryAction = registerForActivityResult(OpenDocument()) { uri ->
if (uri == null) return@registerForActivityResult
Toast.makeText(
this,
this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
Toast.LENGTH_SHORT
).show()
sharedPrefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
val customDictPref = prefsFragment.findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
setCustomDictSummary(customDictPref, uri)
// copy user selected file to internal storage
val inputStream = contentResolver.openInputStream(uri)
val customDictFile = File(filesDir.toString(), XkpwdDictionary.XKPWD_CUSTOM_DICT_FILE).outputStream()
inputStream?.copyTo(customDictFile, 1024)
inputStream?.close()
customDictFile.close()
setResult(RESULT_OK)
}
class PrefsFragment : PreferenceFragmentCompat() {
private var autoFillEnablePreference: SwitchPreferenceCompat? = null
private var clearSavedPassPreference: Preference? = null
private var viewSshKeyPreference: Preference? = null
private lateinit var oreoAutofillDependencies: List<Preference>
private lateinit var prefsActivity: UserPreference
private lateinit var sharedPreferences: SharedPreferences
private lateinit var encryptedPreferences: SharedPreferences
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
prefsActivity = requireActivity() as UserPreference
val context = requireContext()
sharedPreferences = preferenceManager.sharedPreferences
encryptedPreferences = requireActivity().getEncryptedGitPrefs()
addPreferencesFromResource(R.xml.preference)
// Git preferences
val gitServerPreference = findPreference<Preference>(PreferenceKeys.GIT_SERVER_INFO)
val openkeystoreIdPreference = findPreference<Preference>(PreferenceKeys.SSH_OPENKEYSTORE_CLEAR_KEY_ID)
val gitConfigPreference = findPreference<Preference>(PreferenceKeys.GIT_CONFIG)
val sshKeyPreference = findPreference<Preference>(PreferenceKeys.SSH_KEY)
val sshKeygenPreference = findPreference<Preference>(PreferenceKeys.SSH_KEYGEN)
viewSshKeyPreference = findPreference(PreferenceKeys.SSH_SEE_KEY)
clearSavedPassPreference = findPreference(PreferenceKeys.CLEAR_SAVED_PASS)
val deleteRepoPreference = findPreference<Preference>(PreferenceKeys.GIT_DELETE_REPO)
val externalGitRepositoryPreference = findPreference<Preference>(PreferenceKeys.GIT_EXTERNAL)
val selectExternalGitRepositoryPreference = findPreference<Preference>(PreferenceKeys.PREF_SELECT_EXTERNAL)
if (!PasswordRepository.isGitRepo()) {
listOfNotNull(
gitServerPreference,
gitConfigPreference,
sshKeyPreference,
viewSshKeyPreference,
clearSavedPassPreference,
).forEach {
it.parent?.removePreference(it)
}
}
// General preferences
val showTimePreference = findPreference<Preference>(PreferenceKeys.GENERAL_SHOW_TIME)
val clearClipboard20xPreference = findPreference<CheckBoxPreference>(PreferenceKeys.CLEAR_CLIPBOARD_20X)
// Autofill preferences
autoFillEnablePreference = findPreference(PreferenceKeys.AUTOFILL_ENABLE)
val oreoAutofillDirectoryStructurePreference = findPreference<ListPreference>(PreferenceKeys.OREO_AUTOFILL_DIRECTORY_STRUCTURE)
val oreoAutofillDefaultUsername = findPreference<EditTextPreference>(PreferenceKeys.OREO_AUTOFILL_DEFAULT_USERNAME)
val oreoAutofillCustomPublixSuffixes = findPreference<EditTextPreference>(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES)
oreoAutofillDependencies = listOfNotNull(
oreoAutofillDirectoryStructurePreference,
oreoAutofillDefaultUsername,
oreoAutofillCustomPublixSuffixes,
)
oreoAutofillCustomPublixSuffixes?.apply {
setOnBindEditTextListener {
it.isSingleLine = false
it.setHint(R.string.preference_custom_public_suffixes_hint)
}
}
// Misc preferences
val appVersionPreference = findPreference<Preference>(PreferenceKeys.APP_VERSION)
selectExternalGitRepositoryPreference?.summary = sharedPreferences.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
?: getString(R.string.no_repo_selected)
deleteRepoPreference?.isVisible = !sharedPreferences.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)
clearClipboard20xPreference?.isVisible = sharedPreferences.getString(PreferenceKeys.GENERAL_SHOW_TIME)?.toInt() != 0
openkeystoreIdPreference?.isVisible = sharedPreferences.getString(PreferenceKeys.SSH_OPENKEYSTORE_KEYID)?.isNotEmpty()
?: false
updateAutofillSettings()
updateClearSavedPassphrasePrefs()
appVersionPreference?.summary = "Version: ${BuildConfig.VERSION_NAME}"
sshKeyPreference?.onPreferenceClickListener = ClickListener {
prefsActivity.getSshKey()
true
}
sshKeygenPreference?.onPreferenceClickListener = ClickListener {
prefsActivity.makeSshKey(true)
true
}
viewSshKeyPreference?.onPreferenceClickListener = ClickListener {
val df = ShowSshKeyFragment()
df.show(parentFragmentManager, "public_key")
true
}
clearSavedPassPreference?.onPreferenceClickListener = ClickListener {
encryptedPreferences.edit {
if (encryptedPreferences.getString(PreferenceKeys.HTTPS_PASSWORD) != null)
remove(PreferenceKeys.HTTPS_PASSWORD)
else if (encryptedPreferences.getString(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE) != null)
remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE)
}
updateClearSavedPassphrasePrefs()
true
}
openkeystoreIdPreference?.onPreferenceClickListener = ClickListener {
sharedPreferences.edit { putString(PreferenceKeys.SSH_OPENKEYSTORE_KEYID, null) }
it.isVisible = false
true
}
gitServerPreference?.onPreferenceClickListener = ClickListener {
startActivity(Intent(prefsActivity, GitServerConfigActivity::class.java))
true
}
gitConfigPreference?.onPreferenceClickListener = ClickListener {
startActivity(Intent(prefsActivity, GitConfigActivity::class.java))
true
}
deleteRepoPreference?.onPreferenceClickListener = ClickListener {
val repoDir = PasswordRepository.getRepositoryDirectory()
MaterialAlertDialogBuilder(prefsActivity)
.setTitle(R.string.pref_dialog_delete_title)
.setMessage(resources.getString(R.string.dialog_delete_msg, repoDir))
.setCancelable(false)
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
runCatching {
PasswordRepository.getRepositoryDirectory().deleteRecursively()
PasswordRepository.closeRepository()
}.onFailure {
// TODO Handle the different cases of exceptions
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
requireContext().getSystemService<ShortcutManager>()?.apply {
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
}
}
sharedPreferences.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) }
dialogInterface.cancel()
prefsActivity.finish()
}
.setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
.show()
true
}
selectExternalGitRepositoryPreference?.summary =
sharedPreferences.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
?: context.getString(R.string.no_repo_selected)
selectExternalGitRepositoryPreference?.onPreferenceClickListener = ClickListener {
prefsActivity.selectExternalGitRepository()
true
}
val resetRepo = Preference.OnPreferenceChangeListener { _, o ->
deleteRepoPreference?.isVisible = !(o as Boolean)
PasswordRepository.closeRepository()
sharedPreferences.edit { putBoolean(PreferenceKeys.REPO_CHANGED, true) }
true
}
selectExternalGitRepositoryPreference?.onPreferenceChangeListener = resetRepo
externalGitRepositoryPreference?.onPreferenceChangeListener = resetRepo
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
autoFillEnablePreference?.onPreferenceClickListener = ClickListener {
onEnableAutofillClick()
true
}
}
findPreference<Preference>(PreferenceKeys.EXPORT_PASSWORDS)?.apply {
isVisible = sharedPreferences.getBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)
onPreferenceClickListener = Preference.OnPreferenceClickListener {
prefsActivity.exportPasswords()
true
}
}
showTimePreference?.onPreferenceChangeListener = ChangeListener { _, newValue: Any? ->
runCatching {
val isEnabled = newValue.toString().toInt() != 0
clearClipboard20xPreference?.isVisible = isEnabled
true
}.getOr(false)
}
showTimePreference?.summaryProvider = Preference.SummaryProvider<Preference> {
getString(R.string.pref_clipboard_timeout_summary, sharedPreferences.getString
(PreferenceKeys.GENERAL_SHOW_TIME, "45"))
}
findPreference<CheckBoxPreference>(PreferenceKeys.ENABLE_DEBUG_LOGGING)?.isVisible = !BuildConfig.ENABLE_DEBUG_FEATURES
findPreference<CheckBoxPreference>(PreferenceKeys.BIOMETRIC_AUTH)?.apply {
val canAuthenticate = BiometricAuthenticator.canAuthenticate(prefsActivity)
if (!canAuthenticate) {
isEnabled = false
isChecked = false
summary = getString(R.string.biometric_auth_summary_error)
} else {
setOnPreferenceClickListener {
isEnabled = false
sharedPreferences.edit {
val checked = isChecked
BiometricAuthenticator.authenticate(requireActivity()) { result ->
when (result) {
is BiometricAuthenticator.Result.Success -> {
// Apply the changes
putBoolean(PreferenceKeys.BIOMETRIC_AUTH, checked)
isEnabled = true
}
else -> {
// If any error occurs, revert back to the previous state. This
// catch-all clause includes the cancellation case.
putBoolean(PreferenceKeys.BIOMETRIC_AUTH, !checked)
isChecked = !checked
isEnabled = true
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
requireContext().getSystemService<ShortcutManager>()?.apply {
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
}
}
}
true
}
}
}
findPreference<Preference>(PreferenceKeys.PROXY_SETTINGS)?.onPreferenceClickListener = ClickListener {
startActivity(Intent(requireContext(), ProxySelectorActivity::class.java))
true
}
val prefCustomXkpwdDictionary = findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
prefCustomXkpwdDictionary?.onPreferenceClickListener = ClickListener {
prefsActivity.storeCustomDictionaryPath()
true
}
val dictUri = sharedPreferences.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT) ?: ""
if (!TextUtils.isEmpty(dictUri)) {
setCustomDictSummary(prefCustomXkpwdDictionary, Uri.parse(dictUri))
}
val prefIsCustomDict = findPreference<CheckBoxPreference>(PreferenceKeys.PREF_KEY_IS_CUSTOM_DICT)
val prefCustomDictPicker = findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
val prefPwgenType = findPreference<ListPreference>(PreferenceKeys.PREF_KEY_PWGEN_TYPE)
updateXkPasswdPrefsVisibility(prefPwgenType?.value, prefIsCustomDict, prefCustomDictPicker)
prefPwgenType?.onPreferenceChangeListener = ChangeListener { _, newValue ->
updateXkPasswdPrefsVisibility(newValue, prefIsCustomDict, prefCustomDictPicker)
true
}
prefIsCustomDict?.onPreferenceChangeListener = ChangeListener { _, newValue ->
if (!(newValue as Boolean)) {
val customDictFile = File(context.filesDir, XkpwdDictionary.XKPWD_CUSTOM_DICT_FILE)
if (customDictFile.exists() && !customDictFile.delete()) {
w { "Failed to delete custom XkPassword dictionary: $customDictFile" }
}
prefCustomDictPicker?.setSummary(R.string.xkpwgen_pref_custom_dict_picker_summary)
}
true
}
}
private fun updateXkPasswdPrefsVisibility(newValue: Any?, prefIsCustomDict: CheckBoxPreference?, prefCustomDictPicker: Preference?) {
when (newValue as String) {
BasePgpActivity.KEY_PWGEN_TYPE_CLASSIC -> {
prefIsCustomDict?.isVisible = false
prefCustomDictPicker?.isVisible = false
}
BasePgpActivity.KEY_PWGEN_TYPE_XKPASSWD -> {
prefIsCustomDict?.isVisible = true
prefCustomDictPicker?.isVisible = true
}
}
}
private fun updateAutofillSettings() {
val isAutofillServiceEnabled = prefsActivity.isAutofillServiceEnabled
val isAutofillSupported = prefsActivity.isAutofillServiceSupported
if (!isAutofillSupported) {
autoFillEnablePreference?.isVisible = false
} else {
autoFillEnablePreference?.isChecked = isAutofillServiceEnabled
}
oreoAutofillDependencies.forEach {
it.isVisible = isAutofillServiceEnabled
}
}
private fun updateClearSavedPassphrasePrefs() {
clearSavedPassPreference?.apply {
val sshPass = encryptedPreferences.getString(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE)
val httpsPass = encryptedPreferences.getString(PreferenceKeys.HTTPS_PASSWORD)
if (sshPass == null && httpsPass == null) {
isVisible = false
return@apply
}
title = when {
httpsPass != null -> getString(R.string.clear_saved_passphrase_https)
sshPass != null -> getString(R.string.clear_saved_passphrase_ssh)
else -> null
}
isVisible = true
}
}
private fun updateViewSshPubkeyPref() {
viewSshKeyPreference?.isVisible = SshKey.canShowSshPublicKey
}
@RequiresApi(Build.VERSION_CODES.O)
private fun onEnableAutofillClick() {
if (prefsActivity.isAutofillServiceEnabled) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
prefsActivity.autofillManager!!.disableAutofillServices()
else
throw IllegalStateException("isAutofillServiceEnabled == true, but Build.VERSION.SDK_INT < Build.VERSION_CODES.O")
} else {
MaterialAlertDialogBuilder(prefsActivity).run {
setTitle(R.string.pref_autofill_enable_title)
@SuppressLint("InflateParams")
val layout =
layoutInflater.inflate(R.layout.oreo_autofill_instructions, null)
val supportedBrowsersTextView =
layout.findViewById<AppCompatTextView>(R.id.supportedBrowsers)
supportedBrowsersTextView.text =
getInstalledBrowsersWithAutofillSupportLevel(context).joinToString(
separator = "\n"
) {
val appLabel = it.first
val supportDescription = when (it.second) {
BrowserAutofillSupportLevel.None -> getString(R.string.oreo_autofill_no_support)
BrowserAutofillSupportLevel.FlakyFill -> getString(R.string.oreo_autofill_flaky_fill_support)
BrowserAutofillSupportLevel.PasswordFill -> getString(R.string.oreo_autofill_password_fill_support)
BrowserAutofillSupportLevel.PasswordFillAndSaveIfNoAccessibility -> getString(R.string.oreo_autofill_password_fill_and_conditional_save_support)
BrowserAutofillSupportLevel.GeneralFill -> getString(R.string.oreo_autofill_general_fill_support)
BrowserAutofillSupportLevel.GeneralFillAndSave -> getString(R.string.oreo_autofill_general_fill_and_save_support)
}
"$appLabel: $supportDescription"
}
setView(layout)
setPositiveButton(R.string.dialog_ok) { _, _ ->
val intent = Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE).apply {
data = Uri.parse("package:${BuildConfig.APPLICATION_ID}")
}
startActivity(intent)
}
setNegativeButton(R.string.dialog_cancel, null)
setOnDismissListener { updateAutofillSettings() }
show()
}
}
}
override fun onResume() {
super.onResume()
updateAutofillSettings()
updateClearSavedPassphrasePrefs()
updateViewSshPubkeyPref()
}
}
override fun onBackPressed() {
super.onBackPressed()
setResult(RESULT_OK)
finish()
}
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
when (intent?.getStringExtra("operation")) {
"get_ssh_key" -> getSshKey()
"make_ssh_key" -> makeSshKey(false)
"git_external" -> {
fromIntent = true
selectExternalGitRepository()
}
}
prefsFragment = PrefsFragment()
supportFragmentManager
.beginTransaction()
.replace(android.R.id.content, prefsFragment)
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
@Suppress("Deprecation") // for Environment.getExternalStorageDirectory()
fun selectExternalGitRepository() {
MaterialAlertDialogBuilder(this)
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
.setPositiveButton(R.string.dialog_ok) { _, _ ->
directorySelectAction.launch(null)
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
setResult(RESULT_OK)
onBackPressed()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun importSshKey() {
sshKeyImportAction.launch(arrayOf("*/*"))
}
/**
* Opens a file explorer to import the private key
*/
private fun getSshKey() {
if (SshKey.exists) {
MaterialAlertDialogBuilder(this).run {
setTitle(R.string.ssh_keygen_existing_title)
setMessage(R.string.ssh_keygen_existing_message)
setPositiveButton(R.string.ssh_keygen_existing_replace) { _, _ ->
importSshKey()
}
setNegativeButton(R.string.ssh_keygen_existing_keep) { _, _ -> }
show()
}
} else {
importSshKey()
}
}
/**
* Exports the passwords
*/
private fun exportPasswords() {
storeExportAction.launch(null)
}
/**
* Opens a key generator to generate a public/private key pair
*/
fun makeSshKey(fromPreferences: Boolean) {
val intent = Intent(applicationContext, SshKeyGenActivity::class.java)
startActivity(intent)
if (!fromPreferences) {
setResult(RESULT_OK)
finish()
}
}
/**
* Pick custom xkpwd dictionary from sdcard
*/
private fun storeCustomDictionaryPath() {
storeCustomXkpwdDictionaryAction.launch(arrayOf("*/*"))
}
private val isAutofillServiceSupported: Boolean
get() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false
return autofillManager?.isAutofillSupported != null
}
private val isAutofillServiceEnabled: Boolean
get() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false
return autofillManager?.hasEnabledAutofillServices() == true
}
companion object {
private const val TAG = "UserPreference"
fun createDirectorySelectionIntent(context: Context): Intent {
return Intent(context, UserPreference::class.java).run {
putExtra("operation", "git_external")
}
}
/**
* Set custom dictionary summary
*/
@JvmStatic
private fun setCustomDictSummary(customDictPref: Preference?, uri: Uri) {
val fileName = uri.path?.substring(uri.path?.lastIndexOf(":")!! + 1)
customDictPref?.summary = "Selected dictionary: $fileName"
}
}
}

View file

@ -144,6 +144,7 @@ class SshKeyGenActivity : AppCompatActivity() {
.setTitle(getString(R.string.error_generate_ssh_key))
.setMessage(getString(R.string.ssh_key_error_dialog_text) + e.message)
.setPositiveButton(getString(R.string.dialog_ok)) { _, _ ->
setResult(RESULT_OK)
finish()
}
.show()

View file

@ -0,0 +1,61 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.sshkeygen
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.git.sshj.SshKey
import android.net.Uri
import android.os.Bundle
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class SshKeyImportActivity : AppCompatActivity() {
private val sshKeyImportAction = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? ->
if (uri == null) {
finish()
return@registerForActivityResult
}
runCatching {
SshKey.import(uri)
Toast.makeText(this, resources.getString(R.string.ssh_key_success_dialog_title), Toast.LENGTH_LONG).show()
setResult(RESULT_OK)
finish()
}.onFailure { e ->
MaterialAlertDialogBuilder(this)
.setTitle(resources.getString(R.string.ssh_key_error_dialog_title))
.setMessage(e.message)
.setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ -> finish() }
.show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (SshKey.exists) {
MaterialAlertDialogBuilder(this).run {
setTitle(R.string.ssh_keygen_existing_title)
setMessage(R.string.ssh_keygen_existing_message)
setPositiveButton(R.string.ssh_keygen_existing_replace) { _, _ ->
importSshKey()
}
setNegativeButton(R.string.ssh_keygen_existing_keep) { _, _ -> finish() }
setOnCancelListener { finish() }
show()
}
} else {
importSshKey()
}
}
private fun importSshKey() {
sshKeyImportAction.launch(arrayOf("*/*"))
}
}

View file

@ -9,8 +9,10 @@ import android.os.Build
import androidx.annotation.RequiresApi
import com.github.androidpasswordstore.autofillparser.Credentials
import dev.msfjarvis.aps.data.password.PasswordEntry
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.services.getDefaultUsername
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import java.io.File
import java.nio.file.Paths
@ -110,8 +112,7 @@ enum class DirectoryStructure(val value: String) {
companion object {
const val PREFERENCE = "oreo_autofill_directory_structure"
private val DEFAULT = FileBased
val DEFAULT = FileBased
private val reverseMap = values().associateBy { it.value }
fun fromValue(value: String?) = if (value != null) reverseMap[value] ?: DEFAULT else DEFAULT
@ -121,7 +122,7 @@ enum class DirectoryStructure(val value: String) {
object AutofillPreferences {
fun directoryStructure(context: Context): DirectoryStructure {
val value = context.sharedPrefs.getString(DirectoryStructure.PREFERENCE, null)
val value = context.sharedPrefs.getString(PreferenceKeys.OREO_AUTOFILL_DIRECTORY_STRUCTURE)
return DirectoryStructure.fromValue(value)
}

View file

@ -15,7 +15,6 @@ import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.ui.settings.UserPreference
import dev.msfjarvis.aps.util.git.GitCommandExecutor
import dev.msfjarvis.aps.util.settings.AuthMode
import dev.msfjarvis.aps.util.settings.GitSettings
@ -25,6 +24,8 @@ import dev.msfjarvis.aps.util.git.sshj.SshKey
import dev.msfjarvis.aps.util.git.sshj.SshjSessionFactory
import dev.msfjarvis.aps.util.auth.BiometricAuthenticator
import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.ui.sshkeygen.SshKeyGenActivity
import dev.msfjarvis.aps.ui.sshkeygen.SshKeyImportActivity
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.Dispatchers
@ -92,9 +93,11 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
private fun getSshKey(make: Boolean) {
runCatching {
// Ask the UserPreference to provide us with the ssh-key
val intent = Intent(callingActivity.applicationContext, UserPreference::class.java)
intent.putExtra("operation", if (make) "make_ssh_key" else "get_ssh_key")
val intent = if (make) {
Intent(callingActivity.applicationContext, SshKeyGenActivity::class.java)
} else {
Intent(callingActivity.applicationContext, SshKeyImportActivity::class.java)
}
callingActivity.startActivity(intent)
}.onFailure { e ->
e(e)

View file

@ -0,0 +1,14 @@
<!--
~ Copyright © 2014-2021 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:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M21.81,12.74l-0.82,-0.63v-0.22l0.8,-0.63c0.16,-0.12 0.2,-0.34 0.1,-0.51l-0.85,-1.48c-0.07,-0.13 -0.21,-0.2 -0.35,-0.2 -0.05,0 -0.1,0.01 -0.15,0.03l-0.95,0.38c-0.08,-0.05 -0.11,-0.07 -0.19,-0.11l-0.15,-1.01c-0.03,-0.21 -0.2,-0.36 -0.4,-0.36h-1.71c-0.2,0 -0.37,0.15 -0.4,0.34l-0.14,1.01c-0.03,0.02 -0.07,0.03 -0.1,0.05l-0.09,0.06 -0.95,-0.38c-0.05,-0.02 -0.1,-0.03 -0.15,-0.03 -0.14,0 -0.27,0.07 -0.35,0.2l-0.85,1.48c-0.1,0.17 -0.06,0.39 0.1,0.51l0.8,0.63v0.23l-0.8,0.63c-0.16,0.12 -0.2,0.34 -0.1,0.51l0.85,1.48c0.07,0.13 0.21,0.2 0.35,0.2 0.05,0 0.1,-0.01 0.15,-0.03l0.95,-0.37c0.08,0.05 0.12,0.07 0.2,0.11l0.15,1.01c0.03,0.2 0.2,0.34 0.4,0.34h1.71c0.2,0 0.37,-0.15 0.4,-0.34l0.15,-1.01c0.03,-0.02 0.07,-0.03 0.1,-0.05l0.09,-0.06 0.95,0.38c0.05,0.02 0.1,0.03 0.15,0.03 0.14,0 0.27,-0.07 0.35,-0.2l0.85,-1.48c0.1,-0.17 0.06,-0.39 -0.1,-0.51zM18,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM17,17h2v4c0,1.1 -0.9,2 -2,2H7c-1.1,0 -2,-0.9 -2,-2V3c0,-1.1 0.9,-2 2,-2h10c1.1,0 2,0.9 2,2v4h-2V6H7v12h10v-1z"/>
</vector>

View file

@ -0,0 +1,14 @@
<!--
~ Copyright © 2014-2020 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:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M17,20.41L18.41,19 15,15.59 13.59,17 17,20.41zM7.5,8H11v5.59L5.59,19 7,20.41l6,-6V8h3.5L12,3.5 7.5,8z"/>
</vector>

View file

@ -0,0 +1,17 @@
<!--
~ Copyright © 2014-2020 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:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M14.17,13.71l1.4,-2.42c0.09,-0.15 0.05,-0.34 -0.08,-0.45l-1.48,-1.16c0.03,-0.22 0.05,-0.45 0.05,-0.68s-0.02,-0.46 -0.05,-0.69l1.48,-1.16c0.13,-0.11 0.17,-0.3 0.08,-0.45l-1.4,-2.42c-0.09,-0.15 -0.27,-0.21 -0.43,-0.15L12,4.83c-0.36,-0.28 -0.75,-0.51 -1.18,-0.69l-0.26,-1.85C10.53,2.13 10.38,2 10.21,2h-2.8C7.24,2 7.09,2.13 7.06,2.3L6.8,4.15C6.38,4.33 5.98,4.56 5.62,4.84l-1.74,-0.7c-0.16,-0.06 -0.34,0 -0.43,0.15l-1.4,2.42C1.96,6.86 2,7.05 2.13,7.16l1.48,1.16C3.58,8.54 3.56,8.77 3.56,9s0.02,0.46 0.05,0.69l-1.48,1.16C2,10.96 1.96,11.15 2.05,11.3l1.4,2.42c0.09,0.15 0.27,0.21 0.43,0.15l1.74,-0.7c0.36,0.28 0.75,0.51 1.18,0.69l0.26,1.85C7.09,15.87 7.24,16 7.41,16h2.8c0.17,0 0.32,-0.13 0.35,-0.3l0.26,-1.85c0.42,-0.18 0.82,-0.41 1.18,-0.69l1.74,0.7C13.9,13.92 14.08,13.86 14.17,13.71zM8.81,11c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C10.81,10.1 9.91,11 8.81,11z"/>
<path
android:fillColor="#FF000000"
android:pathData="M21.92,18.67l-0.96,-0.74c0.02,-0.14 0.04,-0.29 0.04,-0.44c0,-0.15 -0.01,-0.3 -0.04,-0.44l0.95,-0.74c0.08,-0.07 0.11,-0.19 0.05,-0.29l-0.9,-1.55c-0.05,-0.1 -0.17,-0.13 -0.28,-0.1l-1.11,0.45c-0.23,-0.18 -0.48,-0.33 -0.76,-0.44l-0.17,-1.18C18.73,13.08 18.63,13 18.53,13h-1.79c-0.11,0 -0.21,0.08 -0.22,0.19l-0.17,1.18c-0.27,0.12 -0.53,0.26 -0.76,0.44l-1.11,-0.45c-0.1,-0.04 -0.22,0 -0.28,0.1l-0.9,1.55c-0.05,0.1 -0.04,0.22 0.05,0.29l0.95,0.74c-0.02,0.14 -0.03,0.29 -0.03,0.44c0,0.15 0.01,0.3 0.03,0.44l-0.95,0.74c-0.08,0.07 -0.11,0.19 -0.05,0.29l0.9,1.55c0.05,0.1 0.17,0.13 0.28,0.1l1.11,-0.45c0.23,0.18 0.48,0.33 0.76,0.44l0.17,1.18c0.02,0.11 0.11,0.19 0.22,0.19h1.79c0.11,0 0.21,-0.08 0.22,-0.19l0.17,-1.18c0.27,-0.12 0.53,-0.26 0.75,-0.44l1.12,0.45c0.1,0.04 0.22,0 0.28,-0.1l0.9,-1.55C22.03,18.86 22,18.74 21.92,18.67zM17.63,18.83c-0.74,0 -1.35,-0.6 -1.35,-1.35s0.6,-1.35 1.35,-1.35s1.35,0.6 1.35,1.35S18.37,18.83 17.63,18.83z"/>
</vector>

View file

@ -0,0 +1,14 @@
<!--
~ Copyright © 2014-2020 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:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M19,3H5C3.89,3 3,3.9 3,5v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.11,3 19,3zM19,19H5V7h14V19zM17,12H7v-2h10V12zM13,16H7v-2h6V16z"/>
</vector>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2014-2020 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/preference_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>

View file

@ -89,43 +89,42 @@
<string name="share_as_plaintext">Als Klartext teilen</string>
<string name="last_changed">Zuletzt geändert %s</string>
<!-- Preferences -->
<string name="pref_repository_title">Repository</string>
<string name="pref_edit_server_info">Git-Server Einstellungen</string>
<string name="pref_category_repository_title">Repository</string>
<string name="pref_edit_git_server_settings">Git-Server Einstellungen</string>
<string name="pref_edit_git_config">Lokale Git Konfiguration &amp; Dienstprogramme</string>
<string name="pref_ssh_title">Importiere SSH-Key</string>
<string name="pref_import_ssh_key_title">Importiere SSH-Key</string>
<string name="pref_ssh_keygen_title">Erstelle SSH-Schlüsselpaar</string>
<string name="pref_ssh_see_key_title">Zeige erstellten öffentlichen SSH-Key</string>
<string name="pref_git_delete_repo">Repository löschen</string>
<string name="pref_git_delete_repo_title">Repository löschen</string>
<string name="pref_dialog_delete_title">Repository löschen</string>
<string name="pref_category_general_title">Allgemein</string>
<string name="pref_category_title_passwords">Passwörter</string>
<string name="pref_category_passwords_title">Passwörter</string>
<string name="pref_clipboard_timeout_title">Timeout für das Kopieren des Passwortes</string>
<string name="pref_clipboard_timeout_summary">Legen Sie die Zeit (in Sekunden) fest, die das Passwort in der Zwischenablage liegen soll. 0 bedeutet für immer. Aktueller Wert: %1$s</string>
<string name="pref_copy_title">Kopiere Passwort automatisch</string>
<string name="pref_copy_dialog_title">Kopiert das Passwort in die Zwischenablage, wenn der Eintrag entschlüsselt wurde.</string>
<string name="pref_copy_summary">Kopiert das Passwort in die Zwischenablage, wenn der Eintrag entschlüsselt wurde.</string>
<string name="ssh_key_import_error_not_an_ssh_key_message">Die ausgewählte Datei scheint kein privater SSH-Schlüssel zu sein.</string>
<string name="ssh_key_success_dialog_title">SSH-Key importiert</string>
<string name="ssh_key_error_dialog_title">Schlüssel-Importfehler</string>
<string name="ssh_key_error_dialog_text">Nachricht : \n</string>
<string name="pref_recursive_filter">Suche in Unterordnern</string>
<string name="pref_recursive_filter_hint">Findet Passwörter auch in Unterordnern.</string>
<string name="pref_recursive_filter_title">Suche in Unterordnern</string>
<string name="pref_recursive_filter_summary">Findet Passwörter auch in Unterordnern.</string>
<string name="pref_sort_order_title">Passwortsortierung</string>
<string name="pref_folder_first_sort_order">Ordner zuerst</string>
<string name="pref_file_first_sort_order">Dateien zuerst</string>
<string name="pref_type_independent_sort_order">Typ unabhängig</string>
<string name="pref_recently_used_sort_order">Zuletzt verwendet</string>
<string name="pref_autofill_title">Automatisch ausfüllen</string>
<string name="pref_category_autofill_title">Automatisch ausfüllen</string>
<string name="pref_autofill_enable_title">Autofill aktivieren</string>
<string name="pref_misc_title">Verschiedenes</string>
<string name="pref_category_misc_title">Verschiedenes</string>
<string name="pref_clear_clipboard_title">Lösche die Zwischenablage 20-mal</string>
<string name="pref_clear_clipboard_hint">Speichert Nonsense 20-mal anstatt 1-mal in der Zwischenablage. Nützlich bspw. auf Samsung-Geräten, die den Verlauf der Zwischenablage speichern.</string>
<string name="pref_clear_clipboard_summary">Speichert Nonsense 20-mal anstatt 1-mal in der Zwischenablage. Nützlich bspw. auf Samsung-Geräten, die den Verlauf der Zwischenablage speichern.</string>
<string name="pref_git_delete_repo_summary">Lösche das lokale (versteckte) Repository</string>
<string name="pref_external_repository">Externes Repository</string>
<string name="pref_external_repository_title">Externes Repository</string>
<string name="pref_external_repository_summary">Nutze ein externes Repository</string>
<string name="pref_select_external_repository">Wähle ein externes Repository</string>
<string name="pref_select_external_repository_title">Wähle ein externes Repository</string>
<string name="prefs_export_passwords_title">Passwörter exportieren</string>
<string name="prefs_export_passwords_summary">Exportiert die verschlüsselten Passwörter in ein externes Verzeichnis</string>
<string name="prefs_version">Version</string>
<!-- PasswordGenerator fragment -->
<string name="pwgen_title">Passwort generieren</string>
<string name="pwgen_generate">Generieren</string>
@ -147,12 +146,12 @@
<string name="xkpwgen_custom_dict_imported">Eigene Wortliste: %1$s</string>
<string name="xkpwgen_builder_error">Das ausgewählte Wörterbuch enthält nicht genügend Wörter der angegebenen Länge %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="xkpwgen_pref_gentype_title">Passwortgenerator</string>
<string name="xkpwgen_pref_custom_dict_title">Eigene Wortliste</string>
<string name="xkpwgen_pref_custom_dict_summary_on">Eigene Wordlist-Datei verwenden</string>
<string name="xkpwgen_pref_custom_dict_summary_off">Integrierte Wortliste verwenden</string>
<string name="xkpwgen_pref_custom_dict_picker_title">Eigene Wortliste</string>
<string name="xkpwgen_pref_custom_dict_picker_summary">Tippen Sie, um eine benutzerdefinierte Wordlist-Datei mit einem Wort pro Zeile auszuwählen</string>
<string name="pref_password_generator_type_title">Passwortgenerator</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Eigene Wortliste</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Eigene Wordlist-Datei verwenden</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Integrierte Wortliste verwenden</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Eigene Wortliste</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Tippen Sie, um eine benutzerdefinierte Wordlist-Datei mit einem Wort pro Zeile auszuwählen</string>
<!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Passwort</string>
<string name="ssh_keygen_generate">Generieren</string>
@ -192,7 +191,7 @@
<string name="show_extra_content_pref_summary">Soll weiterer Inhalt sichtbar sein?</string>
<string name="pwd_generate_button">Generieren</string>
<string name="refresh_list">Aktualisieren</string>
<string name="no_repo_selected">Kein externes Repository ausgewählt</string>
<string name="pref_select_external_repository_summary_no_repo_selected">Kein externes Repository ausgewählt</string>
<string name="send_plaintext_password_to">Passwort unverschlüsselt senden an…</string>
<string name="app_icon_hint">App Icon</string>
<!-- Oreo Autofill -->
@ -238,10 +237,10 @@
<string name="biometric_prompt_title">Biometrische Abfrage</string>
<string name="biometric_auth_error">Authentifizierungsfehler</string>
<string name="biometric_auth_error_reason">Authentifizierungsfehler: %s</string>
<string name="biometric_auth_title">Biometrische Authentifizierung aktivieren</string>
<string name="biometric_auth_summary">Wenn aktiviert, werden Sie beim Starten der App nach Ihrem Fingerabdruck gefragt</string>
<string name="biometric_auth_summary_error">Fingerabdrucksensor fehlt oder ist nicht ansprechbar</string>
<string name="ssh_openkeystore_clear_keyid">Lösche gespeicherte OpenKeystore SSH-Schlüssel-ID</string>
<string name="pref_biometric_auth_title">Biometrische Authentifizierung aktivieren</string>
<string name="pref_biometric_auth_summary">Wenn aktiviert, werden Sie beim Starten der App nach Ihrem Fingerabdruck gefragt</string>
<string name="pref_biometric_auth_summary_error">Fingerabdrucksensor fehlt oder ist nicht ansprechbar</string>
<string name="pref_title_openkeystore_clear_keyid">Lösche gespeicherte OpenKeystore SSH-Schlüssel-ID</string>
<string name="access_sdcard_text">Der Speicherort befindet sich in Ihrer SD-Karte oder im internen Speicher, aber die App hat nicht die Berechtigung, darauf zuzugreifen.</string>
<string name="your_public_key">Ihr öffentlicher Schlüssel</string>
<string name="error_generate_ssh_key">Fehler beim Generieren des SSH-Schlüssels</string>
@ -254,16 +253,15 @@
<string name="message_error_destination_outside_repo">Ziel muss innerhalb des repository sein</string>
<string name="message_rename_folder">Ziel für %1$s angeben</string>
<string name="button_create">Erstellen</string>
<string name="pref_search_on_start">Suchfeld beim Start öffnen</string>
<string name="pref_search_on_start_hint">Suchleiste beim Start der App anzeigen</string>
<string name="password_generator_category_title">Passwort Generator</string>
<string name="pref_search_on_start_title">Suchfeld beim Start öffnen</string>
<string name="pref_search_on_start_summary">Suchleiste beim Start der App anzeigen</string>
<string name="tap_clear_clipboard">Hier tippen, um die Zwischenablage zu löschen</string>
<string name="clone_git_repo">Das Repository muss geklont werden, bevor Änderungen synchronisert werden können.</string>
<string name="theme_title">App Farbthema</string>
<string name="theme_light">Hell</string>
<string name="theme_dark">Dunkel</string>
<string name="theme_battery_saver">Durch Energiesparmodus gesetzt</string>
<string name="theme_follow_system">Systemstandard</string>
<string name="pref_app_theme_title">App Farbthema</string>
<string name="pref_app_theme_value_light">Hell</string>
<string name="pref_app_theme_value_dark">Dunkel</string>
<string name="pref_app_theme_value_battery_saver">Durch Energiesparmodus gesetzt</string>
<string name="pref_app_theme_value_follow_system">Systemstandard</string>
<string name="connection_mode_ssh_key">SSH-Schlüssel</string>
<string name="connection_mode_basic_authentication">Passwort</string>
<string name="git_server_config_save_success">Konfiguration erfolgreich gespeichert</string>

View file

@ -91,43 +91,42 @@
<string name="share_as_plaintext">Partager en clair</string>
<string name="last_changed">Dernière modification le %s</string>
<!-- Preferences -->
<string name="pref_repository_title">Dépôt</string>
<string name="pref_edit_server_info">Modifier les paramètres du serveur Git</string>
<string name="pref_category_repository_title">Dépôt</string>
<string name="pref_edit_git_server_settings">Modifier les paramètres du serveur Git</string>
<string name="pref_edit_git_config">Configuration locale de Git &amp; utilitaires</string>
<string name="pref_ssh_title">Importer une clef SSH</string>
<string name="pref_import_ssh_key_title">Importer une clef SSH</string>
<string name="pref_ssh_keygen_title">Générer une paire de clefs SSH</string>
<string name="pref_ssh_see_key_title">Voir la clef publique SSH générée</string>
<string name="pref_git_delete_repo">Supprimer le dépôt</string>
<string name="pref_git_delete_repo_title">Supprimer le dépôt</string>
<string name="pref_dialog_delete_title">Effacer le dépôt</string>
<string name="pref_category_general_title">Général</string>
<string name="pref_category_title_passwords">Mot de passe</string>
<string name="pref_category_passwords_title">Mot de passe</string>
<string name="pref_clipboard_timeout_title">Délai imparti pour la copie</string>
<string name="pref_clipboard_timeout_summary">Définissez le temps (en secondes) durant lequel le mot de passe restera dans le presse-papiers. 0 pour une rétention illimitée. Valeur actuelle: %1$s</string>
<string name="pref_copy_title">Copie automatique du mot de passe</string>
<string name="pref_copy_dialog_title">Copie automatiquement le mot de passe vers le presse-papier si le déchiffrement a réussi.</string>
<string name="pref_copy_summary">Copie automatiquement le mot de passe vers le presse-papier si le déchiffrement a réussi.</string>
<string name="ssh_key_import_error_not_an_ssh_key_message">Le fichier sélectionné ne semble pas être une clé privée SSH.</string>
<string name="ssh_key_success_dialog_title">Clef SSH importée</string>
<string name="ssh_key_error_dialog_title">Erreur d\'importation de la clé</string>
<string name="ssh_key_error_dialog_text">Message : \n</string>
<string name="pref_recursive_filter">Filtre récursif</string>
<string name="pref_recursive_filter_hint">Cherche le mot de passe dans tous les sous-répertoires du répertoire actuel.</string>
<string name="pref_recursive_filter_title">Filtre récursif</string>
<string name="pref_recursive_filter_summary">Cherche le mot de passe dans tous les sous-répertoires du répertoire actuel.</string>
<string name="pref_sort_order_title">Ordre de tri des mots de passe</string>
<string name="pref_folder_first_sort_order">Dossiers en premier</string>
<string name="pref_file_first_sort_order">Fichiers en premier</string>
<string name="pref_type_independent_sort_order">Indifférent au type d\'entrée</string>
<string name="pref_recently_used_sort_order">Récemment utilisé</string>
<string name="pref_autofill_title">Saisie automatique</string>
<string name="pref_category_autofill_title">Saisie automatique</string>
<string name="pref_autofill_enable_title">Saisie automatique</string>
<string name="pref_misc_title">Divers</string>
<string name="pref_category_misc_title">Divers</string>
<string name="pref_clear_clipboard_title">Effacer le presse-papier 20 fois</string>
<string name="pref_clear_clipboard_hint">Enregistre des informations absurdes dans le presse-papier 20 fois à la place d\'une seule. Utile sur les téléphones Samsung qui disposent d\'un historique du presse-papier.</string>
<string name="pref_clear_clipboard_summary">Enregistre des informations absurdes dans le presse-papier 20 fois à la place d\'une seule. Utile sur les téléphones Samsung qui disposent d\'un historique du presse-papier.</string>
<string name="pref_git_delete_repo_summary">Supprime le dépot local (caché)</string>
<string name="pref_external_repository">Dépôt externe</string>
<string name="pref_external_repository_title">Dépôt externe</string>
<string name="pref_external_repository_summary">Utilise un dépôt externe pour les mots de passe</string>
<string name="pref_select_external_repository">Choisissez un dépôt externe</string>
<string name="pref_select_external_repository_title">Choisissez un dépôt externe</string>
<string name="prefs_export_passwords_title">Exporter les mots de passe</string>
<string name="prefs_export_passwords_summary">Exporter les mots de passe (chiffrés) vers un répertoire externe</string>
<string name="prefs_version">Version</string>
<!-- PasswordGenerator fragment -->
<string name="pwgen_title">Générer un mot de passe</string>
<string name="pwgen_generate">Générer</string>
@ -149,12 +148,12 @@
<string name="xkpwgen_custom_dict_imported">Liste de mots personnalisée : %1$s</string>
<string name="xkpwgen_builder_error">Le dictionnaire sélectionné ne contient pas assez de mots de la longueur %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="xkpwgen_pref_gentype_title">Type de générateur de mot de passe</string>
<string name="xkpwgen_pref_custom_dict_title">Liste de mots personnalisée</string>
<string name="xkpwgen_pref_custom_dict_summary_on">Utiliser une liste de mots personnalisée</string>
<string name="xkpwgen_pref_custom_dict_summary_off">Utilisation de la liste de mots intégrée</string>
<string name="xkpwgen_pref_custom_dict_picker_title">Fichier personnalisé de liste de mots</string>
<string name="xkpwgen_pref_custom_dict_picker_summary">Touchez pour choisir un fichier de liste de mots personnalisés contenant un mot par ligne</string>
<string name="pref_password_generator_type_title">Type de générateur de mot de passe</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Liste de mots personnalisée</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Utiliser une liste de mots personnalisée</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Utilisation de la liste de mots intégrée</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Fichier personnalisé de liste de mots</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Touchez pour choisir un fichier de liste de mots personnalisés contenant un mot par ligne</string>
<!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Mot de passe</string>
<string name="ssh_keygen_generate">Générer</string>
@ -191,7 +190,7 @@
<string name="show_extra_content_pref_summary">Controller la visibilité du contenu supplémentaire une fois déchiffré</string>
<string name="pwd_generate_button">Générer</string>
<string name="refresh_list">Rafraichir la liste</string>
<string name="no_repo_selected">Pas de dépôt externe séléctionné</string>
<string name="pref_select_external_repository_summary_no_repo_selected">Pas de dépôt externe séléctionné</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 -->
@ -224,9 +223,9 @@
<string name="git_operation_remember_passphrase">Se rappeler de la phrase secrète dans la configuration de l\'application (peu sûr)</string>
<string name="reset_to_remote">Réinitialisation dure de la branche distante</string>
<string name="biometric_prompt_title">Identification biométrique</string>
<string name="biometric_auth_title">Authentification biométrique</string>
<string name="biometric_auth_summary">Lorsque cette option est activée, Password Store vous demandera votre empreinte digitale au lancement</string>
<string name="biometric_auth_summary_error">Lecteur d\'empreinte digitale non accessible ou manquant</string>
<string name="pref_biometric_auth_title">Authentification biométrique</string>
<string name="pref_biometric_auth_summary">Lorsque cette option est activée, Password Store vous demandera votre empreinte digitale au lancement</string>
<string name="pref_biometric_auth_summary_error">Lecteur d\'empreinte digitale non accessible ou manquant</string>
<string name="your_public_key">Votre clé publique</string>
<string name="error_generate_ssh_key">Une erreur est survenue pendant la génération de la clé ssh</string>
<string name="pref_show_hidden_title">Afficher tous les fichiers et dossiers</string>
@ -235,14 +234,13 @@
<string name="title_rename_folder">Renommer le dossier</string>
<string name="message_rename_folder">Entrez le chemin pour %1$s</string>
<string name="button_create">Créer</string>
<string name="pref_search_on_start">Ouvrir la recherche au démarrage</string>
<string name="pref_search_on_start_hint">Ouvrir la barre de recherche au démarrage de l\'application</string>
<string name="password_generator_category_title">Générateur de mot de passe</string>
<string name="pref_search_on_start_title">Ouvrir la recherche au démarrage</string>
<string name="pref_search_on_start_summary">Ouvrir la barre de recherche au démarrage de l\'application</string>
<string name="tap_clear_clipboard">Appuyez ici pour effacer le presse-papiers</string>
<string name="theme_title">Thème de l\'application</string>
<string name="theme_light">Clair</string>
<string name="theme_dark">Sombre</string>
<string name="theme_follow_system">Thème système</string>
<string name="pref_app_theme_title">Thème de l\'application</string>
<string name="pref_app_theme_value_light">Clair</string>
<string name="pref_app_theme_value_dark">Sombre</string>
<string name="pref_app_theme_value_follow_system">Thème système</string>
<string name="connection_mode_ssh_key">Clé SSH</string>
<string name="connection_mode_basic_authentication">Mot de passe</string>
<string name="git_server_config_save_error">L\'URL du dépôt fournie n\'est pas valide</string>

View file

@ -93,43 +93,42 @@
<string name="share_as_plaintext">Compartir como texto plano</string>
<string name="last_changed">Último cambio %s</string>
<!-- Preferences -->
<string name="pref_repository_title">Repositorio</string>
<string name="pref_edit_server_info">Editar axustes do servidor git</string>
<string name="pref_category_repository_title">Repositorio</string>
<string name="pref_edit_git_server_settings">Editar axustes do servidor git</string>
<string name="pref_edit_git_config">Utilidades Git</string>
<string name="pref_ssh_title">Importar chave SSH</string>
<string name="pref_import_ssh_key_title">Importar chave SSH</string>
<string name="pref_ssh_keygen_title">Crear par de chaves SSH</string>
<string name="pref_ssh_see_key_title">Ver a chave pública SSH creada</string>
<string name="pref_git_delete_repo">Eliminar repositorio</string>
<string name="pref_git_delete_repo_title">Eliminar repositorio</string>
<string name="pref_dialog_delete_title">Baleirar repositorio</string>
<string name="pref_category_general_title">Xeral</string>
<string name="pref_category_title_passwords">Contrasinais</string>
<string name="pref_category_passwords_title">Contrasinais</string>
<string name="pref_clipboard_timeout_title">Caducidade do copiado do contrasinal</string>
<string name="pref_clipboard_timeout_summary">Establece os segundos que queres que o contrasinal permaneza copiado no portapapeis. 0 significa para sempre. Valor actual: %1$s</string>
<string name="pref_copy_title">Copiar contrasinal automáticamente</string>
<string name="pref_copy_dialog_title">Copia automáticamente o contrasinal ao portapapeis se o descifra correctamente</string>
<string name="pref_copy_summary">Copia automáticamente o contrasinal ao portapapeis se o descifra correctamente</string>
<string name="ssh_key_import_error_not_an_ssh_key_message">O ficheiro escollido non semella ser unha chave privada SSH.</string>
<string name="ssh_key_success_dialog_title">Chave-SSH importada</string>
<string name="ssh_key_error_dialog_title">Houbo un fallo ao importar a chave ssh</string>
<string name="ssh_key_error_dialog_text">Mensaxe : \n</string>
<string name="pref_recursive_filter">Filtro recursivo</string>
<string name="pref_recursive_filter_hint">Atopa as chaves de xeito recursivo no directorio actual.</string>
<string name="pref_recursive_filter_title">Filtro recursivo</string>
<string name="pref_recursive_filter_summary">Atopa as chaves de xeito recursivo no directorio actual.</string>
<string name="pref_sort_order_title">Orde para mostrar contrasinais</string>
<string name="pref_folder_first_sort_order">Primeiro cartafoles</string>
<string name="pref_file_first_sort_order">Primeiro ficheiros</string>
<string name="pref_type_independent_sort_order">Independentemente do tipo</string>
<string name="pref_recently_used_sort_order">Usadas recentemente</string>
<string name="pref_autofill_title">Completado automático</string>
<string name="pref_category_autofill_title">Completado automático</string>
<string name="pref_autofill_enable_title">Activar completado automático</string>
<string name="pref_misc_title">Varios</string>
<string name="pref_category_misc_title">Varios</string>
<string name="pref_clear_clipboard_title">Baleirar portapapeis 20 veces</string>
<string name="pref_clear_clipboard_hint">Gardar números consecutivos no portapapeis 20 veces. Resulta útil nos móbiles Samsung que gardan historial no portapapeis.</string>
<string name="pref_clear_clipboard_summary">Gardar números consecutivos no portapapeis 20 veces. Resulta útil nos móbiles Samsung que gardan historial no portapapeis.</string>
<string name="pref_git_delete_repo_summary">Elimina repositorio local (oculto).</string>
<string name="pref_external_repository">Repositorio externo</string>
<string name="pref_external_repository_title">Repositorio externo</string>
<string name="pref_external_repository_summary">Usar un repositorio externo de contrasinais</string>
<string name="pref_select_external_repository">Selecciona repositorio externo</string>
<string name="pref_select_external_repository_title">Selecciona repositorio externo</string>
<string name="prefs_export_passwords_title">Exportar contrasinais</string>
<string name="prefs_export_passwords_summary">Exporta os contrasinais cifrados a un directorio externo</string>
<string name="prefs_version">Versión</string>
<!-- PasswordGenerator fragment -->
<string name="pwgen_title">Crear contrasinal</string>
<string name="pwgen_generate">Crear</string>
@ -151,12 +150,12 @@
<string name="xkpwgen_custom_dict_imported">Lista persoal de palabras: %1$s</string>
<string name="xkpwgen_builder_error">O dicionario non contén palabras suficientes da lonxitude dada %1$d .. %2$d</string>
<!-- XKPWD prefs -->
<string name="xkpwgen_pref_gentype_title">Tipo de creador de contrasinais</string>
<string name="xkpwgen_pref_custom_dict_title">Lista persoal de palabras</string>
<string name="xkpwgen_pref_custom_dict_summary_on">Usar ficheiro con palabras personalizadas</string>
<string name="xkpwgen_pref_custom_dict_summary_off">Usar lista de palabras incluída</string>
<string name="xkpwgen_pref_custom_dict_picker_title">Ficheiro persoal de palabras</string>
<string name="xkpwgen_pref_custom_dict_picker_summary">Toca para escoller un ficheiro persoal con palabras que conteña unha palabra por liña</string>
<string name="pref_password_generator_type_title">Tipo de creador de contrasinais</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Lista persoal de palabras</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Usar ficheiro con palabras personalizadas</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Usar lista de palabras incluída</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Ficheiro persoal de palabras</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Toca para escoller un ficheiro persoal con palabras que conteña unha palabra por liña</string>
<!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Frase de paso</string>
<string name="ssh_keygen_generate">Crear</string>
@ -196,7 +195,7 @@
<string name="show_extra_content_pref_summary">Controla a visibilidade do contido extra unha vez descifrado</string>
<string name="pwd_generate_button">Crear</string>
<string name="refresh_list">Actualizar lista</string>
<string name="no_repo_selected">Non hai seleccionado ningún repositorio externo</string>
<string name="pref_select_external_repository_summary_no_repo_selected">Non hai seleccionado ningún repositorio externo</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 -->
@ -249,10 +248,10 @@ a app desde unha fonte de confianza, como a Play Store, Amazon Appstore, F-Droid
<string name="biometric_prompt_title">Petición biométrica</string>
<string name="biometric_auth_error">Fallo de autenticación</string>
<string name="biometric_auth_error_reason">Fallou a autenticación: %s</string>
<string name="biometric_auth_title">Activar autenticación biométrica</string>
<string name="biometric_auth_summary">Ao activala, Password Store vaiche pedir a túa pegada dactilar ao iniciar a app</string>
<string name="biometric_auth_summary_error">O hardware de pegada dixital non é accesible ou existente</string>
<string name="ssh_openkeystore_clear_keyid">Eliminar o ID lembrado da chave SSH en OpenKeystore</string>
<string name="pref_biometric_auth_title">Activar autenticación biométrica</string>
<string name="pref_biometric_auth_summary">Ao activala, Password Store vaiche pedir a túa pegada dactilar ao iniciar a app</string>
<string name="pref_biometric_auth_summary_error">O hardware de pegada dixital non é accesible ou existente</string>
<string name="pref_title_openkeystore_clear_keyid">Eliminar o ID lembrado da chave SSH en OpenKeystore</string>
<string name="access_sdcard_text">O almacenaxe está na tarxeta SD pero a app non ten permiso para acceder a el. Por favor concédelle permiso.</string>
<string name="your_public_key">A túa chave pública</string>
<string name="error_generate_ssh_key">Algo fallou ao intentar crear a chave-ssh</string>
@ -265,16 +264,15 @@ a app desde unha fonte de confianza, como a Play Store, Amazon Appstore, F-Droid
<string name="message_error_destination_outside_repo">O destino debe estar dentro do repositorio</string>
<string name="message_rename_folder">Escribe o destino para %1$s</string>
<string name="button_create">Crear</string>
<string name="pref_search_on_start">Abrir busca ao inicio</string>
<string name="pref_search_on_start_hint">Abrir a barra de busca cando se inicia a app</string>
<string name="password_generator_category_title">Creador de contrasinais</string>
<string name="pref_search_on_start_title">Abrir busca ao inicio</string>
<string name="pref_search_on_start_summary">Abrir a barra de busca cando se inicia a app</string>
<string name="tap_clear_clipboard">Toca aquí para baleirar o portapapeis</string>
<string name="clone_git_repo">Clonar un repositorio git para sincronizar os cambios</string>
<string name="theme_title">Decorado da App</string>
<string name="theme_light">Claro</string>
<string name="theme_dark">Escuro</string>
<string name="theme_battery_saver">Establecido polo Aforrador de enerxía</string>
<string name="theme_follow_system">Por omisión do sistema</string>
<string name="pref_app_theme_title">Decorado da App</string>
<string name="pref_app_theme_value_light">Claro</string>
<string name="pref_app_theme_value_dark">Escuro</string>
<string name="pref_app_theme_value_battery_saver">Establecido polo Aforrador de enerxía</string>
<string name="pref_app_theme_value_follow_system">Por omisión do sistema</string>
<string name="connection_mode_ssh_key">Chave SSH</string>
<string name="connection_mode_basic_authentication">Contrasinal</string>
<string name="git_server_config_save_success">Configuración gardada</string>
@ -354,7 +352,7 @@ a app desde unha fonte de confianza, como a Play Store, Amazon Appstore, F-Droid
<!-- Proxy configuration activity -->
<string name="proxy_hostname">Servidor proxy</string>
<string name="port">Porto</string>
<string name="pref_proxy_settings">Axustes do proxy HTTP(S)</string>
<string name="pref_edit_proxy_settings">Axustes do proxy HTTP(S)</string>
<string name="invalid_proxy_url">URL non válido</string>
<string name="oreo_autofill_password_fill_and_conditional_save_support">Completa e garda contrasinais (gardar require que os servizos de accesibilidade non estén activados)</string>
<string name="clear_saved_host_key">Eliminar chave do host gardada</string>

View file

@ -93,43 +93,42 @@
<string name="share_as_plaintext">Condividi come testo semplice</string>
<string name="last_changed">Ultima modifica %s</string>
<!-- Preferences -->
<string name="pref_repository_title">Repository</string>
<string name="pref_edit_server_info">Modifica impostazioni del server di Git</string>
<string name="pref_category_repository_title">Repository</string>
<string name="pref_edit_git_server_settings">Modifica impostazioni del server di Git</string>
<string name="pref_edit_git_config">Configurazione &amp; utilità della configurazione di Git</string>
<string name="pref_ssh_title">Importa chiave SSH</string>
<string name="pref_import_ssh_key_title">Importa chiave SSH</string>
<string name="pref_ssh_keygen_title">Genera coppia di chiavi SSH</string>
<string name="pref_ssh_see_key_title">Visualizza la chiave SSH pubblica generata</string>
<string name="pref_git_delete_repo">Elimina repository</string>
<string name="pref_git_delete_repo_title">Elimina repository</string>
<string name="pref_dialog_delete_title">Cancella repository</string>
<string name="pref_category_general_title">Generale</string>
<string name="pref_category_title_passwords">Password</string>
<string name="pref_category_passwords_title">Password</string>
<string name="pref_clipboard_timeout_title">Timeout copia della password</string>
<string name="pref_clipboard_timeout_summary">Imposta per quanto tempo (in secondi) vuoi che la password rimanga negli appunti. 0 significa per sempre. Valore corrente: %1$s</string>
<string name="pref_copy_title">Copia automaticamente la password</string>
<string name="pref_copy_dialog_title">Copia automaticamente la password negli appunti dopo il successo della decifratura.</string>
<string name="pref_copy_summary">Copia automaticamente la password negli appunti dopo il successo della decifratura.</string>
<string name="ssh_key_import_error_not_an_ssh_key_message">Il file selezionato non sembra essere una chiave privata SSH.</string>
<string name="ssh_key_success_dialog_title">Chiave SSH importata</string>
<string name="ssh_key_error_dialog_title">Errore di importazione della chiave</string>
<string name="ssh_key_error_dialog_text">Messaggio : \n</string>
<string name="pref_recursive_filter">Filtro ricorsivo</string>
<string name="pref_recursive_filter_hint">Trova ricorsivamente le password della directory corrente.</string>
<string name="pref_recursive_filter_title">Filtro ricorsivo</string>
<string name="pref_recursive_filter_summary">Trova ricorsivamente le password della directory corrente.</string>
<string name="pref_sort_order_title">Ordine password</string>
<string name="pref_folder_first_sort_order">Prima le cartelle</string>
<string name="pref_file_first_sort_order">Prima i file</string>
<string name="pref_type_independent_sort_order">Tipo indipendente</string>
<string name="pref_recently_used_sort_order">Usato di recente</string>
<string name="pref_autofill_title">Auto-compilazione</string>
<string name="pref_category_autofill_title">Auto-compilazione</string>
<string name="pref_autofill_enable_title">Abilita Auto-Compilazione</string>
<string name="pref_misc_title">Varie</string>
<string name="pref_category_misc_title">Varie</string>
<string name="pref_clear_clipboard_title">Cancella 20 volte gli appunti</string>
<string name="pref_clear_clipboard_hint">Archivia i numeri consecutivi negli appunti per 20 volte. Utile sui telefoni Samsung che presentano la cronologia degli appunti.</string>
<string name="pref_clear_clipboard_summary">Archivia i numeri consecutivi negli appunti per 20 volte. Utile sui telefoni Samsung che presentano la cronologia degli appunti.</string>
<string name="pref_git_delete_repo_summary">Elimina repository locale (nascosta)</string>
<string name="pref_external_repository">Repository Esterna</string>
<string name="pref_external_repository_title">Repository Esterna</string>
<string name="pref_external_repository_summary">Usa una repository di password esterna</string>
<string name="pref_select_external_repository">Seleziona repository esterna</string>
<string name="pref_select_external_repository_title">Seleziona repository esterna</string>
<string name="prefs_export_passwords_title">Esporta password</string>
<string name="prefs_export_passwords_summary">Esporta le password crittografate ad una directory esterna</string>
<string name="prefs_version">Versione</string>
<!-- PasswordGenerator fragment -->
<string name="pwgen_title">Genera Password</string>
<string name="pwgen_generate">Genera</string>
@ -151,12 +150,12 @@
<string name="xkpwgen_custom_dict_imported">Lista di parole personalizzata: %1$s</string>
<string name="xkpwgen_builder_error">Il dizionario selezionato non contiene abbastanza parole della data lunghezza %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="xkpwgen_pref_gentype_title">Tipo di generatore di password</string>
<string name="xkpwgen_pref_custom_dict_title">Lista di parole personalizzata</string>
<string name="xkpwgen_pref_custom_dict_summary_on">Usando file di elenco di parole personalizzati</string>
<string name="xkpwgen_pref_custom_dict_summary_off">Usando liste di parole integrate</string>
<string name="xkpwgen_pref_custom_dict_picker_title">File di elenco di parole personalizzato</string>
<string name="xkpwgen_pref_custom_dict_picker_summary">Tocca per selezionare un file di lista di parole personalizzato contenente una parola per riga</string>
<string name="pref_password_generator_type_title">Tipo di generatore di password</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Lista di parole personalizzata</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Usando file di elenco di parole personalizzati</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Usando liste di parole integrate</string>
<string name="pref_xkpwgen_custom_dict_picker_title">File di elenco di parole personalizzato</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Tocca per selezionare un file di lista di parole personalizzato contenente una parola per riga</string>
<!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Frase Segreta</string>
<string name="ssh_keygen_generate">Genera</string>
@ -196,7 +195,7 @@
<string name="show_extra_content_pref_summary">Controlla la visibilità del contenuto extra una volta decrittografato.</string>
<string name="pwd_generate_button">Genera</string>
<string name="refresh_list">Aggiorna elenco</string>
<string name="no_repo_selected">Nessuna repository esterna selezionata</string>
<string name="pref_select_external_repository_summary_no_repo_selected">Nessuna repository esterna selezionata</string>
<string name="send_plaintext_password_to">Invia password come testo semplice usando…</string>
<string name="app_icon_hint">Icona app</string>
<!-- Oreo Autofill -->
@ -248,10 +247,10 @@
<string name="biometric_prompt_title">Richiesta Biometrica</string>
<string name="biometric_auth_error">Autenticazione non riuscita</string>
<string name="biometric_auth_error_reason">Autenticazione non riuscita: %s</string>
<string name="biometric_auth_title">Abilita autenticazione biometrica</string>
<string name="biometric_auth_summary">Quando abilitata, il Password Store ti chiederà la tua impronta digitale al lancio dell\'app</string>
<string name="biometric_auth_summary_error">L\'hardware delle impronte digitali non è accessibile o mancante</string>
<string name="ssh_openkeystore_clear_keyid">Elimina l\'ID della Chiave SSH di OpenKeystore memorizzato</string>
<string name="pref_biometric_auth_title">Abilita autenticazione biometrica</string>
<string name="pref_biometric_auth_summary">Quando abilitata, il Password Store ti chiederà la tua impronta digitale al lancio dell\'app</string>
<string name="pref_biometric_auth_summary_error">L\'hardware delle impronte digitali non è accessibile o mancante</string>
<string name="pref_title_openkeystore_clear_keyid">Elimina l\'ID della Chiave SSH di OpenKeystore memorizzato</string>
<string name="access_sdcard_text">La posizione dell\'archiviazione nella tua Scheda SD o Archiviazione Interna, ma l\'app non ha i permessi per accedervi.</string>
<string name="your_public_key">La tua chiave pubblica</string>
<string name="error_generate_ssh_key">Errore provando a generare la chiave-ssh</string>
@ -264,16 +263,15 @@
<string name="message_error_destination_outside_repo">La destinazione deve essere nella repository</string>
<string name="message_rename_folder">Inserire destinazione per %1$s</string>
<string name="button_create">Crea</string>
<string name="pref_search_on_start">Apri ricerca all\'avvio</string>
<string name="pref_search_on_start_hint">Apri la barra di ricerca al lancio dell\'app</string>
<string name="password_generator_category_title">Generatore di Password</string>
<string name="pref_search_on_start_title">Apri ricerca all\'avvio</string>
<string name="pref_search_on_start_summary">Apri la barra di ricerca al lancio dell\'app</string>
<string name="tap_clear_clipboard">Tocca qui per cancellare gli appunti</string>
<string name="clone_git_repo">La repository deve essere clonata prima di sincronizzare le modifiche.</string>
<string name="theme_title">Tema dell\'App</string>
<string name="theme_light">Chiaro</string>
<string name="theme_dark">Scuro</string>
<string name="theme_battery_saver">Impostato dal Risparmio Energetico</string>
<string name="theme_follow_system">Predefinito del sistema</string>
<string name="pref_app_theme_title">Tema dell\'App</string>
<string name="pref_app_theme_value_light">Chiaro</string>
<string name="pref_app_theme_value_dark">Scuro</string>
<string name="pref_app_theme_value_battery_saver">Impostato dal Risparmio Energetico</string>
<string name="pref_app_theme_value_follow_system">Predefinito del sistema</string>
<string name="connection_mode_ssh_key">Chiave SSH</string>
<string name="connection_mode_basic_authentication">Password</string>
<string name="git_server_config_save_success">Configurazione correttamente salvata</string>
@ -353,7 +351,7 @@
<!-- Proxy configuration activity -->
<string name="proxy_hostname">Nome host del proxy</string>
<string name="port">Porta</string>
<string name="pref_proxy_settings">Impostazioni proxy HTTP(S)</string>
<string name="pref_edit_proxy_settings">Impostazioni proxy HTTP(S)</string>
<string name="invalid_proxy_url">URL non valido</string>
<string name="oreo_autofill_password_fill_and_conditional_save_support">Compila e salva le password (il salvataggio necessita che nessun servizio di accessibilità sia abilitato)</string>
<string name="clear_saved_host_key">Cancella la chiave host salvata</string>

View file

@ -93,43 +93,42 @@
<string name="share_as_plaintext">Compartilhar como texto</string>
<string name="last_changed">Última alteração %s</string>
<!-- Preferences -->
<string name="pref_repository_title">Repositório</string>
<string name="pref_edit_server_info">Editar configurações do servidor Git</string>
<string name="pref_category_repository_title">Repositório</string>
<string name="pref_edit_git_server_settings">Editar configurações do servidor Git</string>
<string name="pref_edit_git_config">Configuração local do Git &amp; utilitários</string>
<string name="pref_ssh_title">Importar chave SSH</string>
<string name="pref_import_ssh_key_title">Importar chave SSH</string>
<string name="pref_ssh_keygen_title">Gerar um par de chave SSH</string>
<string name="pref_ssh_see_key_title">Ver a chave SSH pública gerada</string>
<string name="pref_git_delete_repo">Excluir repositório</string>
<string name="pref_git_delete_repo_title">Excluir repositório</string>
<string name="pref_dialog_delete_title">Limpar repositório</string>
<string name="pref_category_general_title">Geral</string>
<string name="pref_category_title_passwords">Senhas</string>
<string name="pref_category_passwords_title">Senhas</string>
<string name="pref_clipboard_timeout_title">Tempo limite de cópia da senha</string>
<string name="pref_clipboard_timeout_summary">Definir o tempo (em segundos) que a senha está na área de transferência. 0 significa para sempre. Valor atual: %1$s</string>
<string name="pref_copy_title">Copiar senha automaticamente</string>
<string name="pref_copy_dialog_title">Automaticamente copie a senha para a área de transferência após a descriptografia ser bem sucedida.</string>
<string name="pref_copy_summary">Automaticamente copie a senha para a área de transferência após a descriptografia ser bem sucedida.</string>
<string name="ssh_key_import_error_not_an_ssh_key_message">O arquivo selecionado não parece ser uma chave SSH privada.</string>
<string name="ssh_key_success_dialog_title">Chave SSH importada</string>
<string name="ssh_key_error_dialog_title">Erro ao importar chave</string>
<string name="ssh_key_error_dialog_text">Mensagem : \n</string>
<string name="pref_recursive_filter">Filtragem recursiva</string>
<string name="pref_recursive_filter_hint">Encontrar senhas do diretório corrente recursivamente.</string>
<string name="pref_recursive_filter_title">Filtragem recursiva</string>
<string name="pref_recursive_filter_summary">Encontrar senhas do diretório corrente recursivamente.</string>
<string name="pref_sort_order_title">Ordenação da Senha</string>
<string name="pref_folder_first_sort_order">Pastas primeiro</string>
<string name="pref_file_first_sort_order">Arquivos primeiro</string>
<string name="pref_type_independent_sort_order">Tipo independente</string>
<string name="pref_recently_used_sort_order">Usado recentemente</string>
<string name="pref_autofill_title">Preenchimento Automático</string>
<string name="pref_category_autofill_title">Preenchimento Automático</string>
<string name="pref_autofill_enable_title">Ativar preenchimento automático</string>
<string name="pref_misc_title">Outros</string>
<string name="pref_category_misc_title">Outros</string>
<string name="pref_clear_clipboard_title">Limpar área de transferência 20 vezes</string>
<string name="pref_clear_clipboard_hint">Armazene números consecutivos na área de transferência 20 vezes. Útil em telefones Samsung que apresentam o histórico da área de transferência.</string>
<string name="pref_clear_clipboard_summary">Armazene números consecutivos na área de transferência 20 vezes. Útil em telefones Samsung que apresentam o histórico da área de transferência.</string>
<string name="pref_git_delete_repo_summary">Exclui o repositório local (oculto)</string>
<string name="pref_external_repository">Repositório externo</string>
<string name="pref_external_repository_title">Repositório externo</string>
<string name="pref_external_repository_summary">Use um repositório de senha externo</string>
<string name="pref_select_external_repository">Selecionar repositório externo</string>
<string name="pref_select_external_repository_title">Selecionar repositório externo</string>
<string name="prefs_export_passwords_title">Exportar senhas</string>
<string name="prefs_export_passwords_summary">Exporta as senhas criptografadas para um diretório externo</string>
<string name="prefs_version">Versão</string>
<!-- PasswordGenerator fragment -->
<string name="pwgen_title">Gerar Senha</string>
<string name="pwgen_generate">Gerar</string>
@ -151,12 +150,12 @@
<string name="xkpwgen_custom_dict_imported">Lista de palavras personalizada: %1$s</string>
<string name="xkpwgen_builder_error">O dicionário selecionado não contém palavras suficientes de tamanho %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="xkpwgen_pref_gentype_title">Tipo de gerador de senha</string>
<string name="xkpwgen_pref_custom_dict_title">Lista de palavras personalizadas</string>
<string name="xkpwgen_pref_custom_dict_summary_on">Usando um arquivo de Lista de Palavras</string>
<string name="xkpwgen_pref_custom_dict_summary_off">Usando o arquivo de palavras embutido</string>
<string name="xkpwgen_pref_custom_dict_picker_title">Lista de palavras personalizadas</string>
<string name="xkpwgen_pref_custom_dict_picker_summary">Toque para escolher um arquivo personalizado de lista de palavras contendo uma palavra por linha</string>
<string name="pref_password_generator_type_title">Tipo de gerador de senha</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Lista de palavras personalizadas</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Usando um arquivo de Lista de Palavras</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Usando o arquivo de palavras embutido</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Lista de palavras personalizadas</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Toque para escolher um arquivo personalizado de lista de palavras contendo uma palavra por linha</string>
<!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Frase Secreta</string>
<string name="ssh_keygen_generate">Gerar</string>
@ -196,7 +195,7 @@
<string name="show_extra_content_pref_summary">Controlar a visibilidade do conteúdo extra uma vez descriptografado.</string>
<string name="pwd_generate_button">Gerar</string>
<string name="refresh_list">Atualizar lista</string>
<string name="no_repo_selected">Nenhum repositório externo selecionado</string>
<string name="pref_select_external_repository_summary_no_repo_selected">Nenhum repositório externo selecionado</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 -->
@ -247,10 +246,10 @@
<string name="biometric_prompt_title">Confirmação Biométrica</string>
<string name="biometric_auth_error">Falha de autenticação</string>
<string name="biometric_auth_error_reason">Falha de autenticação: %s</string>
<string name="biometric_auth_title">Ativar autenticação biométrica</string>
<string name="biometric_auth_summary">Quando ativado, o Password Store irá pedir a sua impressão digital ao iniciar o aplicativo</string>
<string name="biometric_auth_summary_error">Hardware de impressão digital não acessível ou ausente</string>
<string name="ssh_openkeystore_clear_keyid">Limpar ID de chave SSH lembrada do OpenKeystore</string>
<string name="pref_biometric_auth_title">Ativar autenticação biométrica</string>
<string name="pref_biometric_auth_summary">Quando ativado, o Password Store irá pedir a sua impressão digital ao iniciar o aplicativo</string>
<string name="pref_biometric_auth_summary_error">Hardware de impressão digital não acessível ou ausente</string>
<string name="pref_title_openkeystore_clear_keyid">Limpar ID de chave SSH lembrada do OpenKeystore</string>
<string name="access_sdcard_text">O local do armazenamento está em seu cartão SD ou armazenamento interno, mas o aplicativo não tem permissão para acessá-lo.</string>
<string name="your_public_key">Sua chave pública</string>
<string name="error_generate_ssh_key">Erro ao tentar gerar a chave SSH</string>
@ -263,16 +262,15 @@
<string name="message_error_destination_outside_repo">O destino deve estar dentro do repositório</string>
<string name="message_rename_folder">Insira o destino para %1$s</string>
<string name="button_create">Criar</string>
<string name="pref_search_on_start">Abrir pesquisa ao inicializar</string>
<string name="pref_search_on_start_hint">Abrir barra de pesquisa quando o aplicativo for iniciado</string>
<string name="password_generator_category_title">Gerador de Senha</string>
<string name="pref_search_on_start_title">Abrir pesquisa ao inicializar</string>
<string name="pref_search_on_start_summary">Abrir barra de pesquisa quando o aplicativo for iniciado</string>
<string name="tap_clear_clipboard">Toque aqui para limpar a área de transferência</string>
<string name="clone_git_repo">O repositório deve ser clonado antes de sincronizar as alterações.</string>
<string name="theme_title">Tema do aplicativo</string>
<string name="theme_light">Claro</string>
<string name="theme_dark">Escuro</string>
<string name="theme_battery_saver">Configurado pela Economia de bateria</string>
<string name="theme_follow_system">Padrão do sistema</string>
<string name="pref_app_theme_title">Tema do aplicativo</string>
<string name="pref_app_theme_value_light">Claro</string>
<string name="pref_app_theme_value_dark">Escuro</string>
<string name="pref_app_theme_value_battery_saver">Configurado pela Economia de bateria</string>
<string name="pref_app_theme_value_follow_system">Padrão do sistema</string>
<string name="connection_mode_ssh_key">Chave SSH</string>
<string name="connection_mode_basic_authentication">Senha</string>
<string name="git_server_config_save_success">Configuração salva com sucesso</string>

View file

@ -97,43 +97,42 @@
<string name="share_as_plaintext">Поделиться в открытом виде</string>
<string name="last_changed">Последние изменение %s</string>
<!-- Preferences -->
<string name="pref_repository_title">Репозиторий</string>
<string name="pref_edit_server_info">Изменить настройки сервера Git</string>
<string name="pref_category_repository_title">Репозиторий</string>
<string name="pref_edit_git_server_settings">Изменить настройки сервера Git</string>
<string name="pref_edit_git_config">Конфигурация локального Git</string>
<string name="pref_ssh_title">Импортировать SSH ключ</string>
<string name="pref_import_ssh_key_title">Импортировать SSH ключ</string>
<string name="pref_ssh_keygen_title">Сгенерировать пару SSH ключей</string>
<string name="pref_ssh_see_key_title">Просмотреть публичный SSH ключ</string>
<string name="pref_git_delete_repo">Удалить репозиторий</string>
<string name="pref_git_delete_repo_title">Удалить репозиторий</string>
<string name="pref_dialog_delete_title">Очистить репозиторий</string>
<string name="pref_category_general_title">Общие</string>
<string name="pref_category_title_passwords">Пароли</string>
<string name="pref_category_passwords_title">Пароли</string>
<string name="pref_clipboard_timeout_title">Срок хранения пароля в буфере обмена</string>
<string name="pref_clipboard_timeout_summary">Установите время (в секундах), которое вы хотите, чтобы пароль был в буфере обмена. 0 означает навсегда. Текущее значение: %1$s</string>
<string name="pref_copy_title">Автоматически копировать пароль</string>
<string name="pref_copy_dialog_title">Автоматически копировать пароль в буфер обмена после успешного расшифрования</string>
<string name="pref_copy_summary">Автоматически копировать пароль в буфер обмена после успешного расшифрования</string>
<string name="ssh_key_import_error_not_an_ssh_key_message">Выбранный файл не похож на приватный SSH-ключ.</string>
<string name="ssh_key_success_dialog_title">SSH ключ импортирован</string>
<string name="ssh_key_error_dialog_title">Ошибка импорта ключа</string>
<string name="ssh_key_error_dialog_text">Сообщение: \n</string>
<string name="pref_recursive_filter">Рекурсивная фильтрация</string>
<string name="pref_recursive_filter_hint">Рекурсивный поиск паролей в текущей директории</string>
<string name="pref_recursive_filter_title">Рекурсивная фильтрация</string>
<string name="pref_recursive_filter_summary">Рекурсивный поиск паролей в текущей директории</string>
<string name="pref_sort_order_title">Порядок сортировки паролей</string>
<string name="pref_folder_first_sort_order">Сначала папки</string>
<string name="pref_file_first_sort_order">Сначала файлы</string>
<string name="pref_type_independent_sort_order">Типонезависимый</string>
<string name="pref_recently_used_sort_order">Недавно использованные</string>
<string name="pref_autofill_title">Автозаполнение</string>
<string name="pref_category_autofill_title">Автозаполнение</string>
<string name="pref_autofill_enable_title">Включить автозаполнение</string>
<string name="pref_misc_title">Другое</string>
<string name="pref_category_misc_title">Другое</string>
<string name="pref_clear_clipboard_title">Очистить буфер 20 раз</string>
<string name="pref_clear_clipboard_hint">Вставлять чепуху в буфер обмена 20 раз вместо одного. Полезно на некоторых моделях телефонов с запоминанием истории буфера обмена</string>
<string name="pref_clear_clipboard_summary">Вставлять чепуху в буфер обмена 20 раз вместо одного. Полезно на некоторых моделях телефонов с запоминанием истории буфера обмена</string>
<string name="pref_git_delete_repo_summary">Удалить локальный (скрытый) репозиторий</string>
<string name="pref_external_repository">Внешний репозиторий</string>
<string name="pref_external_repository_title">Внешний репозиторий</string>
<string name="pref_external_repository_summary">Использовать внешний репозиторий</string>
<string name="pref_select_external_repository">Выбрать внешний репозиторий</string>
<string name="pref_select_external_repository_title">Выбрать внешний репозиторий</string>
<string name="prefs_export_passwords_title">Экспортировать пароли</string>
<string name="prefs_export_passwords_summary">Экспортировать пароли в открытом виде во внешнее хранилище</string>
<string name="prefs_version">Версия</string>
<!-- PasswordGenerator fragment -->
<string name="pwgen_title">Сгенерировать пароль</string>
<string name="pwgen_generate">Сгенерировать</string>
@ -155,12 +154,12 @@
<string name="xkpwgen_custom_dict_imported">Пользовательский список слов: %1$s</string>
<string name="xkpwgen_builder_error">Выбранный словарь не содержит достаточного количества слова заданной длинны %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="xkpwgen_pref_gentype_title">Тип генератора паролей</string>
<string name="xkpwgen_pref_custom_dict_title">Пользовательский список слов</string>
<string name="xkpwgen_pref_custom_dict_summary_on">Использовать файл списка слов созданный пользователем</string>
<string name="xkpwgen_pref_custom_dict_summary_off">Использовать встроенный список слов</string>
<string name="xkpwgen_pref_custom_dict_picker_title">Файл пользовательского списка слов</string>
<string name="xkpwgen_pref_custom_dict_picker_summary">Нажмите чтобы выбрать файл пользовательского списка слов содержащий одно слово на строку</string>
<string name="pref_password_generator_type_title">Тип генератора паролей</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Пользовательский список слов</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Использовать файл списка слов созданный пользователем</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Использовать встроенный список слов</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Файл пользовательского списка слов</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Нажмите чтобы выбрать файл пользовательского списка слов содержащий одно слово на строку</string>
<!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Пароль</string>
<string name="ssh_keygen_generate">Сгенерировать</string>
@ -200,7 +199,7 @@
<string name="show_extra_content_pref_summary">Видимость поля дополнительной информации после расшифрования</string>
<string name="pwd_generate_button">Сгенерировать</string>
<string name="refresh_list">Обновить список</string>
<string name="no_repo_selected">Внешний репозиторий не выбран</string>
<string name="pref_select_external_repository_summary_no_repo_selected">Внешний репозиторий не выбран</string>
<string name="send_plaintext_password_to">Поделиться паролем в открытом виде с помощью</string>
<string name="app_icon_hint">Иконка приложения</string>
<!-- Oreo Autofill -->
@ -251,10 +250,10 @@
<string name="biometric_prompt_title">Запрос биометрии</string>
<string name="biometric_auth_error">Ошибка авторизации</string>
<string name="biometric_auth_error_reason">Ошибка аутентификации: %s</string>
<string name="biometric_auth_title">Включить биометрическую аутентификацию</string>
<string name="biometric_auth_summary">Когда ключено, Password Store будет запрашивать ваш опечаток пальца при каждом запуске приложения</string>
<string name="biometric_auth_summary_error">Сенсор отпечатка пальца не доступен или отсутствует</string>
<string name="ssh_openkeystore_clear_keyid">Очистить сохраненный SSH Key идентификатор OpenKystortore</string>
<string name="pref_biometric_auth_title">Включить биометрическую аутентификацию</string>
<string name="pref_biometric_auth_summary">Когда ключено, Password Store будет запрашивать ваш опечаток пальца при каждом запуске приложения</string>
<string name="pref_biometric_auth_summary_error">Сенсор отпечатка пальца не доступен или отсутствует</string>
<string name="pref_title_openkeystore_clear_keyid">Очистить сохраненный SSH Key идентификатор OpenKystortore</string>
<string name="access_sdcard_text">Хранилище расположено на вашей SD-карте или во внутреннем хранилище, но у приложения нет разрешения на доступ к нему.</string>
<string name="your_public_key">Ваш публичный ключ</string>
<string name="error_generate_ssh_key">Возникла ошибка при попытке генерации ssh ключа</string>
@ -267,16 +266,15 @@
<string name="message_error_destination_outside_repo">Путь должен указывать на область внутри репозитория</string>
<string name="message_rename_folder">Введите адрес назначения для %1$s</string>
<string name="button_create">Создать</string>
<string name="pref_search_on_start">Открыть поиск на старте</string>
<string name="pref_search_on_start_hint">Открыть панель поиска при запуске приложения</string>
<string name="password_generator_category_title">Генератор паролей</string>
<string name="pref_search_on_start_title">Открыть поиск на старте</string>
<string name="pref_search_on_start_summary">Открыть панель поиска при запуске приложения</string>
<string name="tap_clear_clipboard">Нажмите здесь чтобы очистить буфер обмена</string>
<string name="clone_git_repo">Для синхронизации изменений клонируйте git репозиторий</string>
<string name="theme_title">Тема приложения</string>
<string name="theme_light">Светлая</string>
<string name="theme_dark">Темная</string>
<string name="theme_battery_saver">Задается экономией батареи</string>
<string name="theme_follow_system">Системная</string>
<string name="pref_app_theme_title">Тема приложения</string>
<string name="pref_app_theme_value_light">Светлая</string>
<string name="pref_app_theme_value_dark">Темная</string>
<string name="pref_app_theme_value_battery_saver">Задается экономией батареи</string>
<string name="pref_app_theme_value_follow_system">Системная</string>
<string name="connection_mode_ssh_key">SSH ключ</string>
<string name="connection_mode_basic_authentication">Пароль</string>
<string name="git_server_config_save_success">Конфигурация успешно сохранена</string>

View file

@ -5,9 +5,9 @@
<resources>
<string-array name="app_theme_options">
<item>@string/theme_light</item>
<item>@string/theme_dark</item>
<item>@string/theme_follow_system</item>
<item>@string/pref_app_theme_value_light</item>
<item>@string/pref_app_theme_value_dark</item>
<item>@string/pref_app_theme_value_follow_system</item>
</string-array>
<string-array name="app_theme_values">
<item>light</item>

View file

@ -41,9 +41,9 @@
<item>directory</item>
</string-array>
<string-array name="app_theme_options">
<item>@string/theme_light</item>
<item>@string/theme_dark</item>
<item>@string/theme_battery_saver</item>
<item>@string/pref_app_theme_value_light</item>
<item>@string/pref_app_theme_value_dark</item>
<item>@string/pref_app_theme_value_battery_saver</item>
</string-array>
<string-array name="app_theme_values">
<item>light</item>

View file

@ -110,43 +110,43 @@
<string name="last_changed">Last changed %s</string>
<!-- Preferences -->
<string name="pref_repository_title">Repository</string>
<string name="pref_edit_server_info">Edit Git server settings</string>
<string name="pref_category_repository_title">Repository</string>
<string name="pref_edit_git_server_settings">Edit Git server settings</string>
<string name="pref_edit_git_config">Local Git config &amp; utilities</string>
<string name="pref_ssh_title">Import SSH key</string>
<string name="pref_import_ssh_key_title">Import SSH key</string>
<string name="pref_ssh_keygen_title">Generate SSH key pair</string>
<string name="pref_ssh_see_key_title">View generated public SSH key</string>
<string name="pref_git_delete_repo">Delete repository</string>
<string name="pref_git_delete_repo_title">Delete repository</string>
<string name="pref_dialog_delete_title">Clear repository</string>
<string name="pref_category_general_title">General</string>
<string name="pref_category_title_passwords">Passwords</string>
<string name="pref_category_passwords_title">Passwords</string>
<string name="pref_clipboard_timeout_title">Password copy timeout</string>
<string name="pref_clipboard_timeout_summary">Set the time (in seconds) you want the password to be in clipboard. 0 means forever. Current value: %1$s</string>
<string name="pref_copy_title">Automatically copy password</string>
<string name="pref_copy_dialog_title">Automatically copy the password to the clipboard after decryption was successful.</string>
<string name="pref_copy_summary">Automatically copy the password to the clipboard after decryption was successful.</string>
<string name="ssh_key_import_error_not_an_ssh_key_message">Selected file does not appear to be an SSH private key.</string>
<string name="ssh_key_success_dialog_title">SSH-key imported</string>
<string name="ssh_key_error_dialog_title">Key import error</string>
<string name="ssh_key_error_dialog_text">Message : \n</string>
<string name="pref_recursive_filter">Recursive filtering</string>
<string name="pref_recursive_filter_hint">Recursively find passwords of the current directory.</string>
<string name="pref_recursive_filter_title">Recursive filtering</string>
<string name="pref_recursive_filter_summary">Recursively find passwords of the current directory.</string>
<string name="pref_sort_order_title">Password sort order</string>
<string name="pref_folder_first_sort_order">Folders first</string>
<string name="pref_file_first_sort_order">Files first</string>
<string name="pref_type_independent_sort_order">Type independent</string>
<string name="pref_recently_used_sort_order">Recently used</string>
<string name="pref_autofill_title">Autofill</string>
<string name="pref_category_autofill_title">Autofill</string>
<string name="pref_autofill_enable_title">Enable Autofill</string>
<string name="pref_misc_title">Misc</string>
<string name="pref_category_misc_title">Misc</string>
<string name="pref_clear_clipboard_title">Clear clipboard 20 times</string>
<string name="pref_clear_clipboard_hint">Store consecutive numbers in the clipboard 20 times. Useful on Samsung phones that feature clipboard history.</string>
<string name="pref_clear_clipboard_summary">Store consecutive numbers in the clipboard 20 times. Useful on Samsung phones that feature clipboard history.</string>
<string name="pref_git_delete_repo_summary">Deletes local (hidden) repository</string>
<string name="pref_external_repository">External repository</string>
<string name="pref_external_repository_title">External repository</string>
<string name="pref_external_repository_summary">Use an external password repository</string>
<string name="pref_select_external_repository">Select external repository</string>
<string name="pref_select_external_repository_title">Select external repository</string>
<string name="pref_select_external_repository_summary_no_repo_selected">No external repository selected</string>
<string name="prefs_export_passwords_title">Export passwords</string>
<string name="prefs_export_passwords_summary">Exports the encrypted passwords to an external directory</string>
<string name="prefs_version">Version</string>
<!-- PasswordGenerator fragment -->
<string name="pwgen_title">Generate Password</string>
@ -171,12 +171,12 @@
<string name="xkpwgen_builder_error">Selected dictionary does not contain enough words of given length %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="xkpwgen_pref_gentype_title">Password generator type</string>
<string name="xkpwgen_pref_custom_dict_title">Custom wordlist</string>
<string name="xkpwgen_pref_custom_dict_summary_on">Using custom wordlist file</string>
<string name="xkpwgen_pref_custom_dict_summary_off">Using built-in wordlist</string>
<string name="xkpwgen_pref_custom_dict_picker_title">Custom worldlist file</string>
<string name="xkpwgen_pref_custom_dict_picker_summary">Tap to pick a custom wordlist file containing one word per line</string>
<string name="pref_password_generator_type_title">Password generator type</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Custom wordlist</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Using custom wordlist file</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Using built-in wordlist</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Custom worldlist file</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Tap to pick a custom wordlist file containing one word per line</string>
<!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Passphrase</string>
@ -220,7 +220,6 @@
<string name="show_extra_content_pref_summary">Control the visibility of the extra content once decrypted.</string>
<string name="pwd_generate_button">Generate</string>
<string name="refresh_list">Refresh list</string>
<string name="no_repo_selected">No external repository selected</string>
<string name="send_plaintext_password_to">Send password as plaintext using…</string>
<string name="app_icon_hint">App icon</string>
@ -271,14 +270,15 @@
<string name="git_head_missing">Unable to locate HEAD</string>
<string name="sdcard_root_warning_title">SD-Card root selected</string>
<string name="sdcard_root_warning_message">You have selected the root of your sdcard for the store. This is extremely dangerous and you will lose your data as its content will, eventually, be deleted</string>
<string name="sdcard_root_warning_remove_everything">Remove everything</string>
<string name="git_abort_and_push_title">Abort and Push</string>
<string name="biometric_prompt_title">Biometric Prompt</string>
<string name="biometric_auth_error">Authentication failure</string>
<string name="biometric_auth_error_reason">Authentication failure: %s</string>
<string name="biometric_auth_title">Enable biometric authentication</string>
<string name="biometric_auth_summary">When enabled, Password Store will prompt you for your fingerprint when launching the app</string>
<string name="biometric_auth_summary_error">Fingerprint hardware not accessible or missing</string>
<string name="ssh_openkeystore_clear_keyid">Clear remembered OpenKeystore SSH Key ID</string>
<string name="pref_biometric_auth_title">Enable biometric authentication</string>
<string name="pref_biometric_auth_summary">When enabled, Password Store will prompt you for your fingerprint when launching the app</string>
<string name="pref_biometric_auth_summary_error">Fingerprint hardware not accessible or missing</string>
<string name="pref_title_openkeystore_clear_keyid">Clear remembered OpenKeystore SSH Key ID</string>
<string name="access_sdcard_text">The store location is in your SD Card or Internal storage, but the app does not have permission to access it.</string>
<string name="your_public_key">Your public key</string>
<string name="error_generate_ssh_key">Error while trying to generate the ssh-key</string>
@ -291,16 +291,15 @@
<string name="message_error_destination_outside_repo">Destination must be within the repository</string>
<string name="message_rename_folder">Enter destination for %1$s</string>
<string name="button_create">Create</string>
<string name="pref_search_on_start">Open search on start</string>
<string name="pref_search_on_start_hint">Open search bar when app is launched</string>
<string name="password_generator_category_title">Password Generator</string>
<string name="pref_search_on_start_title">Open search on start</string>
<string name="pref_search_on_start_summary">Open search bar when app is launched</string>
<string name="tap_clear_clipboard">Tap here to clear clipboard</string>
<string name="clone_git_repo">The repository must be cloned before syncing changes.</string>
<string name="theme_title">App theme</string>
<string name="theme_light">Light</string>
<string name="theme_dark">Dark</string>
<string name="theme_battery_saver">Set by Battery Saver</string>
<string name="theme_follow_system">System default</string>
<string name="pref_app_theme_title">App theme</string>
<string name="pref_app_theme_value_light">Light</string>
<string name="pref_app_theme_value_dark">Dark</string>
<string name="pref_app_theme_value_battery_saver">Set by Battery Saver</string>
<string name="pref_app_theme_value_follow_system">System default</string>
<string name="connection_mode_ssh_key">SSH key</string>
<string name="connection_mode_basic_authentication">Password</string>
<string name="connection_mode_openkeychain" translatable="false">OpenKeychain</string>
@ -389,7 +388,7 @@
<!-- Proxy configuration activity -->
<string name="proxy_hostname">Proxy hostname</string>
<string name="port">Port</string>
<string name="pref_proxy_settings">HTTP(S) proxy settings</string>
<string name="pref_edit_proxy_settings">HTTP(S) proxy settings</string>
<string name="invalid_proxy_url">Invalid URL</string>
<string name="oreo_autofill_password_fill_and_conditional_save_support">Fill and save passwords (saving requires that no accessibility services are enabled)</string>
<string name="clear_saved_host_key">Clear saved host key</string>

View file

@ -1,174 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
~ SPDX-License-Identifier: GPL-3.0-only
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="@string/pref_autofill_title">
<SwitchPreferenceCompat
app:defaultValue="true"
app:key="autofill_enable"
app:title="@string/pref_autofill_enable_title" />
<ListPreference
app:defaultValue="file"
app:entries="@array/oreo_autofill_directory_structure_entries"
app:entryValues="@array/oreo_autofill_directory_structure_values"
app:key="oreo_autofill_directory_structure"
app:title="@string/oreo_autofill_preference_directory_structure"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
app:key="oreo_autofill_default_username"
app:summary="@string/preference_default_username_summary"
app:title="@string/preference_default_username_title" />
<EditTextPreference
app:key="oreo_autofill_custom_public_suffixes"
app:summary="@string/preference_custom_public_suffixes_summary"
app:title="@string/preference_custom_public_suffixes_title" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/pref_repository_title">
<Preference
app:key="git_server_info"
app:title="@string/pref_edit_server_info" />
<Preference
app:key="proxy_settings"
app:title="@string/pref_proxy_settings" />
<Preference
app:key="git_config"
app:title="@string/pref_edit_git_config" />
<Preference
app:key="ssh_key"
app:title="@string/pref_ssh_title" />
<Preference
app:key="ssh_keygen"
app:title="@string/pref_ssh_keygen_title" />
<Preference app:key="clear_saved_pass" />
<Preference
app:key="ssh_openkeystore_clear_keyid"
app:title="@string/ssh_openkeystore_clear_keyid" />
<Preference
app:key="ssh_see_key"
app:title="@string/pref_ssh_see_key_title" />
<Preference
app:key="git_delete_repo"
app:summary="@string/pref_git_delete_repo_summary"
app:title="@string/pref_git_delete_repo" />
<CheckBoxPreference
app:key="git_external"
app:summary="@string/pref_external_repository_summary"
app:title="@string/pref_external_repository" />
<Preference
app:dependency="git_external"
app:key="pref_select_external"
app:title="@string/pref_select_external_repository" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/password_generator_category_title">
<ListPreference
app:defaultValue="classic"
app:entries="@array/pwgen_provider_labels"
app:entryValues="@array/pwgen_provider_values"
app:key="pref_key_pwgen_type"
app:persistent="true"
app:title="@string/xkpwgen_pref_gentype_title"
app:useSimpleSummaryProvider="true" />
<CheckBoxPreference
app:key="pref_key_is_custom_dict"
app:summaryOff="@string/xkpwgen_pref_custom_dict_summary_off"
app:summaryOn="@string/xkpwgen_pref_custom_dict_summary_on"
app:title="@string/xkpwgen_pref_custom_dict_title" />
<Preference
app:dependency="pref_key_is_custom_dict"
app:key="pref_key_custom_dict"
app:summary="@string/xkpwgen_pref_custom_dict_picker_summary"
app:title="@string/xkpwgen_pref_custom_dict_picker_title" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/pref_category_general_title">
<ListPreference
android:defaultValue="@string/app_theme_def"
android:entries="@array/app_theme_options"
android:entryValues="@array/app_theme_values"
android:key="app_theme"
android:summary="%s"
android:title="@string/theme_title" />
<ListPreference
app:defaultValue="FOLDER_FIRST"
app:entries="@array/sort_order_entries"
app:entryValues="@array/sort_order_values"
app:key="sort_order"
app:persistent="true"
app:summary="%s"
app:title="@string/pref_sort_order_title" />
<CheckBoxPreference
app:defaultValue="true"
app:key="filter_recursively"
app:summary="@string/pref_recursive_filter_hint"
app:title="@string/pref_recursive_filter" />
<CheckBoxPreference
app:defaultValue="false"
app:key="search_on_start"
app:summary="@string/pref_search_on_start_hint"
app:title="@string/pref_search_on_start" />
<CheckBoxPreference
app:defaultValue="false"
app:key="show_hidden_contents"
app:persistent="true"
app:summary="@string/pref_show_hidden_summary"
app:title="@string/pref_show_hidden_title" />
<CheckBoxPreference
app:key="biometric_auth"
app:summary="@string/biometric_auth_summary"
app:title="@string/biometric_auth_title" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/pref_category_title_passwords">
<EditTextPreference
android:inputType="number"
app:defaultValue="45"
app:key="general_show_time"
app:summary="@string/pref_clipboard_timeout_summary"
app:title="@string/pref_clipboard_timeout_title" />
<CheckBoxPreference
app:defaultValue="true"
app:key="show_password"
app:summary="@string/show_password_pref_summary"
app:title="@string/show_password_pref_title" />
<CheckBoxPreference
app:defaultValue="true"
app:key="show_extra_content"
app:summary="@string/show_extra_content_pref_summary"
app:title="@string/show_extra_content_pref_title" />
<CheckBoxPreference
app:defaultValue="false"
app:dialogTitle="@string/pref_copy_dialog_title"
app:key="copy_on_decrypt"
app:summary="@string/pref_copy_dialog_title"
app:title="@string/pref_copy_title" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/pref_misc_title">
<Preference
app:key="export_passwords"
app:summary="@string/prefs_export_passwords_summary"
app:title="@string/prefs_export_passwords_title" />
<CheckBoxPreference
app:defaultValue="false"
app:key="clear_clipboard_20x"
app:summary="@string/pref_clear_clipboard_hint"
app:title="@string/pref_clear_clipboard_title" />
<CheckBoxPreference
app:defaultValue="false"
app:key="enable_debug_logging"
app:summary="@string/pref_debug_logging_summary"
app:title="@string/pref_debug_logging_title" />
</PreferenceCategory>
<PreferenceCategory>
<Preference
app:icon="@mipmap/ic_launcher"
app:key="app_version"
app:title="@string/prefs_version" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -53,6 +53,7 @@ object Dependencies {
const val jgit = "org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r"
const val kotlin_result = "com.michael-bull.kotlin-result:kotlin-result:1.1.9"
const val leakcanary = "com.squareup.leakcanary:leakcanary-android:2.5"
const val modern_android_prefs = "de.Maxr1998.android:modernpreferences:1.2.0-alpha1"
const val plumber = "com.squareup.leakcanary:plumber-android:2.5"
const val sshj = "com.hierynomus:sshj:0.30.0"
const val ssh_auth = "org.sufficientlysecure:sshauthentication-api:1.0"