mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32d235e8c7 | ||
|
|
cb982b3513 | ||
|
|
d7ed6c26dd | ||
|
|
8ff19f7e68 | ||
|
|
729e062c3a | ||
|
|
7d0340ac07 | ||
|
|
01960e74c1 | ||
|
|
8e40250985 | ||
|
|
8ae2edb61a | ||
|
|
0baa7bcbf1 | ||
|
|
fffee48918 | ||
|
|
515abb6e14 | ||
|
|
6c1c3ff87f | ||
|
|
5b65575c7a | ||
|
|
0f258fc5f8 | ||
|
|
206bc661dc | ||
|
|
d0e35b109e | ||
|
|
61769c4f20 | ||
|
|
95778ee5f4 | ||
|
|
155030fdca | ||
|
|
98237ef76c | ||
|
|
f0a7b38199 | ||
|
|
9fc5e6751b | ||
|
|
4c1630312b | ||
|
|
d397c5c996 | ||
|
|
f6c41b5a60 | ||
|
|
06eb5c01c3 | ||
|
|
7df49f91e8 | ||
|
|
96dcbb0ce7 | ||
|
|
5f828fb986 | ||
|
|
533d663938 | ||
|
|
ae788503a9 | ||
|
|
cf0acd9c73 | ||
|
|
0857f2f1cf | ||
|
|
c05d412bdb | ||
|
|
c8e0ce717d | ||
|
|
cc3485b201 | ||
|
|
81ea7080c2 | ||
|
|
76ff6f5ae0 | ||
|
|
0c0d0b7a6f | ||
|
|
ec8cf1f6b7 | ||
|
|
da44310d1b | ||
|
|
4bd9c84bb0 | ||
|
|
3b1269a770 | ||
|
|
7c986ccee8 | ||
|
|
903bad8f36 | ||
|
|
4b9577437c | ||
|
|
c316011fbc | ||
|
|
3fb1f18c22 | ||
|
|
53935058f5 | ||
|
|
a3860c9581 | ||
|
|
dc20899d26 | ||
|
|
62ac3ddb75 | ||
|
|
b792a61bf9 | ||
|
|
aae9f9e1cb | ||
|
|
d098bf5e6a | ||
|
|
b0e8a3ecd9 | ||
|
|
4efa684022 | ||
|
|
f2c8082990 | ||
|
|
1abba80045 | ||
|
|
68564a2b75 | ||
|
|
385b701b38 | ||
|
|
11c9a1d707 | ||
|
|
c5aef6b561 | ||
|
|
dfcf73cfd0 | ||
|
|
7fc9389700 | ||
|
|
d1af7349bc | ||
|
|
0fd955197d | ||
|
|
cbf33507d1 | ||
|
|
bc60a5d97e | ||
|
|
57596b2991 | ||
|
|
43b3602a52 | ||
|
|
c09ec961b8 | ||
|
|
d140b453b2 | ||
|
|
9eb42636ec | ||
|
|
ee2d663fce | ||
|
|
8e83615a22 | ||
|
|
0ff129c5ca | ||
|
|
e49858439f | ||
|
|
3df07f7f47 | ||
|
|
ff9e179593 | ||
|
|
7539fee04b | ||
|
|
71a339a58f | ||
|
|
9ef2ea016b | ||
|
|
de4936a16d | ||
|
|
574d2b8904 | ||
|
|
1f3f7634e7 | ||
|
|
3c0725baff | ||
|
|
b0e1411012 | ||
|
|
39daf4714d | ||
|
|
4706afa823 | ||
|
|
25977d389d | ||
|
|
f760110569 | ||
|
|
133e78fe97 | ||
|
|
d92e0c8620 | ||
|
|
62fdb69d6b | ||
|
|
def57c9fb2 | ||
|
|
21c9c898c3 | ||
|
|
1f03c922c2 | ||
|
|
3f6ae6bdac | ||
|
|
60615ee1eb | ||
|
|
92b0d1bfa9 | ||
|
|
237988dc1f |
13
CHANGELOG
13
CHANGELOG
@@ -1,3 +1,16 @@
|
||||
KeePassDX(2.5beta30)
|
||||
* Fix Lock after screen off (wait 1.5 seconds)
|
||||
* Upgrade autofill algorithm
|
||||
* Fix ANR during file verifications
|
||||
|
||||
KeePassDX(2.5beta29)
|
||||
* Upgrade autofill algorithm
|
||||
* Delete registered KeyFile after save new credentials
|
||||
* Fix title and username entry view refresh after an update
|
||||
* Fix database lock request (open notification always active)
|
||||
* Allow empty title in entries
|
||||
* Add expiration datetime
|
||||
|
||||
KeePassDX(2.5beta28)
|
||||
* Fix read only database
|
||||
* Upgrade to Android SDK 29
|
||||
|
||||
@@ -30,7 +30,7 @@ KeePassDX is a **free open source password manager for Android**, which helps yo
|
||||
|
||||
Yes, KeePassDX is under **free license (OSI certified)** and **without advertising**. You can have a look at its full source and check whether the encryption algorithms are implemented correctly.
|
||||
|
||||
*Note : If you access the application from a store, visual features may not be available to incentivize the contribution to the work of open source projects. These optional visuals are accessible after a donation (and a small congratulation message :) or the purchase of an extended version, but do not worry, the main features remain completely free. If you contribute to the project and you do not have access to the themes, do not hesitate to contact me at [contact@kunzisoft.com](contact@kunzisoft.com), I will give you the procedure.*
|
||||
*Note : If you access the application from a store, visual styles may not be available to encourage contribution to the work of open source projects. These optional styles are accessible after a contribution (and a congratulation message :) or the purchase of an extended version, but do not worry, the main features remain completely free. If you contribute to the project and you do not have access to the themes, do not hesitate to contact me at [contact@kunzisoft.com](contact@kunzisoft.com), I will give you the procedure.*
|
||||
|
||||
## Contributions
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ android {
|
||||
applicationId "com.kunzisoft.keepass"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 29
|
||||
versionCode = 28
|
||||
versionName = "2.5beta28"
|
||||
versionCode = 30
|
||||
versionName = "2.5beta30"
|
||||
multiDexEnabled true
|
||||
|
||||
testApplicationId = "com.kunzisoft.keepass.tests"
|
||||
@@ -86,7 +86,7 @@ android {
|
||||
}
|
||||
|
||||
def spongycastleVersion = "1.58.0.0"
|
||||
def room_version = "2.2.4"
|
||||
def room_version = "2.2.5"
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
@@ -541,12 +541,10 @@ class EntryActivity : LockingActivity() {
|
||||
|
||||
override fun finish() {
|
||||
// Transit data in previous Activity after an update
|
||||
/*
|
||||
TODO Slowdown when add entry as result
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mEntry);
|
||||
onFinish(EntryEditActivity.UPDATE_ENTRY_RESULT_CODE, intent);
|
||||
*/
|
||||
Intent().apply {
|
||||
putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mEntry)
|
||||
setResult(EntryEditActivity.UPDATE_ENTRY_RESULT_CODE, this)
|
||||
}
|
||||
super.finish()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
package com.kunzisoft.keepass.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.DatePickerDialog
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
@@ -26,13 +28,15 @@ import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ScrollView
|
||||
import android.widget.DatePicker
|
||||
import android.widget.TimePicker
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.widget.ActionMenuView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.GeneratePasswordDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.SetOTPDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.*
|
||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.DateInstant
|
||||
@@ -52,12 +56,15 @@ import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.MenuUtil
|
||||
import com.kunzisoft.keepass.view.EntryEditContentsView
|
||||
import com.kunzisoft.keepass.view.showActionError
|
||||
import org.joda.time.DateTime
|
||||
import java.util.*
|
||||
|
||||
class EntryEditActivity : LockingActivity(),
|
||||
IconPickerDialogFragment.IconPickerListener,
|
||||
GeneratePasswordDialogFragment.GeneratePasswordListener,
|
||||
SetOTPDialogFragment.CreateOtpListener {
|
||||
SetOTPDialogFragment.CreateOtpListener,
|
||||
DatePickerDialog.OnDateSetListener,
|
||||
TimePickerDialog.OnTimeSetListener {
|
||||
|
||||
private var mDatabase: Database? = null
|
||||
|
||||
@@ -70,8 +77,9 @@ class EntryEditActivity : LockingActivity(),
|
||||
|
||||
// Views
|
||||
private var coordinatorLayout: CoordinatorLayout? = null
|
||||
private var scrollView: ScrollView? = null
|
||||
private var scrollView: NestedScrollView? = null
|
||||
private var entryEditContentsView: EntryEditContentsView? = null
|
||||
private var entryEditAddToolBar: ActionMenuView? = null
|
||||
private var saveView: View? = null
|
||||
|
||||
// Education
|
||||
@@ -94,6 +102,16 @@ class EntryEditActivity : LockingActivity(),
|
||||
|
||||
entryEditContentsView = findViewById(R.id.entry_edit_contents)
|
||||
entryEditContentsView?.applyFontVisibilityToFields(PreferencesUtil.fieldFontIsInVisibility(this))
|
||||
entryEditContentsView?.onDateClickListener = View.OnClickListener {
|
||||
entryEditContentsView?.expiresDate?.date?.let { expiresDate ->
|
||||
val dateTime = DateTime(expiresDate)
|
||||
val defaultYear = dateTime.year
|
||||
val defaultMonth = dateTime.monthOfYear-1
|
||||
val defaultDay = dateTime.dayOfMonth
|
||||
DatePickerFragment.getInstance(defaultYear, defaultMonth, defaultDay)
|
||||
.show(supportFragmentManager, "DatePickerFragment")
|
||||
}
|
||||
}
|
||||
// Focus view to reinitialize timeout
|
||||
resetAppTimeoutWhenViewFocusedOrChanged(entryEditContentsView)
|
||||
|
||||
@@ -167,17 +185,46 @@ class EntryEditActivity : LockingActivity(),
|
||||
// Add listener to the icon
|
||||
entryEditContentsView?.setOnIconViewClickListener { IconPickerDialogFragment.launch(this@EntryEditActivity) }
|
||||
|
||||
// Generate password button
|
||||
entryEditContentsView?.setOnPasswordGeneratorClickListener { openPasswordGenerator() }
|
||||
// Bottom Bar
|
||||
entryEditAddToolBar = findViewById(R.id.entry_edit_bottom_bar)
|
||||
entryEditAddToolBar?.apply {
|
||||
menuInflater.inflate(R.menu.entry_edit, menu)
|
||||
|
||||
menu.findItem(R.id.menu_add_field).apply {
|
||||
val allowCustomField = mNewEntry?.allowCustomFields() == true
|
||||
isEnabled = allowCustomField
|
||||
isVisible = allowCustomField
|
||||
}
|
||||
|
||||
menu.findItem(R.id.menu_add_otp).apply {
|
||||
val allowOTP = mDatabase?.allowOTP == true
|
||||
isEnabled = allowOTP
|
||||
isVisible = allowOTP
|
||||
}
|
||||
|
||||
setOnMenuItemClickListener { item ->
|
||||
when (item.itemId) {
|
||||
R.id.menu_generate_password -> {
|
||||
openPasswordGenerator()
|
||||
true
|
||||
}
|
||||
R.id.menu_add_field -> {
|
||||
addNewCustomField()
|
||||
true
|
||||
}
|
||||
R.id.menu_add_otp -> {
|
||||
setupOTP()
|
||||
true
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save button
|
||||
saveView = findViewById(R.id.entry_edit_save)
|
||||
saveView = findViewById(R.id.entry_edit_validate)
|
||||
saveView?.setOnClickListener { saveEntry() }
|
||||
|
||||
entryEditContentsView?.allowCustomField(mNewEntry?.allowCustomFields() == true) {
|
||||
addNewCustomField()
|
||||
}
|
||||
|
||||
// Verify the education views
|
||||
entryEditActivityEducation = EntryEditActivityEducation(this)
|
||||
|
||||
@@ -207,6 +254,9 @@ class EntryEditActivity : LockingActivity(),
|
||||
username = if (newEntry.username.isEmpty()) mDatabase?.defaultUsername ?:"" else newEntry.username
|
||||
url = newEntry.url
|
||||
password = newEntry.password
|
||||
expires = newEntry.expires
|
||||
if (expires)
|
||||
expiresDate = newEntry.expiryTime
|
||||
notes = newEntry.notes
|
||||
for (entry in newEntry.customFields.entries) {
|
||||
post {
|
||||
@@ -228,6 +278,10 @@ class EntryEditActivity : LockingActivity(),
|
||||
username = entryView.username
|
||||
url = entryView.url
|
||||
password = entryView.password
|
||||
expires = entryView.expires
|
||||
if (entryView.expires) {
|
||||
expiryTime = entryView.expiresDate
|
||||
}
|
||||
notes = entryView. notes
|
||||
entryView.customFields.forEach { customField ->
|
||||
putExtraField(customField.name, customField.protectedValue)
|
||||
@@ -259,6 +313,13 @@ class EntryEditActivity : LockingActivity(),
|
||||
entryEditContentsView?.addEmptyCustomField()
|
||||
}
|
||||
|
||||
private fun setupOTP() {
|
||||
// Retrieve the current otpElement if exists
|
||||
// and open the dialog to set up the OTP
|
||||
SetOTPDialogFragment.build(mEntry?.getOtpElement()?.otpModel)
|
||||
.show(supportFragmentManager, "addOTPDialog")
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the new entry or update an existing entry in the database
|
||||
*/
|
||||
@@ -307,8 +368,6 @@ class EntryEditActivity : LockingActivity(),
|
||||
// Save database not needed here
|
||||
menu.findItem(R.id.menu_save_database)?.isVisible = false
|
||||
MenuUtil.contributionMenuInflater(inflater, menu)
|
||||
if (mDatabase?.allowOTP == true)
|
||||
inflater.inflate(R.menu.entry_otp, menu)
|
||||
|
||||
entryEditActivityEducation?.let {
|
||||
Handler().post { performedNextEducation(it) }
|
||||
@@ -318,12 +377,10 @@ class EntryEditActivity : LockingActivity(),
|
||||
}
|
||||
|
||||
private fun performedNextEducation(entryEditActivityEducation: EntryEditActivityEducation) {
|
||||
val passwordView = entryEditContentsView?.generatePasswordView
|
||||
val addNewFieldView = entryEditContentsView?.addNewFieldButton
|
||||
|
||||
val generatePasswordEducationPerformed = passwordView != null
|
||||
val passwordGeneratorView: View? = entryEditAddToolBar?.findViewById(R.id.menu_generate_password)
|
||||
val generatePasswordEducationPerformed = passwordGeneratorView != null
|
||||
&& entryEditActivityEducation.checkAndPerformedGeneratePasswordEducation(
|
||||
passwordView,
|
||||
passwordGeneratorView,
|
||||
{
|
||||
openPasswordGenerator()
|
||||
},
|
||||
@@ -332,16 +389,30 @@ class EntryEditActivity : LockingActivity(),
|
||||
}
|
||||
)
|
||||
if (!generatePasswordEducationPerformed) {
|
||||
// entryNewFieldEducationPerformed
|
||||
mNewEntry != null && mNewEntry!!.allowCustomFields() && mNewEntry!!.customFields.isEmpty()
|
||||
val addNewFieldView: View? = entryEditAddToolBar?.findViewById(R.id.menu_add_field)
|
||||
val addNewFieldEducationPerformed = mNewEntry != null
|
||||
&& mNewEntry!!.allowCustomFields() && mNewEntry!!.customFields.isEmpty()
|
||||
&& addNewFieldView != null && addNewFieldView.visibility == View.VISIBLE
|
||||
&& entryEditActivityEducation.checkAndPerformedEntryNewFieldEducation(
|
||||
addNewFieldView,
|
||||
{
|
||||
addNewCustomField()
|
||||
},
|
||||
{
|
||||
performedNextEducation(entryEditActivityEducation)
|
||||
}
|
||||
)
|
||||
if (!addNewFieldEducationPerformed) {
|
||||
val setupOtpView: View? = entryEditAddToolBar?.findViewById(R.id.menu_add_otp)
|
||||
setupOtpView != null && setupOtpView.visibility == View.VISIBLE
|
||||
&& entryEditActivityEducation.checkAndPerformedSetUpOTPEducation(
|
||||
setupOtpView,
|
||||
{
|
||||
setupOTP()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
@@ -356,14 +427,9 @@ class EntryEditActivity : LockingActivity(),
|
||||
MenuUtil.onContributionItemSelected(this)
|
||||
return true
|
||||
}
|
||||
R.id.menu_add_otp -> {
|
||||
// Retrieve the current otpElement if exists
|
||||
// and open the dialog to set up the OTP
|
||||
SetOTPDialogFragment.build(mEntry?.getOtpElement()?.otpModel)
|
||||
.show(supportFragmentManager, "addOTPDialog")
|
||||
return true
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
}
|
||||
android.R.id.home -> finish()
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item)
|
||||
@@ -383,6 +449,39 @@ class EntryEditActivity : LockingActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDateSet(datePicker: DatePicker?, year: Int, month: Int, day: Int) {
|
||||
// To fix android 4.4 issue
|
||||
// https://stackoverflow.com/questions/12436073/datepicker-ondatechangedlistener-called-twice
|
||||
if (datePicker?.isShown == true) {
|
||||
entryEditContentsView?.expiresDate?.date?.let { expiresDate ->
|
||||
// Save the date
|
||||
entryEditContentsView?.expiresDate =
|
||||
DateInstant(DateTime(expiresDate)
|
||||
.withYear(year)
|
||||
.withMonthOfYear(month + 1)
|
||||
.withDayOfMonth(day)
|
||||
.toDate())
|
||||
// Launch the time picker
|
||||
val dateTime = DateTime(expiresDate)
|
||||
val defaultHour = dateTime.hourOfDay
|
||||
val defaultMinute = dateTime.minuteOfHour
|
||||
TimePickerFragment.getInstance(defaultHour, defaultMinute)
|
||||
.show(supportFragmentManager, "TimePickerFragment")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTimeSet(timePicker: TimePicker?, hours: Int, minutes: Int) {
|
||||
entryEditContentsView?.expiresDate?.date?.let { expiresDate ->
|
||||
// Save the date
|
||||
entryEditContentsView?.expiresDate =
|
||||
DateInstant(DateTime(expiresDate)
|
||||
.withHourOfDay(hours)
|
||||
.withMinuteOfHour(minutes)
|
||||
.toDate())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
mNewEntry?.let {
|
||||
populateEntryWithViews(it)
|
||||
@@ -406,6 +505,15 @@ class EntryEditActivity : LockingActivity(),
|
||||
// Do nothing here
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(R.string.discard_changes)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.discard) { _, _ ->
|
||||
super@EntryEditActivity.onBackPressed()
|
||||
}.create().show()
|
||||
}
|
||||
|
||||
override fun finish() {
|
||||
// Assign entry callback as a result in all case
|
||||
try {
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
@@ -61,6 +62,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
AssignMasterKeyDialogFragment.AssignPasswordDialogListener {
|
||||
|
||||
// Views
|
||||
private var coordinatorLayout: CoordinatorLayout? = null
|
||||
private var fileListContainer: View? = null
|
||||
private var createButtonView: View? = null
|
||||
private var openDatabaseButtonView: View? = null
|
||||
@@ -82,6 +84,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
mFileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(applicationContext)
|
||||
|
||||
setContentView(R.layout.activity_file_selection)
|
||||
coordinatorLayout = findViewById(R.id.activity_file_selection_coordinator_layout)
|
||||
fileListContainer = findViewById(R.id.container_file_list)
|
||||
|
||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||
@@ -161,9 +164,6 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
onActionFinish = { actionTask, _ ->
|
||||
when (actionTask) {
|
||||
ACTION_DATABASE_CREATE_TASK -> {
|
||||
// TODO Check
|
||||
// mAdapterDatabaseHistory?.notifyDataSetChanged()
|
||||
// updateFileListVisibility()
|
||||
GroupActivity.launch(this@FileDatabaseSelectActivity)
|
||||
}
|
||||
}
|
||||
@@ -182,7 +182,9 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
|
||||
private fun fileNoFoundAction(e: FileNotFoundException) {
|
||||
val error = getString(R.string.file_not_found_content)
|
||||
Snackbar.make(activity_file_selection_coordinator_layout, error, Snackbar.LENGTH_LONG).asError().show()
|
||||
coordinatorLayout?.let {
|
||||
Snackbar.make(it, error, Snackbar.LENGTH_LONG).asError().show()
|
||||
}
|
||||
Log.e(TAG, error, e)
|
||||
}
|
||||
|
||||
@@ -281,9 +283,8 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
// Show only uri accessible
|
||||
historyList.filter {
|
||||
if (hideBrokenLocations) {
|
||||
UriUtil.parse(it.databaseUri)?.let { historyUri ->
|
||||
UriUtil.isUriAccessible(contentResolver, historyUri)
|
||||
} ?: false
|
||||
FileDatabaseInfo(this@FileDatabaseSelectActivity,
|
||||
it.databaseUri).exists
|
||||
} else
|
||||
true
|
||||
})
|
||||
@@ -372,10 +373,13 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
if (mDatabaseFileUri != null) {
|
||||
AssignMasterKeyDialogFragment.getInstance(true)
|
||||
.show(supportFragmentManager, "passwordDialog")
|
||||
} else {
|
||||
val error = getString(R.string.error_create_database)
|
||||
coordinatorLayout?.let {
|
||||
Snackbar.make(it, error, Snackbar.LENGTH_LONG).asError().show()
|
||||
}
|
||||
Log.e(TAG, error)
|
||||
}
|
||||
// else {
|
||||
// TODO Show error
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -439,7 +439,6 @@ class GroupActivity : LockingActivity(),
|
||||
enableAddGroup(addGroupEnabled)
|
||||
enableAddEntry(addEntryEnabled)
|
||||
|
||||
if (isEnable)
|
||||
showButton()
|
||||
}
|
||||
}
|
||||
@@ -504,6 +503,7 @@ class GroupActivity : LockingActivity(),
|
||||
private fun finishNodeAction() {
|
||||
actionNodeMode?.finish()
|
||||
actionNodeMode = null
|
||||
addNodeButtonView?.showButton()
|
||||
}
|
||||
|
||||
override fun onNodeSelected(nodes: List<Node>): Boolean {
|
||||
@@ -515,6 +515,7 @@ class GroupActivity : LockingActivity(),
|
||||
} else {
|
||||
actionNodeMode?.invalidate()
|
||||
}
|
||||
addNodeButtonView?.hideButton()
|
||||
} else {
|
||||
finishNodeAction()
|
||||
}
|
||||
@@ -664,13 +665,15 @@ class GroupActivity : LockingActivity(),
|
||||
}
|
||||
|
||||
// Get the SearchView and set the searchable configuration
|
||||
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
|
||||
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager?
|
||||
|
||||
menu.findItem(R.id.menu_search)?.let {
|
||||
val searchView = it.actionView as SearchView?
|
||||
searchView?.apply {
|
||||
setSearchableInfo(searchManager.getSearchableInfo(
|
||||
ComponentName(this@GroupActivity, GroupActivity::class.java)))
|
||||
(searchManager?.getSearchableInfo(
|
||||
ComponentName(this@GroupActivity, GroupActivity::class.java)))?.let { searchableInfo ->
|
||||
setSearchableInfo(searchableInfo)
|
||||
}
|
||||
setIconifiedByDefault(false) // Do not iconify the widget; expand it by default
|
||||
suggestionsAdapter = mSearchSuggestionAdapter
|
||||
setOnSuggestionListener(object : SearchView.OnSuggestionListener {
|
||||
@@ -905,8 +908,8 @@ class GroupActivity : LockingActivity(),
|
||||
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
// Not directly get the entry from intent data but from database
|
||||
mListNodesFragment?.rebuildList()
|
||||
// Directly used the onActivityResult in fragment
|
||||
mListNodesFragment?.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun removeSearchInIntent(intent: Intent) {
|
||||
@@ -953,13 +956,8 @@ class GroupActivity : LockingActivity(),
|
||||
private const val SEARCH_FRAGMENT_TAG = "SEARCH_FRAGMENT_TAG"
|
||||
private const val OLD_GROUP_TO_UPDATE_KEY = "OLD_GROUP_TO_UPDATE_KEY"
|
||||
|
||||
private fun buildAndLaunchIntent(context: Context, group: Group?, readOnly: Boolean,
|
||||
private fun buildIntent(context: Context, group: Group?, readOnly: Boolean,
|
||||
intentBuildLauncher: (Intent) -> Unit) {
|
||||
val checkTime = if (context is Activity)
|
||||
TimeoutHelper.checkTimeAndLockIfTimeout(context)
|
||||
else
|
||||
TimeoutHelper.checkTime(context)
|
||||
if (checkTime) {
|
||||
val intent = Intent(context, GroupActivity::class.java)
|
||||
if (group != null) {
|
||||
intent.putExtra(GROUP_ID_KEY, group.nodeId)
|
||||
@@ -967,6 +965,19 @@ class GroupActivity : LockingActivity(),
|
||||
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly)
|
||||
intentBuildLauncher.invoke(intent)
|
||||
}
|
||||
|
||||
private fun checkTimeAndBuildIntent(activity: Activity, group: Group?, readOnly: Boolean,
|
||||
intentBuildLauncher: (Intent) -> Unit) {
|
||||
if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
|
||||
buildIntent(activity, group, readOnly, intentBuildLauncher)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkTimeAndBuildIntent(context: Context, group: Group?, readOnly: Boolean,
|
||||
intentBuildLauncher: (Intent) -> Unit) {
|
||||
if (TimeoutHelper.checkTime(context)) {
|
||||
buildIntent(context, group, readOnly, intentBuildLauncher)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -976,9 +987,9 @@ class GroupActivity : LockingActivity(),
|
||||
*/
|
||||
|
||||
@JvmOverloads
|
||||
fun launch(context: Context, readOnly: Boolean = PreferencesUtil.enableReadOnlyDatabase(context)) {
|
||||
TimeoutHelper.recordTime(context)
|
||||
buildAndLaunchIntent(context, null, readOnly) { intent ->
|
||||
fun launch(context: Context,
|
||||
readOnly: Boolean = PreferencesUtil.enableReadOnlyDatabase(context)) {
|
||||
checkTimeAndBuildIntent(context, null, readOnly) { intent ->
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
@@ -990,9 +1001,9 @@ class GroupActivity : LockingActivity(),
|
||||
*/
|
||||
// TODO implement pre search to directly open the direct group
|
||||
|
||||
fun launchForKeyboardSelection(context: Context, readOnly: Boolean) {
|
||||
TimeoutHelper.recordTime(context)
|
||||
buildAndLaunchIntent(context, null, readOnly) { intent ->
|
||||
fun launchForKeyboardSelection(context: Context,
|
||||
readOnly: Boolean = PreferencesUtil.enableReadOnlyDatabase(context)) {
|
||||
checkTimeAndBuildIntent(context, null, readOnly) { intent ->
|
||||
EntrySelectionHelper.startActivityForEntrySelection(context, intent)
|
||||
}
|
||||
}
|
||||
@@ -1005,9 +1016,10 @@ class GroupActivity : LockingActivity(),
|
||||
// TODO implement pre search to directly open the direct group
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
fun launchForAutofillResult(activity: Activity, assistStructure: AssistStructure, readOnly: Boolean) {
|
||||
TimeoutHelper.recordTime(activity)
|
||||
buildAndLaunchIntent(activity, null, readOnly) { intent ->
|
||||
fun launchForAutofillResult(activity: Activity,
|
||||
assistStructure: AssistStructure,
|
||||
readOnly: Boolean = PreferencesUtil.enableReadOnlyDatabase(activity)) {
|
||||
checkTimeAndBuildIntent(activity, null, readOnly) { intent ->
|
||||
AutofillHelper.startActivityForAutofillResult(activity, intent, assistStructure)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,13 +369,11 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
||||
EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE -> {
|
||||
if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE
|
||||
|| resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE) {
|
||||
data?.getParcelableExtra<Node>(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY)?.let { newNode ->
|
||||
data?.getParcelableExtra<Node>(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY)?.let { changedNode ->
|
||||
if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE)
|
||||
mAdapter?.addNode(newNode)
|
||||
if (resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE) {
|
||||
//mAdapter.updateLastNodeRegister(newNode);
|
||||
rebuildList()
|
||||
}
|
||||
addNode(changedNode)
|
||||
if (resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE)
|
||||
mAdapter?.notifyDataSetChanged()
|
||||
} ?: Log.e(this.javaClass.name, "New node can be retrieve in Activity Result")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,8 +111,6 @@ open class PasswordActivity : StylishActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this)
|
||||
|
||||
setContentView(R.layout.activity_password)
|
||||
|
||||
toolbar = findViewById(R.id.toolbar)
|
||||
@@ -165,6 +163,12 @@ open class PasswordActivity : StylishActivity() {
|
||||
enableOrNotTheConfirmationButton()
|
||||
}
|
||||
|
||||
// If is a view intent
|
||||
getUriFromIntent(intent)
|
||||
if (savedInstanceState?.containsKey(KEY_KEYFILE) == true) {
|
||||
mDatabaseKeyFileUri = UriUtil.parse(savedInstanceState.getString(KEY_KEYFILE))
|
||||
}
|
||||
|
||||
mProgressDialogThread = ProgressDialogThread(this).apply {
|
||||
onActionFinish = { actionTask, result ->
|
||||
when (actionTask) {
|
||||
@@ -177,11 +181,9 @@ open class PasswordActivity : StylishActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the password in view in all cases
|
||||
removePassword()
|
||||
|
||||
if (result.isSuccess) {
|
||||
setEmptyViews()
|
||||
mDatabaseKeyFileUri = null
|
||||
clearCredentialsViews(true)
|
||||
launchGroupActivity()
|
||||
} else {
|
||||
var resultError = ""
|
||||
@@ -237,6 +239,24 @@ open class PasswordActivity : StylishActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUriFromIntent(intent: Intent?) {
|
||||
// If is a view intent
|
||||
val action = intent?.action
|
||||
if (action != null
|
||||
&& action == VIEW_INTENT) {
|
||||
mDatabaseFileUri = intent.data
|
||||
mDatabaseKeyFileUri = UriUtil.getUriFromIntent(intent, KEY_KEYFILE)
|
||||
} else {
|
||||
mDatabaseFileUri = intent?.getParcelableExtra(KEY_FILENAME)
|
||||
mDatabaseKeyFileUri = intent?.getParcelableExtra(KEY_KEYFILE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
getUriFromIntent(intent)
|
||||
}
|
||||
|
||||
private fun launchGroupActivity() {
|
||||
EntrySelectionHelper.doEntrySelectionAction(intent,
|
||||
{
|
||||
@@ -265,13 +285,15 @@ open class PasswordActivity : StylishActivity() {
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this)
|
||||
|
||||
if (Database.getInstance().loaded)
|
||||
launchGroupActivity()
|
||||
|
||||
// If the database isn't accessible make sure to clear the password field, if it
|
||||
// was saved in the instance state
|
||||
if (Database.getInstance().loaded) {
|
||||
setEmptyViews()
|
||||
clearCredentialsViews()
|
||||
}
|
||||
|
||||
// For check shutdown
|
||||
@@ -283,46 +305,37 @@ open class PasswordActivity : StylishActivity() {
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
mDatabaseKeyFileUri?.let {
|
||||
outState.putString(KEY_KEYFILE, it.toString())
|
||||
}
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
private fun initUriFromIntent() {
|
||||
|
||||
val databaseUri: Uri?
|
||||
val keyFileUri: Uri?
|
||||
|
||||
// If is a view intent
|
||||
val action = intent.action
|
||||
if (action != null
|
||||
&& action == VIEW_INTENT) {
|
||||
databaseUri = intent.data
|
||||
keyFileUri = UriUtil.getUriFromIntent(intent, KEY_KEYFILE)
|
||||
} else {
|
||||
databaseUri = intent.getParcelableExtra(KEY_FILENAME)
|
||||
keyFileUri = intent.getParcelableExtra(KEY_KEYFILE)
|
||||
}
|
||||
|
||||
mForceReadOnly = !UriUtil.isUriWritable(contentResolver, databaseUri)
|
||||
/*
|
||||
// "canXrite" doesn't work with Google Drive, don't really know why?
|
||||
mForceReadOnly = mDatabaseFileUri?.let {
|
||||
!FileDatabaseInfo(this, it).canWrite
|
||||
} ?: false
|
||||
*/
|
||||
mForceReadOnly = false
|
||||
|
||||
// Post init uri with KeyFile if needed
|
||||
if (mRememberKeyFile && (keyFileUri == null || keyFileUri.toString().isEmpty())) {
|
||||
if (mRememberKeyFile && (mDatabaseKeyFileUri == null || mDatabaseKeyFileUri.toString().isEmpty())) {
|
||||
// Retrieve KeyFile in a thread
|
||||
databaseUri?.let { databaseUriNotNull ->
|
||||
mDatabaseFileUri?.let { databaseUri ->
|
||||
FileDatabaseHistoryAction.getInstance(applicationContext)
|
||||
.getKeyFileUriByDatabaseUri(databaseUriNotNull) {
|
||||
.getKeyFileUriByDatabaseUri(databaseUri) {
|
||||
onPostInitUri(databaseUri, it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
onPostInitUri(databaseUri, keyFileUri)
|
||||
onPostInitUri(mDatabaseFileUri, mDatabaseKeyFileUri)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onPostInitUri(databaseFileUri: Uri?, keyFileUri: Uri?) {
|
||||
mDatabaseFileUri = databaseFileUri
|
||||
mDatabaseKeyFileUri = keyFileUri
|
||||
|
||||
// Define title
|
||||
databaseFileUri?.let {
|
||||
FileDatabaseInfo(this, it).retrieveDatabaseTitle { title ->
|
||||
@@ -331,9 +344,8 @@ open class PasswordActivity : StylishActivity() {
|
||||
}
|
||||
|
||||
// Define Key File text
|
||||
val keyUriString = keyFileUri?.toString() ?: ""
|
||||
if (keyUriString.isNotEmpty() && mRememberKeyFile) { // Bug KeepassDX #18
|
||||
populateKeyFileTextView(keyUriString)
|
||||
if (mRememberKeyFile) {
|
||||
populateKeyFileTextView(keyFileUri?.toString())
|
||||
}
|
||||
|
||||
// Define listeners for default database checkbox and validate button
|
||||
@@ -428,10 +440,9 @@ open class PasswordActivity : StylishActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setEmptyViews() {
|
||||
private fun clearCredentialsViews(clearKeyFile: Boolean = !mRememberKeyFile) {
|
||||
populatePasswordTextView(null)
|
||||
// Bug KeepassDX #18
|
||||
if (!mRememberKeyFile) {
|
||||
if (clearKeyFile) {
|
||||
populateKeyFileTextView(null)
|
||||
}
|
||||
}
|
||||
@@ -497,18 +508,13 @@ open class PasswordActivity : StylishActivity() {
|
||||
mDatabaseKeyFileUri = if (checkboxKeyFileView?.isChecked != true) null else keyFile
|
||||
}
|
||||
|
||||
private fun removePassword() {
|
||||
passwordView?.setText("")
|
||||
checkboxPasswordView?.isChecked = false
|
||||
}
|
||||
|
||||
private fun loadDatabase(databaseFileUri: Uri?,
|
||||
password: String?,
|
||||
keyFileUri: Uri?,
|
||||
cipherDatabaseEntity: CipherDatabaseEntity? = null) {
|
||||
|
||||
if (PreferencesUtil.deletePasswordAfterConnexionAttempt(this)) {
|
||||
removePassword()
|
||||
clearCredentialsViews()
|
||||
}
|
||||
|
||||
databaseFileUri?.let { databaseUri ->
|
||||
@@ -671,6 +677,7 @@ open class PasswordActivity : StylishActivity() {
|
||||
keyFileResult = it.onActivityResultCallback(requestCode, resultCode, data
|
||||
) { uri ->
|
||||
if (uri != null) {
|
||||
mDatabaseKeyFileUri = uri
|
||||
populateKeyFileTextView(uri.toString())
|
||||
}
|
||||
}
|
||||
@@ -679,7 +686,7 @@ open class PasswordActivity : StylishActivity() {
|
||||
// this block if not a key file response
|
||||
when (resultCode) {
|
||||
LockingActivity.RESULT_EXIT_LOCK, Activity.RESULT_CANCELED -> {
|
||||
setEmptyViews()
|
||||
clearCredentialsViews()
|
||||
Database.getInstance().closeAndClear(applicationContext.filesDir)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.DatePickerDialog
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
|
||||
class DatePickerFragment : DialogFragment() {
|
||||
|
||||
private var mDefaultYear: Int = 2000
|
||||
private var mDefaultMonth: Int = 1
|
||||
private var mDefaultDay: Int = 1
|
||||
|
||||
private var mListener: DatePickerDialog.OnDateSetListener? = null
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
try {
|
||||
mListener = context as DatePickerDialog.OnDateSetListener
|
||||
} catch (e: ClassCastException) {
|
||||
throw ClassCastException(context.toString()
|
||||
+ " must implement " + DatePickerDialog.OnDateSetListener::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
// Create a new instance of DatePickerDialog and return it
|
||||
return context?.let {
|
||||
arguments?.apply {
|
||||
if (containsKey(DEFAULT_YEAR_BUNDLE_KEY))
|
||||
mDefaultYear = getInt(DEFAULT_YEAR_BUNDLE_KEY)
|
||||
if (containsKey(DEFAULT_MONTH_BUNDLE_KEY))
|
||||
mDefaultMonth = getInt(DEFAULT_MONTH_BUNDLE_KEY)
|
||||
if (containsKey(DEFAULT_DAY_BUNDLE_KEY))
|
||||
mDefaultDay = getInt(DEFAULT_DAY_BUNDLE_KEY)
|
||||
}
|
||||
|
||||
DatePickerDialog(it, mListener, mDefaultYear, mDefaultMonth, mDefaultDay)
|
||||
} ?: super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val DEFAULT_YEAR_BUNDLE_KEY = "DEFAULT_YEAR_BUNDLE_KEY"
|
||||
private const val DEFAULT_MONTH_BUNDLE_KEY = "DEFAULT_MONTH_BUNDLE_KEY"
|
||||
private const val DEFAULT_DAY_BUNDLE_KEY = "DEFAULT_DAY_BUNDLE_KEY"
|
||||
|
||||
fun getInstance(defaultYear: Int,
|
||||
defaultMonth: Int,
|
||||
defaultDay: Int): DatePickerFragment {
|
||||
return DatePickerFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putInt(DEFAULT_YEAR_BUNDLE_KEY, defaultYear)
|
||||
putInt(DEFAULT_MONTH_BUNDLE_KEY, defaultMonth)
|
||||
putInt(DEFAULT_DAY_BUNDLE_KEY, defaultDay)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.DatePickerDialog
|
||||
import android.app.Dialog
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
|
||||
class TimePickerFragment : DialogFragment() {
|
||||
|
||||
private var defaultHour: Int = 0
|
||||
private var defaultMinute: Int = 0
|
||||
|
||||
private var mListener: TimePickerDialog.OnTimeSetListener? = null
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
try {
|
||||
mListener = context as TimePickerDialog.OnTimeSetListener
|
||||
} catch (e: ClassCastException) {
|
||||
throw ClassCastException(context.toString()
|
||||
+ " must implement " + DatePickerDialog.OnDateSetListener::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
// Create a new instance of DatePickerDialog and return it
|
||||
return context?.let {
|
||||
arguments?.apply {
|
||||
if (containsKey(DEFAULT_HOUR_BUNDLE_KEY))
|
||||
defaultHour = getInt(DEFAULT_HOUR_BUNDLE_KEY)
|
||||
if (containsKey(DEFAULT_MINUTE_BUNDLE_KEY))
|
||||
defaultMinute = getInt(DEFAULT_MINUTE_BUNDLE_KEY)
|
||||
}
|
||||
|
||||
TimePickerDialog(it, mListener, defaultHour, defaultMinute, DateFormat.is24HourFormat(activity))
|
||||
} ?: super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val DEFAULT_HOUR_BUNDLE_KEY = "DEFAULT_HOUR_BUNDLE_KEY"
|
||||
private const val DEFAULT_MINUTE_BUNDLE_KEY = "DEFAULT_MINUTE_BUNDLE_KEY"
|
||||
|
||||
fun getInstance(defaultHour: Int,
|
||||
defaultMinute: Int): TimePickerFragment {
|
||||
return TimePickerFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putInt(DEFAULT_HOUR_BUNDLE_KEY, defaultHour)
|
||||
putInt(DEFAULT_MINUTE_BUNDLE_KEY, defaultMinute)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,7 @@
|
||||
package com.kunzisoft.keepass.activities.lock
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
@@ -34,12 +30,9 @@ import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
||||
import com.kunzisoft.keepass.activities.stylish.StylishActivity
|
||||
import com.kunzisoft.keepass.database.action.ProgressDialogThread
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.magikeyboard.MagikIME
|
||||
import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.LOCK_ACTION
|
||||
import com.kunzisoft.keepass.utils.*
|
||||
|
||||
abstract class LockingActivity : StylishActivity() {
|
||||
|
||||
@@ -81,12 +74,10 @@ abstract class LockingActivity : StylishActivity() {
|
||||
}
|
||||
|
||||
if (mTimeoutEnable) {
|
||||
mLockReceiver = LockReceiver()
|
||||
val intentFilter = IntentFilter().apply {
|
||||
addAction(Intent.ACTION_SCREEN_OFF)
|
||||
addAction(LOCK_ACTION)
|
||||
mLockReceiver = LockReceiver {
|
||||
lockAndExit()
|
||||
}
|
||||
registerReceiver(mLockReceiver, intentFilter)
|
||||
registerLockReceiver(mLockReceiver)
|
||||
}
|
||||
|
||||
mExitLock = false
|
||||
@@ -151,29 +142,12 @@ abstract class LockingActivity : StylishActivity() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
unregisterLockReceiver(mLockReceiver)
|
||||
super.onDestroy()
|
||||
if (mLockReceiver != null)
|
||||
unregisterReceiver(mLockReceiver)
|
||||
}
|
||||
|
||||
inner class LockReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
// If allowed, lock and exit
|
||||
if (!TimeoutHelper.temporarilyDisableTimeout) {
|
||||
intent.action?.let {
|
||||
when (it) {
|
||||
Intent.ACTION_SCREEN_OFF -> if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(this@LockingActivity)) {
|
||||
lockAndExit()
|
||||
}
|
||||
LOCK_ACTION -> lockAndExit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected fun lockAndExit() {
|
||||
sendBroadcast(Intent(LOCK_ACTION))
|
||||
lock()
|
||||
}
|
||||
|
||||
@@ -208,20 +182,8 @@ abstract class LockingActivity : StylishActivity() {
|
||||
}
|
||||
|
||||
fun Activity.lock() {
|
||||
// Stop the Magikeyboard service
|
||||
stopService(Intent(this, KeyboardEntryNotificationService::class.java))
|
||||
MagikIME.removeEntry(this)
|
||||
closeDatabase()
|
||||
|
||||
// Stop the notification service
|
||||
stopService(Intent(this, ClipboardEntryNotificationService::class.java))
|
||||
|
||||
Log.i(Activity::class.java.name, "Shutdown " + localClassName +
|
||||
" after inactivity or manual lock")
|
||||
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).apply {
|
||||
cancelAll()
|
||||
}
|
||||
// Clear data
|
||||
Database.getInstance().closeAndClear(applicationContext.filesDir)
|
||||
// Add onActivityForResult response
|
||||
setResult(LockingActivity.RESULT_EXIT_LOCK)
|
||||
finish()
|
||||
|
||||
@@ -84,24 +84,25 @@ class FileDatabaseHistoryAdapter(private val context: Context)
|
||||
// File path
|
||||
holder.filePath.text = UriUtil.decode(fileDatabaseInfo.fileUri?.toString())
|
||||
|
||||
if (fileDatabaseInfo.dataAccessible()) {
|
||||
if (fileDatabaseInfo.exists) {
|
||||
holder.fileInformation.clearColorFilter()
|
||||
} else {
|
||||
holder.fileInformation.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
|
||||
// Modification
|
||||
if (fileDatabaseInfo.lastModificationAccessible()) {
|
||||
holder.fileModification.text = fileDatabaseInfo.getModificationString()
|
||||
fileDatabaseInfo.getModificationString()?.let {
|
||||
holder.fileModification.text = it
|
||||
holder.fileModification.visibility = View.VISIBLE
|
||||
} else {
|
||||
} ?: run {
|
||||
holder.fileModification.visibility = View.GONE
|
||||
}
|
||||
|
||||
// Size
|
||||
if (fileDatabaseInfo.sizeAccessible()) {
|
||||
holder.fileSize.text = fileDatabaseInfo.getSizeString()
|
||||
fileDatabaseInfo.getSizeString()?.let {
|
||||
holder.fileSize.text = it
|
||||
holder.fileSize.visibility = View.VISIBLE
|
||||
} else {
|
||||
} ?: run {
|
||||
holder.fileSize.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ class SearchEntryCursorAdapter(private val context: Context,
|
||||
private val database: Database)
|
||||
: androidx.cursoradapter.widget.CursorAdapter(context, null, FLAG_REGISTER_CONTENT_OBSERVER) {
|
||||
|
||||
private val cursorInflater: LayoutInflater = context.getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
private val cursorInflater: LayoutInflater? = context.getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
|
||||
private var displayUsername: Boolean = false
|
||||
private val iconColor: Int
|
||||
|
||||
@@ -58,7 +58,7 @@ class SearchEntryCursorAdapter(private val context: Context,
|
||||
|
||||
override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
|
||||
|
||||
val view = cursorInflater.inflate(R.layout.item_search_entry, parent, false)
|
||||
val view = cursorInflater!!.inflate(R.layout.item_search_entry, parent, false)
|
||||
val viewHolder = ViewHolder()
|
||||
viewHolder.imageViewIcon = view.findViewById(R.id.entry_icon)
|
||||
viewHolder.textViewTitle = view.findViewById(R.id.entry_text)
|
||||
|
||||
@@ -112,6 +112,14 @@ class FileDatabaseHistoryAction(applicationContext: Context) {
|
||||
).execute()
|
||||
}
|
||||
|
||||
fun deleteKeyFileByDatabaseUri(databaseUri: Uri) {
|
||||
ActionDatabaseAsyncTask(
|
||||
{
|
||||
databaseFileHistoryDao.deleteKeyFileByDatabaseUri(databaseUri.toString())
|
||||
}
|
||||
).execute()
|
||||
}
|
||||
|
||||
fun deleteAllKeyFiles() {
|
||||
ActionDatabaseAsyncTask(
|
||||
{
|
||||
|
||||
@@ -38,6 +38,9 @@ interface FileDatabaseHistoryDao {
|
||||
@Delete
|
||||
fun delete(fileDatabaseHistory: FileDatabaseHistoryEntity): Int
|
||||
|
||||
@Query("UPDATE file_database_history SET keyfile_uri=null WHERE database_uri = :databaseUriString")
|
||||
fun deleteKeyFileByDatabaseUri(databaseUriString: String)
|
||||
|
||||
@Query("UPDATE file_database_history SET keyfile_uri=null")
|
||||
fun deleteAllKeyFiles()
|
||||
|
||||
|
||||
@@ -26,15 +26,14 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.service.autofill.Dataset
|
||||
import android.service.autofill.FillResponse
|
||||
import androidx.annotation.RequiresApi
|
||||
import android.util.Log
|
||||
import android.view.autofill.AutofillManager
|
||||
import android.view.autofill.AutofillValue
|
||||
import android.widget.RemoteViews
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import java.util.*
|
||||
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@@ -56,10 +55,10 @@ object AutofillHelper {
|
||||
return String.format("%s (%s)", entryInfo.title, entryInfo.username)
|
||||
if (entryInfo.title.isNotEmpty())
|
||||
return entryInfo.title
|
||||
if (entryInfo.username.isNotEmpty())
|
||||
return entryInfo.username
|
||||
if (entryInfo.url.isNotEmpty())
|
||||
return entryInfo.url
|
||||
if (entryInfo.username.isNotEmpty())
|
||||
return entryInfo.username
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -71,12 +70,12 @@ object AutofillHelper {
|
||||
val builder = Dataset.Builder(views)
|
||||
builder.setId(entryInfo.id)
|
||||
|
||||
struct.password.forEach { id -> builder.setValue(id, AutofillValue.forText(entryInfo.password)) }
|
||||
|
||||
val ids = ArrayList(struct.username)
|
||||
if (entryInfo.username.contains("@") || struct.username.isEmpty())
|
||||
ids.addAll(struct.email)
|
||||
ids.forEach { id -> builder.setValue(id, AutofillValue.forText(entryInfo.username)) }
|
||||
struct.usernameId?.let { usernameId ->
|
||||
builder.setValue(usernameId, AutofillValue.forText(entryInfo.username))
|
||||
}
|
||||
struct.passwordId?.let { password ->
|
||||
builder.setValue(password, AutofillValue.forText(entryInfo.password))
|
||||
}
|
||||
|
||||
return try {
|
||||
builder.build()
|
||||
|
||||
@@ -31,7 +31,6 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import com.kunzisoft.keepass.activities.FileDatabaseSelectActivity
|
||||
import com.kunzisoft.keepass.activities.GroupActivity
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@@ -42,9 +41,11 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
||||
val assistStructure = AutofillHelper.retrieveAssistStructure(intent)
|
||||
if (assistStructure != null) {
|
||||
if (Database.getInstance().loaded && TimeoutHelper.checkTime(this))
|
||||
GroupActivity.launchForAutofillResult(this, assistStructure, PreferencesUtil.enableReadOnlyDatabase(this))
|
||||
GroupActivity.launchForAutofillResult(this,
|
||||
assistStructure)
|
||||
else {
|
||||
FileDatabaseSelectActivity.launchForAutofillResult(this, assistStructure)
|
||||
FileDatabaseSelectActivity.launchForAutofillResult(this,
|
||||
assistStructure)
|
||||
}
|
||||
} else {
|
||||
setResult(Activity.RESULT_CANCELED)
|
||||
|
||||
@@ -35,13 +35,13 @@ class KeeAutofillService : AutofillService() {
|
||||
val fillContexts = request.fillContexts
|
||||
val latestStructure = fillContexts[fillContexts.size - 1].structure
|
||||
|
||||
cancellationSignal.setOnCancelListener { Log.e(TAG, "Cancel autofill not implemented in this sample.") }
|
||||
cancellationSignal.setOnCancelListener { Log.w(TAG, "Cancel autofill.") }
|
||||
|
||||
val responseBuilder = FillResponse.Builder()
|
||||
// Check user's settings for authenticating Responses and Datasets.
|
||||
val parseResult = StructureParser(latestStructure).parse()
|
||||
parseResult?.allAutofillIds()?.let { autofillIds ->
|
||||
if (listOf(*autofillIds).isNotEmpty()) {
|
||||
if (autofillIds.isNotEmpty()) {
|
||||
// If the entire Autofill Response is authenticated, AuthActivity is used
|
||||
// to generate Response.
|
||||
val sender = AutofillLauncherActivity.getAuthIntentSenderForResponse(this)
|
||||
|
||||
@@ -21,7 +21,6 @@ package com.kunzisoft.keepass.autofill
|
||||
import android.app.assist.AssistStructure
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import android.text.InputType
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.autofill.AutofillId
|
||||
@@ -40,69 +39,130 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
result = Result()
|
||||
result?.apply {
|
||||
usernameCandidate = null
|
||||
for (i in 0 until structure.windowNodeCount) {
|
||||
mainLoop@ for (i in 0 until structure.windowNodeCount) {
|
||||
val windowNode = structure.getWindowNodeAt(i)
|
||||
/*
|
||||
title.add(windowNode.title)
|
||||
windowNode.rootViewNode.webDomain?.let {
|
||||
webDomain.add(it)
|
||||
}
|
||||
parseViewNode(windowNode.rootViewNode)
|
||||
*/
|
||||
if (parseViewNode(windowNode.rootViewNode))
|
||||
break@mainLoop
|
||||
}
|
||||
// If not explicit username field found, add the field just before password field.
|
||||
if (username.isEmpty() && email.isEmpty()
|
||||
&& password.isNotEmpty() && usernameCandidate != null)
|
||||
username.add(usernameCandidate!!)
|
||||
if (usernameId == null && passwordId != null && usernameCandidate != null)
|
||||
usernameId = usernameCandidate
|
||||
}
|
||||
|
||||
return result
|
||||
// Return the result only if password field is retrieved
|
||||
return if (result?.passwordId != null)
|
||||
result
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
private fun parseViewNode(node: AssistStructure.ViewNode) {
|
||||
private fun parseViewNode(node: AssistStructure.ViewNode): Boolean {
|
||||
if (node.autofillId != null) {
|
||||
val hints = node.autofillHints
|
||||
val autofillId = node.autofillId
|
||||
if (autofillId != null) {
|
||||
if (hints != null && hints.isNotEmpty()) {
|
||||
when {
|
||||
Arrays.stream(hints).anyMatch { View.AUTOFILL_HINT_USERNAME == it } -> result?.username?.add(autofillId)
|
||||
Arrays.stream(hints).anyMatch { View.AUTOFILL_HINT_EMAIL_ADDRESS == it } -> result?.email?.add(autofillId)
|
||||
Arrays.stream(hints).anyMatch { View.AUTOFILL_HINT_PASSWORD == it } -> result?.password?.add(autofillId)
|
||||
else -> Log.d(TAG, "unsupported hints")
|
||||
}
|
||||
} else if (node.autofillType == View.AUTOFILL_TYPE_TEXT) {
|
||||
val inputType = node.inputType
|
||||
when {
|
||||
inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS > 0 -> result?.email?.add(autofillId)
|
||||
inputType and InputType.TYPE_TEXT_VARIATION_PASSWORD > 0 -> result?.password?.add(autofillId)
|
||||
result?.password?.isEmpty() == true -> usernameCandidate = autofillId
|
||||
if (parseNodeByAutofillHint(node))
|
||||
return true
|
||||
} else {
|
||||
if (parseNodeByHtmlAttributes(node))
|
||||
return true
|
||||
}
|
||||
}
|
||||
// Recursive method to process each node
|
||||
for (i in 0 until node.childCount) {
|
||||
if (parseViewNode(node.getChildAt(i)))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for (i in 0 until node.childCount)
|
||||
parseViewNode(node.getChildAt(i))
|
||||
private fun parseNodeByAutofillHint(node: AssistStructure.ViewNode): Boolean {
|
||||
val autofillId = node.autofillId
|
||||
node.autofillHints?.forEach {
|
||||
when {
|
||||
it.toLowerCase(Locale.ENGLISH) == View.AUTOFILL_HINT_USERNAME
|
||||
|| it.toLowerCase(Locale.ENGLISH) == View.AUTOFILL_HINT_EMAIL_ADDRESS
|
||||
|| it.toLowerCase(Locale.ENGLISH) == View.AUTOFILL_HINT_PHONE -> {
|
||||
result?.usernameId = autofillId
|
||||
Log.d(TAG, "Autofill username hint")
|
||||
}
|
||||
it.toLowerCase(Locale.ENGLISH) == View.AUTOFILL_HINT_PASSWORD
|
||||
|| it.toLowerCase(Locale.ENGLISH).contains("password") -> {
|
||||
result?.passwordId = autofillId
|
||||
Log.d(TAG, "Autofill password hint")
|
||||
return true
|
||||
}
|
||||
// Ignore autocomplete="off"
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion
|
||||
it.toLowerCase(Locale.ENGLISH) == "off" ||
|
||||
it.toLowerCase(Locale.ENGLISH) == "on" -> {
|
||||
Log.d(TAG, "Autofill web hint")
|
||||
return parseNodeByHtmlAttributes(node)
|
||||
}
|
||||
else -> Log.d(TAG, "Autofill unsupported hint $it")
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun parseNodeByHtmlAttributes(node: AssistStructure.ViewNode): Boolean {
|
||||
val autofillId = node.autofillId
|
||||
val nodHtml = node.htmlInfo
|
||||
when (nodHtml?.tag?.toLowerCase(Locale.ENGLISH)) {
|
||||
"input" -> {
|
||||
nodHtml.attributes?.forEach { pairAttribute ->
|
||||
when (pairAttribute.first.toLowerCase(Locale.ENGLISH)) {
|
||||
"type" -> {
|
||||
when (pairAttribute.second.toLowerCase(Locale.ENGLISH)) {
|
||||
"tel", "email" -> {
|
||||
result?.usernameId = autofillId
|
||||
Log.d(TAG, "Autofill username type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
|
||||
}
|
||||
"text" -> {
|
||||
usernameCandidate = autofillId
|
||||
Log.d(TAG, "Autofill type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
|
||||
}
|
||||
"password" -> {
|
||||
result?.passwordId = autofillId
|
||||
Log.d(TAG, "Autofill password type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
internal class Result {
|
||||
val title: MutableList<CharSequence>
|
||||
val webDomain: MutableList<String>
|
||||
val username: MutableList<AutofillId>
|
||||
val email: MutableList<AutofillId>
|
||||
val password: MutableList<AutofillId>
|
||||
var usernameId: AutofillId? = null
|
||||
set(value) {
|
||||
if (field == null)
|
||||
field = value
|
||||
}
|
||||
|
||||
init {
|
||||
title = ArrayList()
|
||||
webDomain = ArrayList()
|
||||
username = ArrayList()
|
||||
email = ArrayList()
|
||||
password = ArrayList()
|
||||
var passwordId: AutofillId? = null
|
||||
set(value) {
|
||||
if (field == null)
|
||||
field = value
|
||||
}
|
||||
|
||||
fun allAutofillIds(): Array<AutofillId> {
|
||||
val all = ArrayList<AutofillId>()
|
||||
all.addAll(username)
|
||||
all.addAll(email)
|
||||
all.addAll(password)
|
||||
usernameId?.let {
|
||||
all.add(it)
|
||||
}
|
||||
passwordId?.let {
|
||||
all.add(it)
|
||||
}
|
||||
return all.toTypedArray()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
||||
// really not much to do when no fingerprint support found
|
||||
isKeyManagerInit = false
|
||||
} else {
|
||||
this.keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
||||
this.keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
|
||||
|
||||
try {
|
||||
this.keyStore = KeyStore.getInstance(BIOMETRIC_KEYSTORE)
|
||||
|
||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.database.action
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
|
||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
|
||||
@@ -70,6 +71,9 @@ open class AssignPasswordInDatabaseRunnable (
|
||||
// Erase the biometric
|
||||
CipherDatabaseAction.getInstance(context)
|
||||
.deleteByDatabaseUri(mDatabaseUri)
|
||||
// Erase the register keyfile
|
||||
FileDatabaseHistoryAction.getInstance(context)
|
||||
.deleteKeyFileByDatabaseUri(mDatabaseUri)
|
||||
|
||||
if (!result.isSuccess) {
|
||||
// Erase the current master key
|
||||
|
||||
@@ -86,8 +86,11 @@ class LoadDatabaseRunnable(private val context: Context,
|
||||
.addOrUpdateCipherDatabase(cipherDatabaseEntity) // return value not called
|
||||
}
|
||||
|
||||
// Register the current time to init the lock timer
|
||||
PreferencesUtil.saveCurrentTime(context)
|
||||
|
||||
// Start the opening notification
|
||||
DatabaseOpenNotificationService.startIfAllowed(context)
|
||||
DatabaseOpenNotificationService.start(context)
|
||||
} else {
|
||||
mDatabase.closeAndClear(cacheDirectory)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
||||
import com.kunzisoft.keepass.database.element.*
|
||||
@@ -35,6 +36,7 @@ import com.kunzisoft.keepass.database.element.node.Node
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.database.element.node.Type
|
||||
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
|
||||
import com.kunzisoft.keepass.notifications.DatabaseOpenNotificationService
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_ASSIGN_PASSWORD_TASK
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_COPY_NODES_TASK
|
||||
@@ -85,12 +87,17 @@ class ProgressDialogThread(private val activity: FragmentActivity) {
|
||||
|
||||
private val actionTaskListener = object: DatabaseTaskNotificationService.ActionTaskListener {
|
||||
override fun onStartAction(titleId: Int?, messageId: Int?, warningId: Int?) {
|
||||
TimeoutHelper.temporarilyDisableTimeout(activity)
|
||||
TimeoutHelper.temporarilyDisableTimeout()
|
||||
// Stop the opening notification
|
||||
DatabaseOpenNotificationService.stop(activity)
|
||||
startOrUpdateDialog(titleId, messageId, warningId)
|
||||
|
||||
}
|
||||
|
||||
override fun onUpdateAction(titleId: Int?, messageId: Int?, warningId: Int?) {
|
||||
TimeoutHelper.temporarilyDisableTimeout(activity)
|
||||
TimeoutHelper.temporarilyDisableTimeout()
|
||||
// Stop the opening notification
|
||||
DatabaseOpenNotificationService.stop(activity)
|
||||
startOrUpdateDialog(titleId, messageId, warningId)
|
||||
}
|
||||
|
||||
@@ -98,7 +105,18 @@ class ProgressDialogThread(private val activity: FragmentActivity) {
|
||||
onActionFinish?.invoke(actionTask, result)
|
||||
// Remove the progress task
|
||||
ProgressTaskDialogFragment.stop(activity)
|
||||
TimeoutHelper.releaseTemporarilyDisableTimeoutAndLockIfTimeout(activity)
|
||||
TimeoutHelper.releaseTemporarilyDisableTimeout()
|
||||
|
||||
val inTime = if (activity is LockingActivity) {
|
||||
TimeoutHelper.checkTimeAndLockIfTimeout(activity)
|
||||
} else {
|
||||
TimeoutHelper.checkTime(activity)
|
||||
}
|
||||
// Start the opening notification if in time
|
||||
// (databaseOpenService is open manually in Action Open Task)
|
||||
if (actionTask != ACTION_DATABASE_LOAD_TASK && inTime) {
|
||||
DatabaseOpenNotificationService.start(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +144,7 @@ class ProgressDialogThread(private val activity: FragmentActivity) {
|
||||
if (serviceConnection == null) {
|
||||
serviceConnection = object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
|
||||
mBinder = (serviceBinder as DatabaseTaskNotificationService.ActionTaskBinder).apply {
|
||||
mBinder = (serviceBinder as DatabaseTaskNotificationService.ActionTaskBinder?)?.apply {
|
||||
addActionTaskListener(actionTaskListener)
|
||||
getService().checkAction()
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ class DateInstant : Parcelable {
|
||||
fun getDateTimeString(resources: Resources, date: Date): String {
|
||||
return java.text.DateFormat.getDateTimeInstance(
|
||||
java.text.DateFormat.MEDIUM,
|
||||
java.text.DateFormat.MEDIUM,
|
||||
java.text.DateFormat.SHORT,
|
||||
ConfigurationCompat.getLocales(resources.configuration)[0])
|
||||
.format(date)
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ class FieldReferencesEngine {
|
||||
|
||||
if (result != null) {
|
||||
val found = result.entry
|
||||
found?.stopToManageFieldReferences()
|
||||
val wanted = result.wanted
|
||||
|
||||
var data: String? = null
|
||||
@@ -145,22 +146,15 @@ class FieldReferencesEngine {
|
||||
searchParametersV4.setupNone()
|
||||
|
||||
searchParametersV4.searchString = ref.substring(4)
|
||||
if (scan == 'T') {
|
||||
searchParametersV4.searchInTitles = true
|
||||
} else if (scan == 'U') {
|
||||
searchParametersV4.searchInUserNames = true
|
||||
} else if (scan == 'A') {
|
||||
searchParametersV4.searchInUrls = true
|
||||
} else if (scan == 'P') {
|
||||
searchParametersV4.searchInPasswords = true
|
||||
} else if (scan == 'N') {
|
||||
searchParametersV4.searchInNotes = true
|
||||
} else if (scan == 'I') {
|
||||
searchParametersV4.searchInUUIDs = true
|
||||
} else if (scan == 'O') {
|
||||
searchParametersV4.searchInOther = true
|
||||
} else {
|
||||
return null
|
||||
when (scan) {
|
||||
'T' -> searchParametersV4.searchInTitles = true
|
||||
'U' -> searchParametersV4.searchInUserNames = true
|
||||
'A' -> searchParametersV4.searchInUrls = true
|
||||
'P' -> searchParametersV4.searchInPasswords = true
|
||||
'N' -> searchParametersV4.searchInNotes = true
|
||||
'I' -> searchParametersV4.searchInUUIDs = true
|
||||
'O' -> searchParametersV4.searchInOther = true
|
||||
else -> return null
|
||||
}
|
||||
|
||||
val list = ArrayList<EntryKDBX>()
|
||||
|
||||
@@ -21,8 +21,7 @@ package com.kunzisoft.keepass.database.element.node
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
|
||||
class NodeIdUUID : NodeId<UUID> {
|
||||
|
||||
|
||||
@@ -94,7 +94,8 @@ open class Education(val activity: Activity) {
|
||||
R.string.education_copy_username_key,
|
||||
R.string.education_entry_edit_key,
|
||||
R.string.education_password_generator_key,
|
||||
R.string.education_entry_new_field_key)
|
||||
R.string.education_entry_new_field_key,
|
||||
R.string.education_setup_OTP_key)
|
||||
|
||||
|
||||
/**
|
||||
@@ -271,6 +272,18 @@ open class Education(val activity: Activity) {
|
||||
context.resources.getBoolean(R.bool.education_entry_new_field_default))
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the explanatory view to setup OTP has already been displayed.
|
||||
*
|
||||
* @param context The context to open the SharedPreferences
|
||||
* @return boolean value of education_setup_OTP_key key
|
||||
*/
|
||||
fun isEducationSetupOTPPerformed(context: Context): Boolean {
|
||||
val prefs = getEducationSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.education_setup_OTP_key),
|
||||
context.resources.getBoolean(R.bool.education_setup_OTP_default))
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the reset education preference has been reclicked
|
||||
*
|
||||
|
||||
@@ -37,7 +37,7 @@ class EntryEditActivityEducation(activity: Activity)
|
||||
activity.getString(R.string.education_generate_password_title),
|
||||
activity.getString(R.string.education_generate_password_summary))
|
||||
.textColorInt(Color.WHITE)
|
||||
.tintTarget(false)
|
||||
.tintTarget(true)
|
||||
.cancelable(true),
|
||||
object : TapTargetView.Listener() {
|
||||
override fun onTargetClick(view: TapTargetView) {
|
||||
@@ -66,7 +66,7 @@ class EntryEditActivityEducation(activity: Activity)
|
||||
activity.getString(R.string.education_entry_new_field_title),
|
||||
activity.getString(R.string.education_entry_new_field_summary))
|
||||
.textColorInt(Color.WHITE)
|
||||
.tintTarget(false)
|
||||
.tintTarget(true)
|
||||
.cancelable(true),
|
||||
object : TapTargetView.Listener() {
|
||||
override fun onTargetClick(view: TapTargetView) {
|
||||
@@ -82,4 +82,33 @@ class EntryEditActivityEducation(activity: Activity)
|
||||
},
|
||||
R.string.education_entry_new_field_key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and display learning views
|
||||
* Displays the explanation to setup OTP
|
||||
*/
|
||||
fun checkAndPerformedSetUpOTPEducation(educationView: View,
|
||||
onEducationViewClick: ((TapTargetView?) -> Unit)? = null,
|
||||
onOuterViewClick: ((TapTargetView?) -> Unit)? = null): Boolean {
|
||||
return checkAndPerformedEducation(!isEducationSetupOTPPerformed(activity),
|
||||
TapTarget.forView(educationView,
|
||||
activity.getString(R.string.education_setup_OTP_title),
|
||||
activity.getString(R.string.education_setup_OTP_summary))
|
||||
.textColorInt(Color.WHITE)
|
||||
.tintTarget(true)
|
||||
.cancelable(true),
|
||||
object : TapTargetView.Listener() {
|
||||
override fun onTargetClick(view: TapTargetView) {
|
||||
super.onTargetClick(view)
|
||||
onEducationViewClick?.invoke(view)
|
||||
}
|
||||
|
||||
override fun onOuterCircleClick(view: TapTargetView?) {
|
||||
super.onOuterCircleClick(view)
|
||||
view?.dismiss(false)
|
||||
onOuterViewClick?.invoke(view)
|
||||
}
|
||||
},
|
||||
R.string.education_setup_OTP_key)
|
||||
}
|
||||
}
|
||||
@@ -24,14 +24,13 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import com.kunzisoft.keepass.activities.FileDatabaseSelectActivity
|
||||
import com.kunzisoft.keepass.activities.GroupActivity
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
|
||||
class KeyboardLauncherActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
if (Database.getInstance().loaded && TimeoutHelper.checkTime(this))
|
||||
GroupActivity.launchForKeyboardSelection(this, PreferencesUtil.enableReadOnlyDatabase(this))
|
||||
GroupActivity.launchForKeyboardSelection(this)
|
||||
else {
|
||||
// Pass extra to get entry
|
||||
FileDatabaseSelectActivity.launchForKeyboardSelection(this)
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.kunzisoft.keepass.magikeyboard
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.inputmethodservice.InputMethodService
|
||||
import android.inputmethodservice.Keyboard
|
||||
import android.inputmethodservice.KeyboardView
|
||||
@@ -42,8 +42,7 @@ import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.Field
|
||||
import com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.LOCK_ACTION
|
||||
import com.kunzisoft.keepass.utils.REMOVE_ENTRY_MAGIKEYBOARD_ACTION
|
||||
import com.kunzisoft.keepass.utils.*
|
||||
|
||||
class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
|
||||
@@ -55,29 +54,18 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
private var fieldsAdapter: FieldsAdapter? = null
|
||||
private var playSoundDuringCLick: Boolean = false
|
||||
|
||||
private var lockBroadcastReceiver: BroadcastReceiver? = null
|
||||
private var lockReceiver: LockReceiver? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
// Remove the entry and lock the keyboard when the lock signal is receive
|
||||
lockBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
REMOVE_ENTRY_MAGIKEYBOARD_ACTION, LOCK_ACTION -> {
|
||||
lockReceiver = LockReceiver {
|
||||
removeEntryInfo()
|
||||
assignKeyboardView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerReceiver(lockBroadcastReceiver,
|
||||
IntentFilter().apply {
|
||||
addAction(LOCK_ACTION)
|
||||
addAction(REMOVE_ENTRY_MAGIKEYBOARD_ACTION)
|
||||
}
|
||||
)
|
||||
registerLockReceiver(lockReceiver, true)
|
||||
}
|
||||
|
||||
override fun onCreateInputView(): View {
|
||||
@@ -187,12 +175,12 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
private fun switchToPreviousKeyboard() {
|
||||
var imeManager: InputMethodManager? = null
|
||||
try {
|
||||
imeManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imeManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
switchToPreviousInputMethod()
|
||||
} else {
|
||||
window.window?.let { window ->
|
||||
imeManager.switchToLastInputMethod(window.attributes.token)
|
||||
imeManager?.switchToLastInputMethod(window.attributes.token)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@@ -214,8 +202,8 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
KEY_BACK_KEYBOARD -> switchToPreviousKeyboard()
|
||||
|
||||
KEY_CHANGE_KEYBOARD -> {
|
||||
val imeManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imeManager.showInputMethodPicker()
|
||||
(getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?)
|
||||
?.showInputMethodPicker()
|
||||
}
|
||||
KEY_UNLOCK -> {
|
||||
}
|
||||
@@ -301,7 +289,7 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
|
||||
override fun onDestroy() {
|
||||
dismissCustomKeys()
|
||||
unregisterReceiver(lockBroadcastReceiver)
|
||||
unregisterLockReceiver(lockReceiver)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,9 @@ import android.os.Build
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.GroupActivity
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.LOCK_ACTION
|
||||
import com.kunzisoft.keepass.utils.closeDatabase
|
||||
|
||||
class DatabaseOpenNotificationService: LockNotificationService() {
|
||||
|
||||
@@ -36,8 +37,14 @@ class DatabaseOpenNotificationService: LockNotificationService() {
|
||||
private fun stopNotificationAndSendLock() {
|
||||
// Send lock action
|
||||
sendBroadcast(Intent(LOCK_ACTION))
|
||||
// Stop the service
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
override fun actionOnLock() {
|
||||
closeDatabase()
|
||||
// Remove the lock timer (no more needed if it exists)
|
||||
TimeoutHelper.cancelLockTimer(this)
|
||||
// Service is stopped after receive the broadcast
|
||||
super.actionOnLock()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
@@ -60,13 +67,16 @@ class DatabaseOpenNotificationService: LockNotificationService() {
|
||||
|
||||
val database = Database.getInstance()
|
||||
if (database.loaded) {
|
||||
notificationManager?.notify(notificationId, buildNewNotification().apply {
|
||||
startForeground(notificationId, buildNewNotification().apply {
|
||||
setSmallIcon(R.drawable.notification_ic_database_open)
|
||||
setContentTitle(getString(R.string.database_opened))
|
||||
setContentText(database.name + " (" + database.version + ")")
|
||||
setAutoCancel(false)
|
||||
setContentIntent(pendingDatabaseIntent)
|
||||
// Unfortunately swipe is disabled in lollipop+
|
||||
setDeleteIntent(pendingDeleteIntent)
|
||||
addAction(R.drawable.ic_lock_white_24dp, getString(R.string.lock),
|
||||
pendingDeleteIntent)
|
||||
}.build())
|
||||
} else {
|
||||
stopSelf()
|
||||
@@ -80,9 +90,11 @@ class DatabaseOpenNotificationService: LockNotificationService() {
|
||||
companion object {
|
||||
const val ACTION_CLOSE_DATABASE = "ACTION_CLOSE_DATABASE"
|
||||
|
||||
fun startIfAllowed(context: Context) {
|
||||
if (PreferencesUtil.isPersistentNotificationEnable(context)) {
|
||||
// Start the opening notification
|
||||
fun start(context: Context) {
|
||||
// Start the opening notification, keep it active to receive lock
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(Intent(context, DatabaseOpenNotificationService::class.java))
|
||||
} else {
|
||||
context.startService(Intent(context, DatabaseOpenNotificationService::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,31 +19,28 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.notifications
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import com.kunzisoft.keepass.utils.LOCK_ACTION
|
||||
import com.kunzisoft.keepass.utils.LockReceiver
|
||||
import com.kunzisoft.keepass.utils.registerLockReceiver
|
||||
import com.kunzisoft.keepass.utils.unregisterLockReceiver
|
||||
|
||||
abstract class LockNotificationService : NotificationService() {
|
||||
|
||||
private var lockBroadcastReceiver: BroadcastReceiver? = null
|
||||
private var mLockReceiver: LockReceiver? = null
|
||||
|
||||
protected open fun actionOnLock() {
|
||||
// Stop the service in all cases
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
// Register a lock receiver to stop notification service when lock on keyboard is performed
|
||||
lockBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
// Stop the service in all cases
|
||||
stopSelf()
|
||||
mLockReceiver = LockReceiver {
|
||||
actionOnLock()
|
||||
}
|
||||
}
|
||||
registerReceiver(lockBroadcastReceiver,
|
||||
IntentFilter().apply {
|
||||
addAction(LOCK_ACTION)
|
||||
}
|
||||
)
|
||||
registerLockReceiver(mLockReceiver)
|
||||
}
|
||||
|
||||
protected fun stopTask(task: Thread?) {
|
||||
@@ -59,7 +56,7 @@ abstract class LockNotificationService : NotificationService() {
|
||||
|
||||
override fun onDestroy() {
|
||||
|
||||
unregisterReceiver(lockBroadcastReceiver)
|
||||
unregisterLockReceiver(mLockReceiver)
|
||||
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
@@ -248,13 +248,19 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
||||
BiometricUnlockDatabaseHelper.deleteEntryKeyInKeystoreForBiometric(
|
||||
activity,
|
||||
object : BiometricUnlockDatabaseHelper.BiometricUnlockErrorCallback {
|
||||
override fun onInvalidKeyException(e: Exception) {}
|
||||
|
||||
override fun onBiometricException(e: Exception) {
|
||||
fun showException(e: Exception) {
|
||||
Toast.makeText(context,
|
||||
getString(R.string.biometric_scanning_error, e.localizedMessage),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onInvalidKeyException(e: Exception) {
|
||||
showException(e)
|
||||
}
|
||||
|
||||
override fun onBiometricException(e: Exception) {
|
||||
showException(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
CipherDatabaseAction.getInstance(context.applicationContext).deleteAll()
|
||||
|
||||
@@ -31,15 +31,13 @@ object PreferencesUtil {
|
||||
|
||||
var APPEARANCE_CHANGED = false
|
||||
|
||||
private const val KEY_DEFAULT_DATABASE_PATH = "KEY_DEFAULT_DATABASE_PATH"
|
||||
|
||||
fun saveDefaultDatabasePath(context: Context, defaultDatabaseUri: Uri?) {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
prefs?.edit()?.apply {
|
||||
defaultDatabaseUri?.let {
|
||||
putString(KEY_DEFAULT_DATABASE_PATH, it.toString())
|
||||
putString(context.getString(R.string.default_database_path_key), it.toString())
|
||||
} ?: kotlin.run {
|
||||
remove(KEY_DEFAULT_DATABASE_PATH)
|
||||
remove(context.getString(R.string.default_database_path_key))
|
||||
}
|
||||
apply()
|
||||
}
|
||||
@@ -47,7 +45,7 @@ object PreferencesUtil {
|
||||
|
||||
fun getDefaultDatabasePath(context: Context): String? {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getString(KEY_DEFAULT_DATABASE_PATH, "")
|
||||
return prefs.getString(context.getString(R.string.default_database_path_key), "")
|
||||
}
|
||||
|
||||
fun saveNodeSort(context: Context,
|
||||
@@ -207,12 +205,6 @@ object PreferencesUtil {
|
||||
context.resources.getBoolean(R.bool.enable_auto_save_database_default))
|
||||
}
|
||||
|
||||
fun isPersistentNotificationEnable(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.persistent_notification_key),
|
||||
context.resources.getBoolean(R.bool.persistent_notification_default))
|
||||
}
|
||||
|
||||
fun isBiometricUnlockEnable(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.biometric_unlock_enable_key),
|
||||
|
||||
@@ -46,53 +46,63 @@ object TimeoutHelper {
|
||||
private set
|
||||
|
||||
private fun getLockPendingIntent(context: Context): PendingIntent {
|
||||
return PendingIntent.getBroadcast(context,
|
||||
return PendingIntent.getBroadcast(context.applicationContext,
|
||||
REQUEST_ID,
|
||||
Intent(LOCK_ACTION),
|
||||
PendingIntent.FLAG_CANCEL_CURRENT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the current time to check it later with checkTime
|
||||
* Start the lock timer by creating an alarm,
|
||||
* if the method is recalled with a previous lock timer pending, the previous one is deleted
|
||||
*/
|
||||
fun recordTime(context: Context) {
|
||||
// Record timeout time in case timeout service is killed
|
||||
PreferencesUtil.saveCurrentTime(context)
|
||||
|
||||
private fun startLockTimer(context: Context) {
|
||||
if (Database.getInstance().loaded) {
|
||||
val timeout = PreferencesUtil.getAppTimeout(context)
|
||||
|
||||
// No timeout don't start timeout service
|
||||
if (timeout != NEVER) {
|
||||
// No timeout don't start timeout service
|
||||
(context.applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager?)?.let { alarmManager ->
|
||||
val triggerTime = System.currentTimeMillis() + timeout
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
Log.d(TAG, "TimeoutHelper start")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
am.setExact(AlarmManager.RTC, triggerTime, getLockPendingIntent(context))
|
||||
alarmManager.setExact(AlarmManager.RTC, triggerTime, getLockPendingIntent(context))
|
||||
} else {
|
||||
am.set(AlarmManager.RTC, triggerTime, getLockPendingIntent(context))
|
||||
alarmManager.set(AlarmManager.RTC, triggerTime, getLockPendingIntent(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the lock timer currently pending, useful if lock was triggered by another way
|
||||
*/
|
||||
fun cancelLockTimer(context: Context) {
|
||||
(context.applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager?)?.let { alarmManager ->
|
||||
Log.d(TAG, "TimeoutHelper cancel")
|
||||
alarmManager.cancel(getLockPendingIntent(context))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the current time, to check it later with checkTime and start a new lock timer
|
||||
*/
|
||||
fun recordTime(context: Context) {
|
||||
// Record timeout time in case timeout service is killed
|
||||
PreferencesUtil.saveCurrentTime(context)
|
||||
startLockTimer(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the time previously record with recordTime and do the [timeoutAction] if timeout
|
||||
* if temporarilyDisableTimeout() is called, the function as no effect until releaseTemporarilyDisableTimeoutAndCheckTime() is called
|
||||
* return 'false' if timeout, 'true' if in time
|
||||
* return 'false' and send broadcast lock action if timeout, 'true' if in time
|
||||
*/
|
||||
fun checkTime(context: Context, timeoutAction: (() -> Unit)? = null): Boolean {
|
||||
// No effect if temporarily disable
|
||||
if (temporarilyDisableTimeout)
|
||||
return true
|
||||
|
||||
// Cancel the lock PendingIntent
|
||||
if (Database.getInstance().loaded) {
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
Log.d(TAG, "TimeoutHelper cancel")
|
||||
am.cancel(getLockPendingIntent(context))
|
||||
}
|
||||
|
||||
// Check whether the timeout has expired
|
||||
val currentTime = System.currentTimeMillis()
|
||||
|
||||
@@ -115,6 +125,7 @@ object TimeoutHelper {
|
||||
if (diff >= appTimeout) {
|
||||
// We have timed out
|
||||
timeoutAction?.invoke()
|
||||
context.sendBroadcast(Intent(LOCK_ACTION))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -142,27 +153,14 @@ object TimeoutHelper {
|
||||
/**
|
||||
* Temporarily disable timeout, checkTime() function always return true
|
||||
*/
|
||||
fun temporarilyDisableTimeout(context: Context) {
|
||||
fun temporarilyDisableTimeout() {
|
||||
temporarilyDisableTimeout = true
|
||||
|
||||
// Stop the opening notification
|
||||
DatabaseOpenNotificationService.stop(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the temporarily disable timeout and directly call checkTime()
|
||||
* Release the temporarily disable timeout
|
||||
*/
|
||||
fun releaseTemporarilyDisableTimeoutAndLockIfTimeout(context: Context): Boolean {
|
||||
fun releaseTemporarilyDisableTimeout() {
|
||||
temporarilyDisableTimeout = false
|
||||
val inTime = if (context is LockingActivity) {
|
||||
checkTimeAndLockIfTimeout(context)
|
||||
} else {
|
||||
checkTime(context)
|
||||
}
|
||||
if (inTime) {
|
||||
// Start the opening notification
|
||||
DatabaseOpenNotificationService.startIfAllowed(context)
|
||||
}
|
||||
return inTime
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,110 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.utils
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Context.ALARM_SERVICE
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.magikeyboard.MagikIME
|
||||
import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
|
||||
const val DATABASE_START_TASK_ACTION = "com.kunzisoft.keepass.DATABASE_START_TASK_ACTION"
|
||||
const val DATABASE_STOP_TASK_ACTION = "com.kunzisoft.keepass.DATABASE_STOP_TASK_ACTION"
|
||||
|
||||
const val LOCK_ACTION = "com.kunzisoft.keepass.LOCK"
|
||||
|
||||
const val REMOVE_ENTRY_MAGIKEYBOARD_ACTION = "com.kunzisoft.keepass.REMOVE_ENTRY_MAGIKEYBOARD"
|
||||
|
||||
class LockReceiver(var lockAction: () -> Unit) : BroadcastReceiver() {
|
||||
|
||||
var mLockPendingIntent: PendingIntent? = null
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
// If allowed, lock and exit
|
||||
if (!TimeoutHelper.temporarilyDisableTimeout) {
|
||||
intent.action?.let {
|
||||
when (it) {
|
||||
Intent.ACTION_SCREEN_ON -> {
|
||||
cancelLockPendingIntent(context)
|
||||
}
|
||||
Intent.ACTION_SCREEN_OFF -> {
|
||||
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(context)) {
|
||||
mLockPendingIntent = PendingIntent.getBroadcast(context,
|
||||
4575,
|
||||
Intent(intent).apply {
|
||||
action = LOCK_ACTION
|
||||
},
|
||||
0)
|
||||
// Launch the effective action after a small time
|
||||
val first: Long = System.currentTimeMillis() + context.getString(R.string.timeout_screen_off).toLong()
|
||||
val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager?
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
alarmManager?.setExact(AlarmManager.RTC_WAKEUP, first, mLockPendingIntent)
|
||||
} else {
|
||||
alarmManager?.set(AlarmManager.RTC_WAKEUP, first, mLockPendingIntent)
|
||||
}
|
||||
} else {
|
||||
cancelLockPendingIntent(context)
|
||||
}
|
||||
}
|
||||
LOCK_ACTION,
|
||||
REMOVE_ENTRY_MAGIKEYBOARD_ACTION -> lockAction.invoke()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelLockPendingIntent(context: Context) {
|
||||
mLockPendingIntent?.let {
|
||||
val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager?
|
||||
alarmManager?.cancel(mLockPendingIntent)
|
||||
mLockPendingIntent = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.registerLockReceiver(lockReceiver: LockReceiver?,
|
||||
registerRemoveEntryMagikeyboard: Boolean = false) {
|
||||
lockReceiver?.let {
|
||||
registerReceiver(it, IntentFilter().apply {
|
||||
addAction(Intent.ACTION_SCREEN_OFF)
|
||||
addAction(Intent.ACTION_SCREEN_ON)
|
||||
addAction(LOCK_ACTION)
|
||||
if (registerRemoveEntryMagikeyboard)
|
||||
addAction(REMOVE_ENTRY_MAGIKEYBOARD_ACTION)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.unregisterLockReceiver(lockReceiver: LockReceiver?) {
|
||||
lockReceiver?.let {
|
||||
unregisterReceiver(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.closeDatabase() {
|
||||
// Stop the Magikeyboard service
|
||||
stopService(Intent(this, KeyboardEntryNotificationService::class.java))
|
||||
MagikIME.removeEntry(this)
|
||||
|
||||
// Stop the notification service
|
||||
stopService(Intent(this, ClipboardEntryNotificationService::class.java))
|
||||
|
||||
Log.i(Context::class.java.name, "Shutdown after inactivity or manual lock")
|
||||
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?)?.apply {
|
||||
cancelAll()
|
||||
}
|
||||
// Clear data
|
||||
Database.getInstance().closeAndClear(applicationContext.filesDir)
|
||||
}
|
||||
@@ -21,25 +21,77 @@ package com.kunzisoft.keepass.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.text.format.Formatter
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import java.io.Serializable
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
class FileDatabaseInfo : FileInfo {
|
||||
class FileDatabaseInfo : Serializable {
|
||||
|
||||
constructor(context: Context, fileUri: Uri): super(context, fileUri)
|
||||
private var context: Context
|
||||
private var documentFile: DocumentFile? = null
|
||||
var fileUri: Uri?
|
||||
private set
|
||||
|
||||
constructor(context: Context, filePath: String): super(context, filePath)
|
||||
constructor(context: Context, fileUri: Uri) {
|
||||
this.context = context
|
||||
this.fileUri = fileUri
|
||||
init()
|
||||
}
|
||||
|
||||
constructor(context: Context, filePath: String) {
|
||||
this.context = context
|
||||
this.fileUri = UriUtil.parse(filePath)
|
||||
init()
|
||||
}
|
||||
|
||||
fun init() {
|
||||
documentFile = UriUtil.getFileData(context, fileUri)
|
||||
}
|
||||
|
||||
var exists: Boolean = false
|
||||
get() {
|
||||
return documentFile?.exists() ?: field
|
||||
}
|
||||
private set
|
||||
|
||||
var canRead: Boolean = false
|
||||
get() {
|
||||
return documentFile?.canRead() ?: field
|
||||
}
|
||||
private set
|
||||
|
||||
var canWrite: Boolean = false
|
||||
get() {
|
||||
return documentFile?.canWrite() ?: field
|
||||
}
|
||||
private set
|
||||
|
||||
fun getModificationString(): String? {
|
||||
return documentFile?.lastModified()?.let {
|
||||
DateFormat.getDateTimeInstance()
|
||||
.format(Date(it))
|
||||
}
|
||||
}
|
||||
|
||||
fun getSizeString(): String? {
|
||||
return documentFile?.let {
|
||||
Formatter.formatFileSize(context, it.length())
|
||||
}
|
||||
}
|
||||
|
||||
fun retrieveDatabaseAlias(alias: String): String {
|
||||
return when {
|
||||
alias.isNotEmpty() -> alias
|
||||
PreferencesUtil.isFullFilePathEnable(context) -> filePath ?: ""
|
||||
else -> fileName ?: ""
|
||||
PreferencesUtil.isFullFilePathEnable(context) -> fileUri?.path ?: ""
|
||||
else -> if (exists) documentFile?.name ?: "" else fileUri?.path ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
fun retrieveDatabaseTitle(titleCallback: (String)->Unit) {
|
||||
|
||||
fileUri?.let { fileUri ->
|
||||
FileDatabaseHistoryAction.getInstance(context.applicationContext)
|
||||
.getFileDatabaseHistory(fileUri) { fileDatabaseHistoryEntity ->
|
||||
@@ -48,5 +100,4 @@ class FileDatabaseInfo : FileInfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePassDX.
|
||||
*
|
||||
* KeePassDX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.text.format.Formatter
|
||||
import java.io.Serializable
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
open class FileInfo : Serializable {
|
||||
|
||||
var context: Context
|
||||
var fileUri: Uri?
|
||||
var filePath: String? = null
|
||||
var fileName: String? = ""
|
||||
var lastModification = Date(0L)
|
||||
var size: Long = 0L
|
||||
|
||||
constructor(context: Context, fileUri: Uri) {
|
||||
this.context = context
|
||||
this.fileUri = fileUri
|
||||
init()
|
||||
}
|
||||
|
||||
constructor(context: Context, filePath: String) {
|
||||
this.context = context
|
||||
this.fileUri = UriUtil.parse(filePath)
|
||||
init()
|
||||
}
|
||||
|
||||
fun init() {
|
||||
this.filePath = fileUri?.path
|
||||
|
||||
UriUtil.getFileData(context, fileUri)?.let { file ->
|
||||
size = file.length()
|
||||
fileName = file.name
|
||||
lastModification = Date(file.lastModified())
|
||||
}
|
||||
|
||||
if (fileName == null || fileName!!.isEmpty()) {
|
||||
fileName = filePath
|
||||
}
|
||||
}
|
||||
|
||||
fun lastModificationAccessible(): Boolean {
|
||||
return lastModification.after(Date(0L))
|
||||
}
|
||||
|
||||
fun sizeAccessible(): Boolean {
|
||||
return size != 0L
|
||||
}
|
||||
|
||||
fun dataAccessible(): Boolean {
|
||||
return UriUtil.isUriAccessible(context.contentResolver, fileUri)
|
||||
}
|
||||
|
||||
fun getModificationString(): String {
|
||||
return DateFormat.getDateTimeInstance()
|
||||
.format(lastModification)
|
||||
}
|
||||
|
||||
fun getSizeString(): String {
|
||||
return Formatter.formatFileSize(context, size)
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,7 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.utils
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.Locale
|
||||
import java.util.*
|
||||
|
||||
object StringUtil {
|
||||
|
||||
@@ -85,5 +84,17 @@ object StringUtil {
|
||||
|
||||
return currentText
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun UUID.toKeePassRefString(): String {
|
||||
val tempString = toString().replace("-", "").toUpperCase(Locale.ENGLISH)
|
||||
return StringBuffer(reverseString2(tempString.substring(12, 16)))
|
||||
.append(reverseString2(tempString.substring(8, 12)))
|
||||
.append(reverseString2(tempString.substring(0, 8)))
|
||||
.append(reverseString2(tempString.substring(20, 32)))
|
||||
.append(reverseString2(tempString.substring(16, 20))).toString()
|
||||
}
|
||||
|
||||
private fun reverseString2(string: String): String {
|
||||
return string.chunked(2).reversed().joinToString("")
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.kunzisoft.keepass.R
|
||||
@@ -37,26 +36,6 @@ import java.util.*
|
||||
|
||||
object UriUtil {
|
||||
|
||||
fun isUriAccessible(contentResolver: ContentResolver, fileUri: Uri?): Boolean {
|
||||
if (fileUri == null)
|
||||
return false
|
||||
return try {
|
||||
//https://developer.android.com/reference/android/content/res/AssetFileDescriptor
|
||||
contentResolver.openInputStream(fileUri)?.close()
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Log.e(UriUtil.javaClass.name, "Unable to access uri $fileUri : ${e.message}")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isUriWritable(contentResolver: ContentResolver, fileUri: Uri?): Boolean {
|
||||
if (fileUri == null)
|
||||
return false
|
||||
// TODO Uri writeable detection
|
||||
return true
|
||||
}
|
||||
|
||||
fun getFileData(context: Context, fileUri: Uri?): DocumentFile? {
|
||||
if (fileUri == null)
|
||||
return null
|
||||
|
||||
@@ -69,8 +69,8 @@ class AddNodeButtonView @JvmOverloads constructor(context: Context,
|
||||
}
|
||||
|
||||
private fun inflate(context: Context) {
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
inflater.inflate(R.layout.view_button_add_node, this)
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
|
||||
inflater?.inflate(R.layout.view_button_add_node, this)
|
||||
|
||||
addEntryEnable = true
|
||||
addGroupEnable = true
|
||||
@@ -132,7 +132,7 @@ class AddNodeButtonView @JvmOverloads constructor(context: Context,
|
||||
}
|
||||
|
||||
fun showButton() {
|
||||
if (addButtonView?.visibility != VISIBLE)
|
||||
if (isEnable && addButtonView?.visibility != VISIBLE)
|
||||
addButtonView?.show(onAddButtonVisibilityChangedListener)
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@ class AdvancedUnlockInfoView @JvmOverloads constructor(context: Context,
|
||||
|
||||
init {
|
||||
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
inflater.inflate(R.layout.view_advanced_unlock, this)
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
|
||||
inflater?.inflate(R.layout.view_advanced_unlock, this)
|
||||
|
||||
unlockContainerView = findViewById(R.id.fingerprint_container)
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.adapters.EntryAttachmentsAdapter
|
||||
import com.kunzisoft.keepass.adapters.EntryHistoryAdapter
|
||||
@@ -40,8 +41,8 @@ import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.model.EntryAttachment
|
||||
import com.kunzisoft.keepass.otp.OtpElement
|
||||
import com.kunzisoft.keepass.otp.OtpType
|
||||
import com.kunzisoft.keepass.utils.toKeePassRefString
|
||||
import java.util.*
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
|
||||
|
||||
class EntryContentsView @JvmOverloads constructor(context: Context,
|
||||
@@ -91,6 +92,7 @@ class EntryContentsView @JvmOverloads constructor(context: Context,
|
||||
private val historyAdapter = EntryHistoryAdapter(context)
|
||||
|
||||
private val uuidView: TextView
|
||||
private val uuidReferenceView: TextView
|
||||
|
||||
val isUserNamePresent: Boolean
|
||||
get() = userNameContainerView.visibility == View.VISIBLE
|
||||
@@ -99,8 +101,8 @@ class EntryContentsView @JvmOverloads constructor(context: Context,
|
||||
get() = passwordContainerView.visibility == View.VISIBLE
|
||||
|
||||
init {
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
inflater.inflate(R.layout.view_entry_contents, this)
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
|
||||
inflater?.inflate(R.layout.view_entry_contents, this)
|
||||
|
||||
userNameContainerView = findViewById(R.id.entry_user_name_container)
|
||||
userNameView = findViewById(R.id.entry_user_name)
|
||||
@@ -146,6 +148,7 @@ class EntryContentsView @JvmOverloads constructor(context: Context,
|
||||
}
|
||||
|
||||
uuidView = findViewById(R.id.entry_UUID)
|
||||
uuidReferenceView = findViewById(R.id.entry_UUID_reference)
|
||||
|
||||
val attrColorAccent = intArrayOf(R.attr.colorAccent)
|
||||
val taColorAccent = context.theme.obtainStyledAttributes(attrColorAccent)
|
||||
@@ -346,6 +349,7 @@ class EntryContentsView @JvmOverloads constructor(context: Context,
|
||||
|
||||
fun assignUUID(uuid: UUID) {
|
||||
uuidView.text = uuid.toString()
|
||||
uuidReferenceView.text = uuid.toKeePassRefString()
|
||||
}
|
||||
|
||||
/* -------------
|
||||
|
||||
@@ -43,8 +43,8 @@ open class EntryCustomField @JvmOverloads constructor(context: Context,
|
||||
|
||||
init {
|
||||
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
inflater.inflate(R.layout.item_entry_new_field, this)
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
|
||||
inflater?.inflate(R.layout.item_entry_new_field, this)
|
||||
|
||||
labelView = findViewById(R.id.title)
|
||||
valueView = findViewById(R.id.value)
|
||||
|
||||
@@ -21,21 +21,21 @@ package com.kunzisoft.keepass.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.*
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.element.DateInstant
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.icons.IconDrawableFactory
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.icons.assignDefaultDatabaseIcon
|
||||
import com.kunzisoft.keepass.model.Field
|
||||
import org.joda.time.Duration
|
||||
import org.joda.time.Instant
|
||||
|
||||
class EntryEditContentsView @JvmOverloads constructor(context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
@@ -52,16 +52,26 @@ class EntryEditContentsView @JvmOverloads constructor(context: Context,
|
||||
private val entryPasswordLayoutView: TextInputLayout
|
||||
private val entryPasswordView: EditText
|
||||
private val entryConfirmationPasswordView: EditText
|
||||
val generatePasswordView: View
|
||||
private val entryCommentView: EditText
|
||||
private val entryExpiresCheckBox: CompoundButton
|
||||
private val entryExpiresTextView: TextView
|
||||
private val entryNotesView: EditText
|
||||
private val entryExtraFieldsContainer: ViewGroup
|
||||
val addNewFieldButton: View
|
||||
|
||||
private var iconColor: Int = 0
|
||||
private var expiresInstant: DateInstant = DateInstant(Instant.now().plus(Duration.standardDays(30)).toDate())
|
||||
|
||||
var onDateClickListener: OnClickListener? = null
|
||||
set(value) {
|
||||
field = value
|
||||
if (entryExpiresCheckBox.isChecked)
|
||||
entryExpiresTextView.setOnClickListener(value)
|
||||
else
|
||||
entryExpiresTextView.setOnClickListener(null)
|
||||
}
|
||||
|
||||
init {
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
inflater.inflate(R.layout.view_entry_edit_contents, this)
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
|
||||
inflater?.inflate(R.layout.view_entry_edit_contents, this)
|
||||
|
||||
entryTitleLayoutView = findViewById(R.id.entry_edit_container_title)
|
||||
entryTitleView = findViewById(R.id.entry_edit_title)
|
||||
@@ -71,10 +81,14 @@ class EntryEditContentsView @JvmOverloads constructor(context: Context,
|
||||
entryPasswordLayoutView = findViewById(R.id.entry_edit_container_password)
|
||||
entryPasswordView = findViewById(R.id.entry_edit_password)
|
||||
entryConfirmationPasswordView = findViewById(R.id.entry_edit_confirmation_password)
|
||||
generatePasswordView = findViewById(R.id.entry_edit_generate_button)
|
||||
entryCommentView = findViewById(R.id.entry_edit_notes)
|
||||
entryExpiresCheckBox = findViewById(R.id.entry_edit_expires_checkbox)
|
||||
entryExpiresTextView = findViewById(R.id.entry_edit_expires_text)
|
||||
entryNotesView = findViewById(R.id.entry_edit_notes)
|
||||
entryExtraFieldsContainer = findViewById(R.id.entry_edit_advanced_container)
|
||||
addNewFieldButton = findViewById(R.id.entry_edit_add_new_field)
|
||||
|
||||
entryExpiresCheckBox.setOnCheckedChangeListener { _, _ ->
|
||||
assignExpiresDateText()
|
||||
}
|
||||
|
||||
// Retrieve the textColor to tint the icon
|
||||
val taIconColor = context.theme.obtainStyledAttributes(intArrayOf(android.R.attr.textColor))
|
||||
@@ -141,30 +155,44 @@ class EntryEditContentsView @JvmOverloads constructor(context: Context,
|
||||
}
|
||||
}
|
||||
|
||||
fun setOnPasswordGeneratorClickListener(clickListener: () -> Unit) {
|
||||
generatePasswordView.setOnClickListener { clickListener.invoke() }
|
||||
private fun assignExpiresDateText() {
|
||||
entryExpiresTextView.text = if (entryExpiresCheckBox.isChecked) {
|
||||
entryExpiresTextView.setOnClickListener(onDateClickListener)
|
||||
expiresInstant.getDateTimeString(resources)
|
||||
} else {
|
||||
entryExpiresTextView.setOnClickListener(null)
|
||||
resources.getString(R.string.never)
|
||||
}
|
||||
if (fontInVisibility)
|
||||
entryExpiresTextView.applyFontVisibility()
|
||||
}
|
||||
|
||||
var expires: Boolean
|
||||
get() {
|
||||
return entryExpiresCheckBox.isChecked
|
||||
}
|
||||
set(value) {
|
||||
entryExpiresCheckBox.isChecked = value
|
||||
assignExpiresDateText()
|
||||
}
|
||||
|
||||
var expiresDate: DateInstant
|
||||
get() {
|
||||
return expiresInstant
|
||||
}
|
||||
set(value) {
|
||||
expiresInstant = value
|
||||
assignExpiresDateText()
|
||||
}
|
||||
|
||||
var notes: String
|
||||
get() {
|
||||
return entryCommentView.text.toString()
|
||||
return entryNotesView.text.toString()
|
||||
}
|
||||
set(value) {
|
||||
entryCommentView.setText(value)
|
||||
entryNotesView.setText(value)
|
||||
if (fontInVisibility)
|
||||
entryCommentView.applyFontVisibility()
|
||||
}
|
||||
|
||||
fun allowCustomField(allow: Boolean, action: () -> Unit) {
|
||||
addNewFieldButton.apply {
|
||||
if (allow) {
|
||||
visibility = View.VISIBLE
|
||||
setOnClickListener { action.invoke() }
|
||||
} else {
|
||||
visibility = View.GONE
|
||||
setOnClickListener(null)
|
||||
}
|
||||
}
|
||||
entryNotesView.applyFontVisibility()
|
||||
}
|
||||
|
||||
val customFields: MutableList<Field>
|
||||
@@ -228,14 +256,6 @@ class EntryEditContentsView @JvmOverloads constructor(context: Context,
|
||||
fun isValid(): Boolean {
|
||||
var isValid = true
|
||||
|
||||
// Require title
|
||||
if (entryTitleView.text.toString().isEmpty()) {
|
||||
entryTitleLayoutView.error = context.getString(R.string.error_title_required)
|
||||
isValid = false
|
||||
} else {
|
||||
entryTitleLayoutView.error = null
|
||||
}
|
||||
|
||||
// Validate password
|
||||
if (entryPasswordView.text.toString() != entryConfirmationPasswordView.text.toString()) {
|
||||
entryPasswordLayoutView.error = context.getString(R.string.error_pass_match)
|
||||
|
||||
@@ -54,8 +54,8 @@ class EntryEditCustomField @JvmOverloads constructor(context: Context,
|
||||
|
||||
init {
|
||||
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
inflater.inflate(R.layout.view_entry_new_field, this)
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
|
||||
inflater?.inflate(R.layout.view_entry_new_field, this)
|
||||
|
||||
val deleteView = findViewById<View>(R.id.entry_new_field_delete)
|
||||
deleteView.setOnClickListener { deleteViewFromParent() }
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.kunzisoft.keepass.view
|
||||
|
||||
import android.content.Context
|
||||
|
||||
@@ -33,6 +33,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Replace font by monospace, must be called after seText()
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:color="@color/white"
|
||||
tools:targetApi="lollipop">
|
||||
<item>
|
||||
<shape>
|
||||
<stroke android:color="?attr/colorAccent" android:width="1dp"/>
|
||||
<solid android:color="@color/transparent"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape>
|
||||
<stroke android:color="@color/grey" android:width="1dp"/>
|
||||
<solid android:color="@color/transparent"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
9
app/src/main/res/drawable/ic_attach_file_white_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_attach_file_white_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M16.5,6v11.5c0,2.21 -1.79,4 -4,4s-4,-1.79 -4,-4V5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5v10.5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V6H10v9.5c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5V5c0,-2.21 -1.79,-4 -4,-4S7,2.79 7,5v12.5c0,3.04 2.46,5.5 5.5,5.5s5.5,-2.46 5.5,-5.5V6h-1.5z"/>
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M11,17c0,0.55 0.45,1 1,1s1,-0.45 1,-1 -0.45,-1 -1,-1 -1,0.45 -1,1zM11,3v4h2L13,5.08c3.39,0.49 6,3.39 6,6.92 0,3.87 -3.13,7 -7,7s-7,-3.13 -7,-7c0,-1.68 0.59,-3.22 1.58,-4.42L12,13l1.41,-1.41 -6.8,-6.8v0.02C4.42,6.45 3,9.05 3,12c0,4.97 4.02,9 9,9 4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9h-1zM18,12c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1 0.45,1 1,1 1,-0.45 1,-1zM6,12c0,0.55 0.45,1 1,1s1,-0.45 1,-1 -0.45,-1 -1,-1 -1,0.45 -1,1z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/ic_check_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_check_white_24dp.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||
</vector>
|
||||
118
app/src/main/res/drawable/ic_generate_password_white_24dp.xml
Normal file
118
app/src/main/res/drawable/ic_generate_password_white_24dp.xml
Normal file
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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="#ffffff"
|
||||
android:pathData="M9.77344,3.13281 C9.4515,3.1329,9.12601,3.22745,8.83789,3.42188 L1.73828,8.21289
|
||||
C1.25807,8.53693,1.00007,9.06311,1,9.59961
|
||||
C0.999958,9.92151,1.09268,10.247,1.28711,10.5352 L6.07813,17.6328
|
||||
C6.5966,18.4011,7.63207,18.6025,8.40039,18.084 L8.59375,17.9531
|
||||
C7.93444,17.5713,7.49368,16.9397,7.33398,16.2305
|
||||
C7.25701,16.1464,7.21481,16.0308,7.23828,15.9102 L7.27148,15.7422
|
||||
C7.271,15.7299,7.26758,15.7194,7.26758,15.707 L7.09961,15.8184
|
||||
C6.92859,15.9337,6.69736,15.8897,6.58203,15.7188
|
||||
C6.46665,15.5479,6.51062,15.3165,6.68164,15.2012 L6.86523,15.0801
|
||||
L6.65039,15.0371 C6.44804,14.9977,6.31618,14.8059,6.35547,14.6035
|
||||
C6.39476,14.4011,6.58863,14.2693,6.79102,14.3086 L7.00586,14.3516
|
||||
L6.88477,14.1699 C6.76939,13.9991,6.81335,13.7677,6.98438,13.6523
|
||||
C7.1554,13.537,7.38468,13.581,7.5,13.752 L7.62305,13.9316 L7.66406,13.7188
|
||||
C7.69855,13.5416,7.8519,13.4274,8.02539,13.4258 L11.1816,6.77344
|
||||
C11.4309,6.24809,11.8397,5.84958,12.3203,5.58984 L11.1602,3.87109
|
||||
C10.8361,3.3909,10.3119,3.13267,9.77539,3.13281 L9.77344,3.13281 Z
|
||||
M9.70703,5.15625 C9.90938,5.19561,10.0373,5.39136,9.99805,5.59375
|
||||
L9.95898,5.80859 L10.1387,5.68555
|
||||
C10.3097,5.57024,10.5409,5.61618,10.6563,5.78711
|
||||
C10.7716,5.95797,10.7257,6.18741,10.5547,6.30273 L10.375,6.42578
|
||||
L10.5879,6.46484 C10.7902,6.5042,10.922,6.70197,10.8828,6.9043
|
||||
C10.8435,7.1067,10.6496,7.23855,10.4473,7.19922 L10.2344,7.15625
|
||||
L10.3535,7.33594 C10.4689,7.5068,10.4249,7.73817,10.2539,7.85352
|
||||
C10.0829,7.9688,9.85163,7.92289,9.73633,7.75195 L9.61523,7.57031
|
||||
L9.57227,7.78516 C9.53298,7.98758,9.34104,8.11943,9.13867,8.08008
|
||||
C8.93633,8.04072,8.80451,7.84684,8.84375,7.64453 L8.88477,7.43164
|
||||
L8.70313,7.55273 C8.53228,7.66806,8.30282,7.62406,8.1875,7.45313
|
||||
C8.07212,7.28226,8.11609,7.05088,8.28711,6.93555 L8.46875,6.8125
|
||||
L8.25391,6.76953 C8.05154,6.73017,7.91971,6.53833,7.95898,6.33594
|
||||
C7.99827,6.13352,8.19412,6.00167,8.39648,6.04102 L8.61133,6.08398
|
||||
L8.48828,5.90234 C8.3729,5.73148,8.41882,5.50205,8.58984,5.38672
|
||||
C8.76069,5.27139,8.99014,5.31344,9.10547,5.48438 L9.22656,5.66602
|
||||
L9.26758,5.45313 C9.30687,5.25073,9.50467,5.11692,9.70703,5.15625 Z
|
||||
M13.6602,6.24414 C13.0088,6.21529,12.3742,6.57309,12.0762,7.20117
|
||||
L8.40625,14.9375 C8.00883,15.7749,8.36373,16.7686,9.20117,17.166
|
||||
L16.9375,20.8379 C17.7749,21.2353,18.7686,20.8804,19.166,20.043 L22.8379,12.3066
|
||||
C23.2353,11.4693,22.8804,10.4736,22.043,10.0762 L14.3066,6.40625
|
||||
C14.0973,6.30689,13.8773,6.25374,13.6602,6.24414 Z M4.62109,8.49023
|
||||
C4.66856,8.4801,4.71886,8.48028,4.76953,8.49023
|
||||
C4.97188,8.52959,5.10374,8.72142,5.06445,8.92383 L5.02148,9.13867
|
||||
L5.20313,9.01758 C5.37397,8.90227,5.60343,8.94625,5.71875,9.11719
|
||||
C5.83413,9.28805,5.78999,9.51944,5.61914,9.63477 L5.43945,9.75586
|
||||
L5.65039,9.79492 C5.85276,9.83428,5.9865,10.0321,5.94727,10.2344
|
||||
C5.90798,10.4368,5.71213,10.5686,5.50977,10.5293 L5.29688,10.4883
|
||||
L5.41797,10.668 C5.53335,10.8388,5.48938,11.0683,5.31836,11.1836
|
||||
C5.14751,11.2989,4.91806,11.253,4.80273,11.082 L4.67969,10.9023 L4.63672,11.1172
|
||||
C4.59743,11.3196,4.40355,11.4495,4.20117,11.4102
|
||||
C3.99883,11.3708,3.867,11.1769,3.90625,10.9746 L3.94922,10.7617 L3.76953,10.8828
|
||||
C3.59851,10.9981,3.36728,10.9541,3.25195,10.7832
|
||||
C3.13658,10.6123,3.18054,10.3829,3.35156,10.2676 L3.53516,10.1426
|
||||
L3.31836,10.1016 C3.11599,10.0622,2.98612,9.86842,3.02539,9.66602
|
||||
C3.06468,9.46362,3.25857,9.33371,3.46094,9.37305 L3.67578,9.41406
|
||||
L3.55078,9.23242 C3.4354,9.06156,3.48132,8.83214,3.65234,8.7168
|
||||
C3.82337,8.60149,4.05462,8.64547,4.16992,8.81641 L4.29102,8.99805
|
||||
L4.33203,8.7832 C4.36154,8.6314,4.47892,8.52021,4.62109,8.49023 Z
|
||||
M19.2363,10.7852 C19.3814,10.7935,19.5126,10.8876,19.5645,11.0332
|
||||
L19.6367,11.2363 L19.7305,11.041
|
||||
C19.8188,10.8547,20.0403,10.7749,20.2266,10.8633
|
||||
C20.4128,10.9517,20.4908,11.1712,20.4023,11.3574 L20.3086,11.5586
|
||||
L20.5156,11.4844 C20.7098,11.4152,20.9211,11.5148,20.9902,11.709
|
||||
C21.0594,11.9032,20.9597,12.1163,20.7656,12.1855 L20.5586,12.2578
|
||||
L20.7578,12.3516 C20.944,12.44,21.022,12.6614,20.9336,12.8477
|
||||
C20.8452,13.0339,20.6238,13.1118,20.4375,13.0234 L20.2402,12.9297
|
||||
L20.3125,13.1367 C20.3817,13.3309,20.282,13.5421,20.0879,13.6113
|
||||
C19.8937,13.6805,19.6825,13.5809,19.6133,13.3867 L19.5391,13.1777
|
||||
L19.4453,13.377 C19.357,13.5632,19.1374,13.6411,18.9512,13.5527 L18.9492,13.5527
|
||||
C18.763,13.4643,18.6832,13.2429,18.7715,13.0566 L18.8652,12.8613
|
||||
L18.6621,12.9336 C18.4679,13.0027,18.2547,12.9012,18.1855,12.707
|
||||
C18.1164,12.5128,18.218,12.3016,18.4121,12.2324 L18.6172,12.1582
|
||||
L18.4199,12.0664 C18.2337,11.978,18.1557,11.7566,18.2441,11.5703
|
||||
C18.3325,11.384,18.554,11.3042,18.7402,11.3926 L18.9355,11.4863 L18.8613,11.2832
|
||||
C18.7922,11.089,18.8938,10.8759,19.0879,10.8066
|
||||
C19.1364,10.7894,19.188,10.7824,19.2363,10.7852 Z M15.2695,12.1973
|
||||
C15.4146,12.2056,15.5478,12.2997,15.5996,12.4453 L15.6699,12.6484
|
||||
L15.7637,12.4531 C15.852,12.2669,16.0735,12.189,16.2598,12.2773
|
||||
C16.446,12.3657,16.524,12.5872,16.4355,12.7734 L16.3438,12.9707 L16.5488,12.8965
|
||||
C16.743,12.8273,16.9543,12.9289,17.0234,13.123
|
||||
C17.0926,13.3172,16.991,13.5304,16.7969,13.5996 L16.5938,13.6699
|
||||
L16.7891,13.7637 C16.9753,13.8521,17.0552,14.0735,16.9668,14.2598
|
||||
C16.8784,14.446,16.6569,14.5239,16.4707,14.4355 L16.2734,14.3438
|
||||
L16.3477,14.5488 C16.4168,14.743,16.3152,14.9542,16.1211,15.0234
|
||||
C15.9269,15.0926,15.7176,14.993,15.6484,14.7988 L15.5742,14.5918
|
||||
L15.4785,14.7891 C15.3902,14.9753,15.1687,15.0532,14.9824,14.9648
|
||||
C14.7962,14.8765,14.7182,14.657,14.8066,14.4707 L14.8984,14.2734
|
||||
L14.6953,14.3477 C14.5011,14.4168,14.2879,14.3152,14.2188,14.1211
|
||||
C14.1496,13.9269,14.2493,13.7157,14.4434,13.6465 L14.6504,13.5723
|
||||
L14.4531,13.4785 C14.2669,13.3901,14.1889,13.1687,14.2773,12.9824
|
||||
C14.3657,12.7962,14.5872,12.7183,14.7734,12.8066 L14.9688,12.8984
|
||||
L14.8945,12.6953 C14.8254,12.5011,14.9289,12.288,15.123,12.2188
|
||||
C15.1716,12.2015,15.2212,12.1945,15.2695,12.1973 Z M11.3008,13.6113
|
||||
C11.4458,13.6197,11.579,13.7138,11.6309,13.8594 L11.7051,14.0625
|
||||
L11.7969,13.8672 C11.8852,13.6809,12.1087,13.6011,12.2949,13.6895
|
||||
C12.4811,13.7778,12.5591,13.9993,12.4707,14.1855 L12.375,14.3848 L12.582,14.3105
|
||||
C12.7762,14.2414,12.9894,14.341,13.0586,14.5352
|
||||
C13.1277,14.7294,13.0242,14.9425,12.8301,15.0117 L12.627,15.084 L12.8242,15.1777
|
||||
C13.0104,15.2661,13.0885,15.4876,13,15.6738
|
||||
C12.9116,15.8601,12.6902,15.938,12.5039,15.8496 L12.3066,15.7559
|
||||
L12.3789,15.9629 C12.4481,16.1571,12.3484,16.3683,12.1543,16.4375
|
||||
C11.9601,16.5067,11.7489,16.4071,11.6797,16.2129 L11.6055,16.0039
|
||||
L11.5137,16.2031 C11.4253,16.3894,11.2019,16.4693,11.0156,16.3809
|
||||
L11.0156,16.3789 C10.8294,16.2905,10.7514,16.071,10.8398,15.8848
|
||||
L10.9336,15.6875 L10.7305,15.7598
|
||||
C10.5363,15.8289,10.3211,15.7273,10.252,15.5332
|
||||
C10.1828,15.339,10.2844,15.1278,10.4785,15.0586 L10.6855,14.9863
|
||||
L10.4863,14.8926 C10.3001,14.8042,10.2221,14.5828,10.3105,14.3965
|
||||
C10.3989,14.2102,10.6184,14.1304,10.8047,14.2188 L11.0039,14.3125
|
||||
L10.9297,14.1094 C10.8605,13.9152,10.9622,13.702,11.1563,13.6328
|
||||
C11.2048,13.6156,11.2524,13.6086,11.3008,13.6113 Z" />
|
||||
</vector>
|
||||
19
app/src/main/res/drawable/ic_new_field_white_24dp.xml
Normal file
19
app/src/main/res/drawable/ic_new_field_white_24dp.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<group>
|
||||
<path
|
||||
android:fillColor="#fffbfb"
|
||||
android:pathData="M 18 3 L 18 6 L 15 6 L 15 8 L 18 8 L 18 11 L 20 11 L 20 8 L 23 8 L 23 6 L 20 6 L
|
||||
20 3 L 18 3 z M 4 6 C 2.8920005 6 2.0000002 6.8920005 2 8 L 2 18 C 1.9999998
|
||||
19.108 2.8920005 20 4 20 L 18 20 C 19.108 20 19.999999 19.108 20 18 L 20 13 L 18
|
||||
13 L 18 16.533203 C 17.999999 17.345736 17.345736 18 16.533203 18 L 5.4667969 18
|
||||
C 4.6542635 18 3.9999998 17.345736 4 16.533203 L 4 9.4667969 C 4.0000002
|
||||
8.6542635 4.6542635 8 5.4667969 8 L 13 8 L 13 6 L 4 6 z M 5 10 L 5 12 L 17 12 L
|
||||
17 10 L 5 10 z M 5 14 L 5 16 L 17 16 L 17 14 L 5 14 z" />
|
||||
</group>
|
||||
</vector>
|
||||
74
app/src/main/res/drawable/ic_otp_white_24dp.xml
Normal file
74
app/src/main/res/drawable/ic_otp_white_24dp.xml
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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="#ffffff"
|
||||
android:pathData="M9.19922,3.13867 L9.19922,4.73828 L9.19922,6.33984 L10.8008,6.33984
|
||||
L10.8008,4.79297 C13.6944,5.15457,15.9841,7.44622,16.3457,10.3398
|
||||
L14.8008,10.3398 L14.8008,11.9395 L16.3438,11.9395
|
||||
C16.2972,12.3042,16.211,12.6543,16.1074,12.998 L17.7559,12.998
|
||||
C17.9,12.399,18,11.7819,18,11.1387 C18,6.72041,14.4183,3.13867,10,3.13867
|
||||
L9.19922,3.13867 Z M4.7207,5.17383 L4.59766,5.25
|
||||
C4.30768,5.51569,4.03687,5.80202,3.78906,6.10742
|
||||
C3.74408,6.16236,3.76404,6.13658,3.75391,6.14844
|
||||
C2.62072,7.56491,2.00133,9.32361,2,11.1387
|
||||
C2,11.4166,2.02145,11.6889,2.05078,11.959
|
||||
C2.06909,12.128,2.09815,12.2932,2.12695,12.459
|
||||
C2.15024,12.5993,2.17255,12.7392,2.20313,12.877
|
||||
C2.21201,12.9175,2.21732,12.9597,2.22656,13 L2.23633,13
|
||||
C2.42308,13.7827,2.72966,14.5165,3.12695,15.1914
|
||||
C3.30082,14.5824,3.66062,14.0532,4.14453,13.666
|
||||
C4.05066,13.4483,3.95825,13.2294,3.88867,13 L3.89063,13
|
||||
C3.88529,12.9838,3.88033,12.9674,3.875,12.9512
|
||||
C3.77847,12.6238,3.7054,12.2864,3.66211,11.9395 L5.19727,11.9395
|
||||
L5.20703,11.9395 L5.20703,10.3398 L5.19727,10.3398 L3.66406,10.3398
|
||||
C3.69055,10.1356,3.73432,9.93472,3.7793,9.73438
|
||||
C3.81343,9.59208,3.85116,9.45203,3.89258,9.3125
|
||||
C4.09265,8.63652,4.39089,7.99073,4.80859,7.41211 L9.10156,11.7051
|
||||
C9.41495,12.0185,9.91902,12.0185,10.2324,11.7051
|
||||
C10.5458,11.3917,10.5458,10.8876,10.2324,10.5742 L5.14258,5.48242
|
||||
C5.02985,5.36975,4.72451,5.175,4.72266,5.17383 L4.7207,5.17383 Z M6,14
|
||||
C4.892,14,4,14.892,4,16 L4,19 C4,20.108,4.892,21,6,21 L21,21
|
||||
C22.108,21,23,20.108,23,19 L23,16 C23,14.892,22.108,14,21,14 L6,14 Z M7.5,15
|
||||
C7.777,15,8,15.2787,8,15.625 L8,16.293 L8.47266,15.8203
|
||||
C8.71749,15.5755,9.07172,15.5366,9.26758,15.7324
|
||||
C9.46352,15.9283,9.42449,16.2825,9.17969,16.5273 L8.70703,17 L9.375,17
|
||||
C9.72124,17,10,17.223,10,17.5 C10,17.777,9.72124,18,9.375,18 L8.70703,18
|
||||
L9.17969,18.4727 C9.42449,18.7175,9.46367,19.0717,9.26758,19.2676
|
||||
C9.07172,19.4634,8.71749,19.4245,8.47266,19.1797 L8,18.707 L8,19.375
|
||||
C8,19.7212,7.777,20,7.5,20 C7.223,20,7,19.7212,7,19.375 L7,18.707
|
||||
L6.52734,19.1797 C6.28251,19.4245,5.92828,19.4634,5.73242,19.2676
|
||||
C5.53649,19.0717,5.57551,18.7175,5.82031,18.4727 L6.29297,18 L5.625,18
|
||||
C5.27876,18,5,17.777,5,17.5 C5,17.223,5.27876,17,5.625,17 L6.29297,17
|
||||
L5.82031,16.5273 C5.57551,16.2825,5.53633,15.9283,5.73242,15.7324
|
||||
C5.92828,15.5366,6.28251,15.5755,6.52734,15.8203 L7,16.293 L7,15.625
|
||||
C7,15.2787,7.223,15,7.5,15 Z M13.5,15 C13.777,15,14,15.2787,14,15.625 L14,16.293
|
||||
L14.4727,15.8203 C14.7175,15.5755,15.0717,15.5366,15.2676,15.7324
|
||||
C15.4635,15.9283,15.4245,16.2825,15.1797,16.5273 L14.707,17 L15.375,17
|
||||
C15.7212,17,16,17.223,16,17.5 C16,17.777,15.7212,18,15.375,18 L14.707,18
|
||||
L15.1797,18.4727 C15.4245,18.7175,15.4637,19.0717,15.2676,19.2676
|
||||
C15.0717,19.4634,14.7175,19.4245,14.4727,19.1797 L14,18.707 L14,19.375
|
||||
C14,19.7212,13.777,20,13.5,20 C13.223,20,13,19.7212,13,19.375 L13,18.707
|
||||
L12.5273,19.1797 C12.2825,19.4245,11.9283,19.4634,11.7324,19.2676
|
||||
C11.5365,19.0717,11.5755,18.7175,11.8203,18.4727 L12.293,18 L11.625,18
|
||||
C11.2788,18,11,17.777,11,17.5 C11,17.223,11.2788,17,11.625,17 L12.293,17
|
||||
L11.8203,16.5273 C11.5755,16.2825,11.5363,15.9283,11.7324,15.7324
|
||||
C11.9283,15.5366,12.2825,15.5755,12.5273,15.8203 L13,16.293 L13,15.625
|
||||
C13,15.2787,13.223,15,13.5,15 Z M19.5,15 C19.777,15,20,15.2787,20,15.625
|
||||
L20,16.293 L20.4727,15.8203 C20.7175,15.5755,21.0717,15.5366,21.2676,15.7324
|
||||
C21.4635,15.9283,21.4245,16.2825,21.1797,16.5273 L20.707,17 L21.375,17
|
||||
C21.7212,17,22,17.223,22,17.5 C22,17.777,21.7212,18,21.375,18 L20.707,18
|
||||
L21.1797,18.4727 C21.4245,18.7175,21.4637,19.0717,21.2676,19.2676
|
||||
C21.0717,19.4634,20.7175,19.4245,20.4727,19.1797 L20,18.707 L20,19.375
|
||||
C20,19.7212,19.777,20,19.5,20 C19.223,20,19,19.7212,19,19.375 L19,18.707
|
||||
L18.5273,19.1797 C18.2825,19.4245,17.9283,19.4634,17.7324,19.2676
|
||||
C17.5365,19.0717,17.5755,18.7175,17.8203,18.4727 L18.293,18 L17.625,18
|
||||
C17.2788,18,17,17.777,17,17.5 C17,17.223,17.2788,17,17.625,17 L18.293,17
|
||||
L17.8203,16.5273 C17.5755,16.2825,17.5363,15.9283,17.7324,15.7324
|
||||
C17.9283,15.5366,18.2825,15.5755,18.5273,15.8203 L19,16.293 L19,15.625
|
||||
C19,15.2787,19.223,15,19.5,15 Z" />
|
||||
</vector>
|
||||
@@ -1,19 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:width="24dp"
|
||||
android:height="24dp">
|
||||
<group
|
||||
android:translateY="-8">
|
||||
<group
|
||||
android:scaleX="1.777778"
|
||||
android:scaleY="1.777778"
|
||||
android:translateX="-205.4844"
|
||||
android:translateY="-31.99788">
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group>
|
||||
<path
|
||||
android:pathData="M125.00684 31.305444l0 -6.644528c0 -0.263013 -0.21159 -0.47461 -0.4746 -0.47461l-6.48633 0c-1.04808 0 -1.89843 0.850344 -1.89843 1.898435l0 6.328127c0 1.048093 0.85035 1.898437 1.89843 1.898437l6.48633 0c0.26301 0 0.4746 -0.2116 0.4746 -0.474611l0 -0.316409c0 -0.148311 -0.0692 -0.282785 -0.176 -0.369792 -0.083 -0.304543 -0.083 -1.172685 0 -1.477229 0.10684 -0.08504 0.176 -0.219501 0.176 -0.36782zm-6.32812 -4.469236c0 -0.06529 0.0534 -0.118652 0.11866 -0.118652l4.19238 0c0.0653 0 0.11866 0.05343 0.11866 0.118652l0 0.39551c0 0.06529 -0.0534 0.118653 -0.11866 0.118653l-4.19238 0c-0.0653 0 -0.11866 -0.05343 -0.11866 -0.118653l0 -0.39551zm0 1.265621c0 -0.06529 0.0534 -0.118653 0.11866 -0.118653l4.19238 0c0.0653 0 0.11866 0.05343 0.11866 0.118653l0 0.395509c0 0.06529 -0.0534 0.118653 -0.11866 0.118653l-4.19238 0c-0.0653 0 -0.11866 -0.05342 -0.11866 -0.118653l0 -0.395509zm5.0111 4.943847l-5.64391 0c-0.35003 0 -0.63282 -0.282781 -0.63282 -0.632808 0 -0.348045 0.28476 -0.632813 0.63282 -0.632813l5.64391 0c-0.0375 0.338162 -0.0375 0.927466 0 1.265621z"
|
||||
android:fillColor="#ffffff" />
|
||||
</group>
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M 12 1 A 11.000003 11.000001 0 0 0 1 12 A 11.000003 11.000001 0 0 0 4 19.529297
|
||||
L 4 18 L 4 16.119141 A 9.0000001 9.0000001 0 0 1 3 12 A 9.0000001 9.0000001 0 0
|
||||
1 4.9746094 6.3886719 L 17.617188 19.03125 A 9.0000001 9.0000001 0 0 1 12 21 A
|
||||
9.0000001 9.0000001 0 0 1 7.9121094 20 L 6 20 L 4.4609375 20 A 11.000003
|
||||
11.000001 0 0 0 12 23 A 11.000003 11.000001 0 0 0 23 12 A 11.000003 11.000001 0
|
||||
0 0 12 1 z M 12 3 A 9.0000001 9.0000001 0 0 1 21 12 A 9.0000001 9.0000001 0 0 1
|
||||
19.025391 17.611328 L 6.3828125 4.96875 A 9.0000001 9.0000001 0 0 1 12 3 z M
|
||||
16.566406 5.0078125 C 16.256202 5.0423192 15.932855 5.1941212 15.669922
|
||||
5.4570312 L 14.46875 6.6601562 L 17.339844 9.53125 L 18.542969 8.3300781 C
|
||||
18.895877 7.9770126 19.030492 7.5200648 18.966797 7.1269531 C 18.396436
|
||||
6.3122027 17.687797 5.6035638 16.873047 5.0332031 C 16.772829 5.0168634
|
||||
16.672741 4.995984 16.566406 5.0078125 z M 13.449219 7.6777344 L 11.978516
|
||||
9.1503906 L 14.849609 12.021484 L 16.320312 10.548828 L 13.449219 7.6777344 z M
|
||||
9.1484375 11.980469 L 5.65625 15.472656 L 5.015625 18.390625 C 4.9299361
|
||||
18.781059 5.2170219 19.069875 5.6074219 18.984375 L 8.5253906 18.345703 L
|
||||
12.019531 14.851562 L 9.1484375 11.980469 z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,25 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:width="24dp"
|
||||
android:height="24dp">
|
||||
<group
|
||||
android:translateY="-8">
|
||||
<group
|
||||
android:scaleX="1.777778"
|
||||
android:scaleY="1.777778"
|
||||
android:translateX="-205.4844"
|
||||
android:translateY="-31.99788">
|
||||
<group
|
||||
android:scaleX="0.5625"
|
||||
android:scaleY="0.5625"
|
||||
android:translateX="115.585"
|
||||
android:translateY="22.49881">
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group>
|
||||
<path
|
||||
android:pathData="M4.375 3C2.5117466 3 1 4.5117271 1 6.375l0 11.25C1 19.488276 2.5117466 21 4.375 21l11.53125 0C16.373823 21 16.75 20.623825 16.75 20.15625l0 -0.5625c0 -0.263664 -0.122669 -0.503524 -0.3125 -0.658203 -0.147556 -0.54141 -0.147556 -2.08359 0 -2.625 0.189938 -0.151182 0.3125 -0.390619 0.3125 -0.654297l0 -0.669922 -2.378906 2.378906c-0.0089 0.500068 -0.0036 1.014773 0.03711 1.384766l-1.525391 0 -3.0507808 0.667969C9.333649 19.527124 8.7483479 19.391267 8.3632812 19.005859 8.2870146 18.929486 8.2287106 18.840044 8.171875 18.75L4.375 18.75C3.7527244 18.75 3.25 18.24727 3.25 17.625 3.25 17.006253 3.7562267 16.5 4.375 16.5l3.8027344 0L8.6503906 14.349609 12.125 10.875l-6.4140625 0C5.5948486 10.875 5.5 10.780031 5.5 10.664062l0 -0.7031245C5.5 9.8448664 5.5949375 9.75 5.7109375 9.75l7.4531245 0c0.02365 0 0.03921 0.018137 0.06055 0.025391L16.550781 6.4492188 16.75 6.25l0 -2.40625C16.75 3.3761713 16.373823 3 15.90625 3L4.375 3Zm16.015625 1.5898438c-0.30546 0.033979 -0.623906 0.1844704 -0.882813 0.4433593l-1.183593 1.1835938 2.828125 2.828125 1.183594 -1.1835938c0.517848 -0.5180889 0.601704 -1.2752558 0.1875 -1.6894531L21.195312 4.8457031C20.988219 4.6386018 20.696085 4.5558644 20.390625 4.5898438ZM17.320312 7.21875L9.6464844 14.894531 9.015625 17.767578c-0.08448 0.384462 0.1995577 0.670133 0.5839844 0.585938L12.472656 17.724609 20.148438 10.046875 17.320312 7.21875ZM5.7109375 7.5L13.164062 7.5C13.280151 7.5 13.375 7.594987 13.375 7.7109375l0 0.703125C13.375 8.5301336 13.28008 8.625 13.164062 8.625l-7.4531245 0C5.5948486 8.625 5.5 8.5300127 5.5 8.4140625l0 -0.703125C5.5 7.5948664 5.5949375 7.5 5.7109375 7.5Z"
|
||||
android:fillColor="#ffffff" />
|
||||
</group>
|
||||
</group>
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1.01553178"
|
||||
android:pathData="M 16.566406,5.0078125 C 15.782726,5.1133592 15.352352,5.8416456
|
||||
14.802734,6.3261719 14.631179,6.503043 14.326338,6.6788074 14.664062,6.8554688 L
|
||||
17.339844,9.53125 C 17.821017,9.0226367 18.368011,8.5699819 18.791016,8.0117188
|
||||
19.125433,7.5187285 19.054409,6.8047721 18.564453,6.4453125 18.109555,6.0127792
|
||||
17.694742,5.5314578 17.210938,5.1328125 17.01828,5.0182169 16.787242,4.9827103
|
||||
16.566406,5.0078125 Z M 13.449219,7.6777344 C 10.851548,10.276042
|
||||
8.2539034,12.874349 5.65625,15.472656 5.4423833,16.493124 5.1885689,17.506656
|
||||
5,18.53125 c 0.019556,0.598212 0.681759,0.466668 1.0722656,0.351562
|
||||
0.8179378,-0.179027 1.6351872,-0.358083 2.453125,-0.537109 2.5983114,-2.598958
|
||||
5.1966104,-5.197918 7.7949214,-7.796875 z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -17,36 +17,74 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:importantForAutofill="noExcludeDescendants"
|
||||
tools:targetApi="o"
|
||||
android:id="@+id/entry_edit_coordinator_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAutofill="noExcludeDescendants"
|
||||
tools:targetApi="o" >
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/toolbar_default"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/entry_edit_scroll"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="none">
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:titleEnabled="false"
|
||||
app:toolbarId="@+id/toolbar"
|
||||
app:layout_scrollFlags="enterAlways|enterAlwaysCollapsed|scroll|exitUntilCollapsed|snap">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="?attr/actionBarSize">
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimaryDark"
|
||||
android:theme="?attr/toolbarAppearance"
|
||||
android:popupTheme="?attr/toolbarPopupAppearance">
|
||||
<androidx.appcompat.widget.ActionMenuView
|
||||
android:id="@+id/entry_edit_bottom_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="?attr/actionBarSize"/>
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
<View
|
||||
android:id="@+id/biometric_delimiter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/colorAccent"/>
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="?attr/toolbarAppearance"
|
||||
android:popupTheme="?attr/toolbarPopupAppearance"
|
||||
app:layout_collapseMode="pin"
|
||||
tools:targetApi="lollipop" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/entry_edit_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbarStyle="insideOverlay"
|
||||
android:scrollbars="none"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -56,23 +94,22 @@
|
||||
android:id="@+id/entry_edit_contents"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintWidth_percent="@dimen/content_percent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_percent="@dimen/content_percent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/entry_edit_save"
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/entry_edit_validate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:src="@drawable/ic_save_white_24dp"
|
||||
android:contentDescription="@string/content_description_entry_save"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_anchorGravity="bottom|end"
|
||||
app:layout_anchor="@+id/entry_edit_scroll"
|
||||
android:src="@drawable/ic_check_white_24dp"
|
||||
android:contentDescription="@string/validate"
|
||||
app:useCompatPadding="true"
|
||||
style="@style/KeepassDXStyle.Fab"/>
|
||||
|
||||
|
||||
@@ -55,12 +55,18 @@
|
||||
tools:ignore="TextFields" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/generate_password_button"
|
||||
android:layout_margin="@dimen/button_margin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp"
|
||||
android:drawableEnd="@drawable/ic_generate_password_white_24dp"
|
||||
android:drawableRight="@drawable/ic_generate_password_white_24dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingRight="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:text="@string/generate_password" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -27,7 +27,12 @@
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/default_margin">
|
||||
android:layout_marginTop="@dimen/default_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:layout_marginStart="@dimen/card_view_margin"
|
||||
android:layout_marginEnd="@dimen/card_view_margin"
|
||||
android:layout_marginLeft="@dimen/card_view_margin"
|
||||
android:layout_marginRight="@dimen/card_view_margin">
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
@@ -182,10 +187,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:layout_marginStart="@dimen/default_margin"
|
||||
android:layout_marginEnd="@dimen/default_margin"
|
||||
android:layout_marginLeft="@dimen/default_margin"
|
||||
android:layout_marginRight="@dimen/default_margin"
|
||||
android:layout_marginStart="@dimen/card_view_margin"
|
||||
android:layout_marginEnd="@dimen/card_view_margin"
|
||||
android:layout_marginLeft="@dimen/card_view_margin"
|
||||
android:layout_marginRight="@dimen/card_view_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin">
|
||||
<LinearLayout
|
||||
android:id="@+id/extra_strings"
|
||||
@@ -200,10 +205,10 @@
|
||||
android:id="@+id/entry_attachments_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/default_margin"
|
||||
android:layout_marginEnd="@dimen/default_margin"
|
||||
android:layout_marginLeft="@dimen/default_margin"
|
||||
android:layout_marginRight="@dimen/default_margin"
|
||||
android:layout_marginStart="@dimen/card_view_margin"
|
||||
android:layout_marginEnd="@dimen/card_view_margin"
|
||||
android:layout_marginLeft="@dimen/card_view_margin"
|
||||
android:layout_marginRight="@dimen/card_view_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin">
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
@@ -230,11 +235,11 @@
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/default_margin"
|
||||
android:layout_marginEnd="@dimen/default_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:layout_marginLeft="@dimen/default_margin"
|
||||
android:layout_marginRight="@dimen/default_margin">
|
||||
android:layout_marginStart="@dimen/card_view_margin"
|
||||
android:layout_marginEnd="@dimen/card_view_margin"
|
||||
android:layout_marginLeft="@dimen/card_view_margin"
|
||||
android:layout_marginRight="@dimen/card_view_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin">
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
@@ -313,10 +318,10 @@
|
||||
android:id="@+id/entry_history_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/default_margin"
|
||||
android:layout_marginEnd="@dimen/default_margin"
|
||||
android:layout_marginLeft="@dimen/default_margin"
|
||||
android:layout_marginRight="@dimen/default_margin"
|
||||
android:layout_marginStart="@dimen/card_view_margin"
|
||||
android:layout_marginEnd="@dimen/card_view_margin"
|
||||
android:layout_marginLeft="@dimen/card_view_margin"
|
||||
android:layout_marginRight="@dimen/card_view_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin">
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
@@ -401,10 +406,10 @@
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/default_margin"
|
||||
android:layout_marginEnd="@dimen/default_margin"
|
||||
android:layout_marginLeft="@dimen/default_margin"
|
||||
android:layout_marginRight="@dimen/default_margin"
|
||||
android:layout_marginStart="@dimen/card_view_margin"
|
||||
android:layout_marginEnd="@dimen/card_view_margin"
|
||||
android:layout_marginLeft="@dimen/card_view_margin"
|
||||
android:layout_marginRight="@dimen/card_view_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin">
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
@@ -421,15 +426,24 @@
|
||||
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="match_parent">
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/entry_UUID"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
|
||||
</HorizontalScrollView>
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/entry_UUID_reference"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.TextEntryItem" />
|
||||
</HorizontalScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
||||
@@ -25,12 +25,22 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/entry_edit_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/default_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginRight="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
<LinearLayout
|
||||
android:padding="@dimen/default_margin"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:layout_margin="@dimen/default_margin">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/entry_edit_icon_button"
|
||||
@@ -75,21 +85,19 @@
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Password -->
|
||||
<RelativeLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/entry_edit_container_password"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:passwordToggleEnabled="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@+id/entry_edit_generate_button"
|
||||
android:layout_toStartOf="@+id/entry_edit_generate_button">
|
||||
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
android:id="@+id/entry_edit_password"
|
||||
android:layout_width="match_parent"
|
||||
@@ -104,15 +112,13 @@
|
||||
<!-- Confirm Password -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/entry_edit_container_confirmation_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
app:layout_constraintTop_toBottomOf="@+id/entry_edit_container_password"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:passwordToggleEnabled="true"
|
||||
android:contentDescription="@string/content_description_repeat_toggle_password_visibility"
|
||||
android:layout_toLeftOf="@+id/entry_edit_generate_button"
|
||||
android:layout_toStartOf="@+id/entry_edit_generate_button"
|
||||
android:layout_below="@+id/entry_edit_container_password">
|
||||
android:contentDescription="@string/content_description_repeat_toggle_password_visibility">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
android:id="@+id/entry_edit_confirmation_password"
|
||||
@@ -124,20 +130,7 @@
|
||||
android:maxLines="1"
|
||||
android:hint="@string/entry_confpassword"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/entry_edit_generate_button"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:padding="12dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_margin="8dp"
|
||||
android:src="@drawable/ic_key_white_24dp"
|
||||
android:contentDescription="@string/content_description_password_generator"
|
||||
android:tint="?attr/colorAccent"/>
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!-- URL -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
@@ -155,7 +148,47 @@
|
||||
android:hint="@string/entry_url"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Comment -->
|
||||
<!-- Expires -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/entry_edit_expires_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:text="@string/entry_expires"
|
||||
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle"/>
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/entry_edit_expires_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/entry_edit_expires_label"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Large"
|
||||
tools:text="2020-03-04 05:00"/>
|
||||
<androidx.appcompat.widget.AppCompatSpinner
|
||||
android:id="@+id/entry_edit_expires_presets"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/entry_edit_expires_label"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/entry_edit_expires_text"
|
||||
app:layout_constraintEnd_toStartOf="@+id/entry_edit_expires_checkbox"/>
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/entry_edit_expires_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/entry_edit_expires_label"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!-- Notes -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
@@ -171,22 +204,16 @@
|
||||
android:inputType="textMultiLine"
|
||||
android:hint="@string/entry_notes"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/entry_edit_advanced_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/default_margin"
|
||||
android:paddingBottom="@dimen/default_margin"
|
||||
app:layout_constraintTop_toBottomOf="@+id/entry_edit_container">
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/entry_edit_add_new_field"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_add_white_24dp"
|
||||
android:contentDescription="@string/content_description_add_field"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:scaleType="centerCrop"/>
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -17,14 +17,23 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<RelativeLayout
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginRight="0dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAutofill="noExcludeDescendants"
|
||||
android:background="@drawable/background_stroke_element"
|
||||
tools:targetApi="o">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
@@ -32,10 +41,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingEnd="12dp">
|
||||
android:paddingLeft="@dimen/default_margin"
|
||||
android:paddingStart="@dimen/default_margin"
|
||||
android:paddingRight="@dimen/default_margin"
|
||||
android:paddingEnd="@dimen/default_margin">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/entry_new_field_label"
|
||||
@@ -73,10 +82,10 @@
|
||||
android:id="@+id/value_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingLeft="@dimen/default_margin"
|
||||
android:paddingStart="@dimen/default_margin"
|
||||
android:paddingRight="@dimen/default_margin"
|
||||
android:paddingEnd="@dimen/default_margin"
|
||||
android:layout_below="@+id/title_container">
|
||||
|
||||
<EditText
|
||||
@@ -90,3 +99,5 @@
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
46
app/src/main/res/menu/entry_edit.xml
Normal file
46
app/src/main/res/menu/entry_edit.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
|
||||
This file is part of KeePassDX.
|
||||
|
||||
KeePassDX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
KeePassDX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:ignore="AlwaysShowAction">
|
||||
<item android:id="@+id/menu_add_field"
|
||||
android:icon="@drawable/ic_new_field_white_24dp"
|
||||
android:title="@string/entry_add_field"
|
||||
android:orderInCategory="92"
|
||||
app:showAsAction="always" />
|
||||
<!--
|
||||
<item android:id="@+id/menu_add_attachment"
|
||||
android:icon="@drawable/ic_attach_file_white_24dp"
|
||||
android:title="@string/entry_add_attachment"
|
||||
android:orderInCategory="93"
|
||||
app:showAsAction="always" />
|
||||
-->
|
||||
<item android:id="@+id/menu_add_otp"
|
||||
android:icon="@drawable/ic_otp_white_24dp"
|
||||
android:title="@string/entry_setup_otp"
|
||||
android:orderInCategory="94"
|
||||
app:showAsAction="always" />
|
||||
<item android:id="@+id/menu_generate_password"
|
||||
android:icon="@drawable/ic_generate_password_white_24dp"
|
||||
android:title="@string/entry_password_generator"
|
||||
android:orderInCategory="95"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
|
||||
This file is part of KeePassDX.
|
||||
|
||||
KeePassDX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
KeePassDX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/menu_add_otp"
|
||||
android:icon="@drawable/ic_av_timer_white_24dp"
|
||||
android:title="@string/entry_setup_otp"
|
||||
android:orderInCategory="91"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
||||
@@ -50,7 +50,6 @@
|
||||
<string name="error_invalid_path">تأكد أن المسار صحيح.</string>
|
||||
<string name="error_no_name">ادخل اسمًا.</string>
|
||||
<string name="error_pass_match">كلمتا السر غير متطابقتين.</string>
|
||||
<string name="error_title_required">اكتب عنوانًا.</string>
|
||||
<string name="field_name">اسم الحقل</string>
|
||||
<string name="field_value">قيمة الحقل</string>
|
||||
<string name="generate_password">توليد كلمة سر</string>
|
||||
@@ -260,7 +259,7 @@
|
||||
<string name="content_description_add_entry">إضافة إدخال</string>
|
||||
<string name="content_description_add_group">إضافة مجموعة</string>
|
||||
<string name="content_description_file_information">معلومات الملف</string>
|
||||
<string name="content_description_password_generator">مولد كلمة السر</string>
|
||||
<string name="entry_password_generator">مولد كلمة السر</string>
|
||||
<string name="content_description_background">الخلفية</string>
|
||||
<string name="rounds">دورات التحويل</string>
|
||||
<string name="rounds_explanation">توفر الدورات الاضافية ضد هجوم توليد التركيبات ،لكنها تبطئ التحميل والحفظ.</string>
|
||||
@@ -272,9 +271,8 @@
|
||||
<string name="content_description_node_children">العقد الفرعية</string>
|
||||
<string name="content_description_add_node">أضف عقدة</string>
|
||||
<string name="content_description_entry_icon">ايقونة المدخل</string>
|
||||
<string name="content_description_entry_save">حفظ المدخل</string>
|
||||
<string name="content_description_password_length">طول كلمة السر</string>
|
||||
<string name="content_description_add_field">أضف حقل</string>
|
||||
<string name="entry_add_field">أضف حقل</string>
|
||||
<string name="content_description_remove_field">أزل حقل</string>
|
||||
<string name="error_move_entry_here">لا يمكنك نقل مدخل هنا.</string>
|
||||
<string name="error_copy_entry_here">لا يمكنك نسخ مدخل هنا.</string>
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
<string name="error_pass_gen_type">Has de seleccionar almenys un tipus de generador de contrasenyes</string>
|
||||
<string name="error_pass_match">Les contrasenyes no coincideixen.</string>
|
||||
<string name="error_rounds_too_large">Massa passades. Establint a 2147483648.</string>
|
||||
<string name="error_title_required">És necessari un títol.</string>
|
||||
<string name="error_wrong_length">Insereix un enter positiu al camp longitud</string>
|
||||
<string name="file_browser">Explorador d\'arxius</string>
|
||||
<string name="generate_password">Generar contrasenya</string>
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
<string name="error_pass_match">Zadání hesla se neshodují.</string>
|
||||
<string name="error_rounds_too_large">Příliš vysoký „Počet průchodů“. Nastavuji na 2147483648.</string>
|
||||
<string name="error_string_key">Je třeba, aby každý řetězec měl název kolonky.</string>
|
||||
<string name="error_title_required">Přidejte název.</string>
|
||||
<string name="error_wrong_length">Do nastavení „Délka“ zadejte celé kladné číslo.</string>
|
||||
<string name="field_name">Název pole</string>
|
||||
<string name="field_value">Hodnota pole</string>
|
||||
@@ -284,7 +283,7 @@
|
||||
<string name="education_generate_password_title">Vytvořte k záznamu silné heslo.</string>
|
||||
<string name="education_generate_password_summary">Vygenerujte silné heslo pro svou položku, definujte je podle kritérií formuláře, a nezapomeňte na bezpečné heslo.</string>
|
||||
<string name="education_entry_new_field_title">Přidat vlastní kolonky</string>
|
||||
<string name="education_entry_new_field_summary">Chcete-li zaregistrovat základní kolonku, která není ve výchozím stavu k dispozici, jednoduše vyplňte novou kolonku. Novou kolonku můžete také nastavit jako chráněnou.</string>
|
||||
<string name="education_entry_new_field_summary">Registrovat další kolonku, zadat hodnotu a volitelně ji ochránit.</string>
|
||||
<string name="education_unlock_title">Odemknout databázi</string>
|
||||
<string name="education_read_only_title">Ochraňte svou databázi před zápisem</string>
|
||||
<string name="education_read_only_summary">Změnit režim otevírání pro dané sezení.
|
||||
@@ -302,7 +301,7 @@
|
||||
<string name="education_sort_summary">Vyberte řazení položek a skupin.</string>
|
||||
<string name="education_donation_title">Zapojit se</string>
|
||||
<string name="education_donation_summary">Zapojte se a pomozte zvýšit stabilitu, bezpečnost a přidávání dalších funkcí.</string>
|
||||
<string name="html_text_ad_free">Na rozdíl od mnoha aplikací pro správu hesel, tato je <strong>bez reklam</strong>, je <strong>svobodným softwarem</strong> a <strong> pod copyleft licencí</strong>. <strong>Nesbírá žádné osobní údaje</strong> v jakékoli formě, bez ohledu na to, jakou verzi používáte.</string>
|
||||
<string name="html_text_ad_free">Na rozdíl od mnoha aplikací pro správu hesel, tato je <strong>bez reklam</strong>", je "<strong>svobodný software pod copyleft licencí</strong> a nesbírá žádné osobní údaje na svých serverech bez ohledu na to, jakou verzi používáte.</string>
|
||||
<string name="html_text_buy_pro">Zakoupením varianty „pro“ získáte přístup k tomuto <strong>vizuálnímu stylu</strong> a hlavně pomůžete <strong>uskutečnění komunitních projektů.</strong></string>
|
||||
<string name="html_text_feature_generosity">Tento <strong>vizuální styl</strong> je k dispozici díky vaší štědrosti.</string>
|
||||
<string name="html_text_donation">Pro zajištění svobody nás všech a pokračování aktivity, počítáme s vaším <strong>přispěním.</strong></string>
|
||||
@@ -362,10 +361,9 @@
|
||||
<string name="content_description_keyfile_checkbox">Checkbox souboru s klíčem</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Přepni ukázání hesla</string>
|
||||
<string name="content_description_entry_icon">Ikona záznamu</string>
|
||||
<string name="content_description_entry_save">Uložit záznam</string>
|
||||
<string name="content_description_password_generator">Generátor hesel</string>
|
||||
<string name="entry_password_generator">Generátor hesel</string>
|
||||
<string name="content_description_password_length">Délka hesla</string>
|
||||
<string name="content_description_add_field">Přidej pole</string>
|
||||
<string name="entry_add_field">Přidej pole</string>
|
||||
<string name="content_description_remove_field">Odebrat pole</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">Sem záznam přesunout nelze.</string>
|
||||
@@ -412,8 +410,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">Prověřením toho dialogu opraví KeePassDX chybu (založením nového UUID pro duplikáty) a bude pokračovat.</string>
|
||||
<string name="database_opened">Databáze otevřena</string>
|
||||
<string name="clipboard_explanation_summary">Kopírujte pole záznamů pomocí schránky Vašeho zařízení</string>
|
||||
<string name="persistent_notification_title">Trvalé oznámení</string>
|
||||
<string name="persistent_notification_summary">Přidat oznámení, když je databáze otevřena</string>
|
||||
<string name="advanced_unlock_explanation_summary">K snadnějšímu otevření databáze použijte pokročilé odemknutí</string>
|
||||
<string name="database_data_compression_title">Komprese dat</string>
|
||||
<string name="database_data_compression_summary">Komprese dat snižuje velikost databáze.</string>
|
||||
@@ -450,9 +446,26 @@
|
||||
<string name="keyboard_auto_go_action_summary">Automatická akce klíče Jít po stisknutí klíče Pole</string>
|
||||
<string name="download_attachment">Stáhnout %1$s</string>
|
||||
<string name="download_initialization">Zahajuji…</string>
|
||||
<string name="download_progression">Probíhá: %1$d%</string>
|
||||
<string name="download_progression">Probíhá: %1$d%</string>
|
||||
<string name="download_finalization">Dokončuji…</string>
|
||||
<string name="download_complete">Ukončeno! Klepnout pro otevření souboru.</string>
|
||||
<string name="hide_expired_entries_title">Skrýt propadlé záznamy</string>
|
||||
<string name="hide_expired_entries_summary">Propadlé záznamy budou skryty</string>
|
||||
<string name="contact">Kontakt</string>
|
||||
<string name="contribution">Příspěvky</string>
|
||||
<string name="feedback">Feedback</string>
|
||||
<string name="auto_focus_search_title">Snadné hledání</string>
|
||||
<string name="auto_focus_search_summary">Při otevření databáze žádat hledání</string>
|
||||
<string name="remember_database_locations_title">Uložit umístění databází</string>
|
||||
<string name="remember_database_locations_summary">Pamatovat si umístění databází</string>
|
||||
<string name="remember_keyfile_locations_title">Uložit umístění souborů s klíči</string>
|
||||
<string name="remember_keyfile_locations_summary">Pamatovat si umístění souborů s klíči</string>
|
||||
<string name="show_recent_files_title">Ukázat nedávné soubory</string>
|
||||
<string name="show_recent_files_summary">Ukázat umístění nedávných databází</string>
|
||||
<string name="hide_broken_locations_title">Skrýt špatné odkazy na databáze</string>
|
||||
<string name="hide_broken_locations_summary">Skrýt špatné odkazy v seznamu nedávných databází</string>
|
||||
<string name="warning_database_read_only">Udělit právo zápisu pro uložení změn v databázi</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft je <strong>otevřený software</strong> a <strong>bey reklam</strong>.
|
||||
\nJe poskytován jak je, pod licencí <strong>GPLv3</strong>, bez jakékoli záruky.</string>
|
||||
<string name="html_about_contribution">Abychom si <strong>udrželi svoji svobodu</strong>, <strong>opravili chyby</strong>,<strong>doplnili funkce</strong> a <strong>byli vždy aktivní</strong>, počítáme s Vaším <strong>přispěním</strong>.</string>
|
||||
</resources>
|
||||
@@ -70,7 +70,6 @@
|
||||
<string name="error_pass_match">Adgangskoderne er ikke ens.</string>
|
||||
<string name="error_rounds_too_large">\"Transformation Runder\" er for stor. Sættes til 2147483648.</string>
|
||||
<string name="error_string_key">Hver streng skal have et feltnavn.</string>
|
||||
<string name="error_title_required">Tilføj en titel.</string>
|
||||
<string name="error_wrong_length">Angiv et positivt heltal i feltet \"Længde\".</string>
|
||||
<string name="field_name">Feltnavn</string>
|
||||
<string name="field_value">Feltværdi</string>
|
||||
@@ -283,7 +282,7 @@
|
||||
<string name="education_generate_password_title">Opret en stærk adgangskode til posten.</string>
|
||||
<string name="education_generate_password_summary">Generer en stærk kodeord til at forbinde elementet, definer det i henhold til kriteriet for formularen og glem ikke et sikkert kodeord.</string>
|
||||
<string name="education_entry_new_field_title">Tilføj brugerdefinerede felter</string>
|
||||
<string name="education_entry_new_field_summary">Registrer et grundlæggende felt, der ikke er oprettet, ved at udfylde et ny, som også kan beskyttes.</string>
|
||||
<string name="education_entry_new_field_summary">Registrer et ekstra felt, tilføj en værdi og beskyt det eventuelt.</string>
|
||||
<string name="education_unlock_title">Lås databasen op</string>
|
||||
<string name="education_read_only_title">Skrivebeskyt databasen</string>
|
||||
<string name="education_read_only_summary">Skift åbningstilstanden for sessionen.
|
||||
@@ -301,8 +300,8 @@
|
||||
<string name="education_donation_title">Deltag</string>
|
||||
<string name="education_donation_summary">Bidrag til at øge stabiliteten, sikkerheden og med at tilføje flere funktioner.</string>
|
||||
<string name="html_text_ad_free">I modsætning til andre programmer til adgangskodeadministration er denne <strong>annoncefri</strong>, <strong>copyleft fri software</strong>, og indsamler ikke personlige data, uanset hvilken version der bruges.</string>
|
||||
<string name="html_text_buy_pro">Ved at købe pro-versionen, er der adgang til <strong>visuel funktionen</strong>, og det vil især hjælpe <strong>gennemførelsen af lokale projekter.</strong></string>
|
||||
<string name="html_text_feature_generosity">Denne <strong>visuelle funktion</strong> er tilgængelige takket være bidrag.</string>
|
||||
<string name="html_text_buy_pro">Ved at købe pro-versionen, er der adgang til <strong>visuel stil</strong>, og det vil især hjælpe <strong>gennemførelsen af lokale projekter.</strong></string>
|
||||
<string name="html_text_feature_generosity">Denne <strong>visuelle stil</strong> er tilgængelige takket være bidrag.</string>
|
||||
<string name="html_text_donation">For at bevare uafhængighed og altid at være aktiv, regner vi med <strong>bidrag.</strong></string>
|
||||
<string name="html_text_dev_feature">Funktionen er <strong>under udvikling</strong>, og det kræver <strong>bidrag</strong>, for snart at være tilgængelig.</string>
|
||||
<string name="html_text_dev_feature_buy_pro">Ved at købe <strong>pro</strong> versionen,</string>
|
||||
@@ -361,10 +360,9 @@
|
||||
<string name="content_description_keyfile_checkbox">Afkrydsningsfelt for nøglefil</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Gentag for at skifte synlighed for adgangskode</string>
|
||||
<string name="content_description_entry_icon">Indtastningsikon</string>
|
||||
<string name="content_description_entry_save">Gem indtastning</string>
|
||||
<string name="content_description_password_generator">Adgangskodegenerator</string>
|
||||
<string name="entry_password_generator">Adgangskodegenerator</string>
|
||||
<string name="content_description_password_length">Længde på adgangskode</string>
|
||||
<string name="content_description_add_field">Tilføj felt</string>
|
||||
<string name="entry_add_field">Tilføj felt</string>
|
||||
<string name="content_description_remove_field">Fjern felt</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="list_groups_show_number_entries_title">Vis antal poster</string>
|
||||
@@ -411,8 +409,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">Ved at godkende dialogboksen, vil KeePassDX løse problemet (ved at generere nye UUID\'er for dubletter) og fortsætte.</string>
|
||||
<string name="database_opened">Database åbnet</string>
|
||||
<string name="clipboard_explanation_summary">Kopier indtastningsfelter ved hjælp af enhedens udklipsholder</string>
|
||||
<string name="persistent_notification_title">Vedvarende meddelelse</string>
|
||||
<string name="persistent_notification_summary">Tilføj en meddelelse, når databasen er åben</string>
|
||||
<string name="advanced_unlock_explanation_summary">Brug avanceret oplåsning for at gøre det lettere at åbne en database</string>
|
||||
<string name="database_data_compression_title">Datakomprimering</string>
|
||||
<string name="database_data_compression_summary">Datakomprimering reducerer databasens størrelse.</string>
|
||||
@@ -449,9 +445,26 @@
|
||||
<string name="keyboard_auto_go_action_summary">Handling af Gå-tasten udføres automatisk, efter der er trykket på en Felt nøgle</string>
|
||||
<string name="download_attachment">Hent %1$s</string>
|
||||
<string name="download_initialization">Initialiserer…</string>
|
||||
<string name="download_progression">I gang: %1$d%</string>
|
||||
<string name="download_progression">I gang: %1$d%</string>
|
||||
<string name="download_finalization">Færdiggørelse…</string>
|
||||
<string name="download_complete">Komplet! Tryk for at åbne filen.</string>
|
||||
<string name="hide_expired_entries_title">Skjul udløbne poster</string>
|
||||
<string name="hide_expired_entries_summary">Udløbne poster vil blive skjult</string>
|
||||
<string name="contact">Kontakt</string>
|
||||
<string name="contribution">Bidrag</string>
|
||||
<string name="feedback">Tilbagemelding</string>
|
||||
<string name="html_about_licence">KeePassDX ©%1$d Kunzisoft er <strong>open source</strong> og <strong>uden reklamer</strong>.
|
||||
\nDet leveres som det er under <strong>GPLv3</strong> licens uden nogen garanti.</string>
|
||||
<string name="html_about_contribution">For at <strong>holde vores frihed</strong>, <strong>rette fejl</strong>, <strong>tilføje funktioner</strong> og <strong>at være altid aktiv</strong>, regner vi med <strong>bidrag</strong>.</string>
|
||||
<string name="auto_focus_search_title">Hurtig søgning</string>
|
||||
<string name="auto_focus_search_summary">Anmod om en søgning når en database åbnes</string>
|
||||
<string name="remember_database_locations_title">Gem placering af databaser</string>
|
||||
<string name="remember_database_locations_summary">Husk placeringen af databaser</string>
|
||||
<string name="remember_keyfile_locations_title">Gem placering af nøglefiler</string>
|
||||
<string name="remember_keyfile_locations_summary">Husker placeringen af databasernøglefiler</string>
|
||||
<string name="show_recent_files_title">Vis seneste filer</string>
|
||||
<string name="show_recent_files_summary">Vis placeringer af de seneste databaser</string>
|
||||
<string name="hide_broken_locations_title">Skjule brudte databaselinks</string>
|
||||
<string name="hide_broken_locations_summary">Skjul brudte links på listen over seneste databaser</string>
|
||||
<string name="warning_database_read_only">Giv fil skriveadgang for at gemme databasændringer</string>
|
||||
</resources>
|
||||
@@ -75,7 +75,6 @@
|
||||
<string name="error_pass_match">Die Passwörter stimmen nicht überein.</string>
|
||||
<string name="error_rounds_too_large">„Transformationsrunden“ zu hoch. Wird auf 2147483648 eingestellt.</string>
|
||||
<string name="error_string_key">Für jede Zeichenfolge ist ein Feldname notwendig.</string>
|
||||
<string name="error_title_required">Titel hinzufügen.</string>
|
||||
<string name="error_wrong_length">Eine positive ganze Zahl in das Feld „Länge“ eingeben.</string>
|
||||
<string name="field_name">Feldname</string>
|
||||
<string name="field_value">Feldwert</string>
|
||||
@@ -270,7 +269,7 @@
|
||||
<string name="education_generate_password_title">Ein starkes Passwort für den Eintrag erstellen.</string>
|
||||
<string name="education_generate_password_summary">Erzeugung eines starken Passworts, das mit dem Eintrag verknüpft wird, nach Kriterien, die einfach in einem Formular festgelegt werden. Dabei an die Passwortsicherheit denken.</string>
|
||||
<string name="education_entry_new_field_title">Benutzerdefinierte Felder hinzufügen</string>
|
||||
<string name="education_entry_new_field_summary">Ein wichtiges, nicht mitgeliefertes Feld erfassen, indem ein neues Feld ausgefüllt wird, das sich auch schützen lässt.</string>
|
||||
<string name="education_entry_new_field_summary">Tragen Sie ein zusätzliches Feld ein, fügen Sie einen Wert hinzu und schützen Sie es optional.</string>
|
||||
<string name="education_unlock_title">Die Datenbank entsperren</string>
|
||||
<string name="education_field_copy_title">Ein Feld kopieren</string>
|
||||
<string name="education_field_copy_summary">Kopierte Felder können an beliebiger Stelle eingefügt werden.
|
||||
@@ -289,10 +288,10 @@
|
||||
<string name="html_text_dev_feature">Diese Funktion ist <strong>in Entwicklung</strong> und erfordert <strong>Ihren Beitrag</strong>, um bald verfügbar zu sein.</string>
|
||||
<string name="html_text_dev_feature_buy_pro">Durch den Kauf der <strong>Pro-Version</strong>,</string>
|
||||
<string name="html_text_dev_feature_contibute">Durch Ihr <strong>Mitwirken</strong>,</string>
|
||||
<string name="html_text_dev_feature_encourage">du bestärkst die Entwickler:innen, <strong>neue Funktionen</strong> einzuführen und gemäß deinen<strong> Anmerkungen <strong>Fehler auszumerzen</strong>.<strong>neue Funktionen</strong> einzuführen und gemäß Ihren Anmerkungen <strong>Fehler auszumerzen</strong>.</string>
|
||||
<string name="html_text_dev_feature_encourage">Sie ermutigen die Entwickler:innen, <strong>neue Funktionen</strong> einzuführen und gemäß Ihren Anmerkungen <strong>Fehler zu beheben</strong>.</string>
|
||||
<string name="html_text_dev_feature_thanks">Vielen Dank für Ihre Unterstützung.</string>
|
||||
<string name="html_text_dev_feature_work_hard">Wir bemühen uns, diese Funktion bald zu veröffentlichen.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Vergessen Sie nicht, Ihre App aktuell zu halten indem sie neue Versionen installieren.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Vergessen Sie nicht, Ihre App aktuell zu halten, indem Sie neue Versionen installieren.</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="contribute">Unterstützen</string>
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
@@ -358,10 +357,9 @@
|
||||
<string name="content_description_add_group">Gruppe hinzufügen</string>
|
||||
<string name="content_description_file_information">Datei-Informationen</string>
|
||||
<string name="content_description_entry_icon">Symbol für den Eintrag</string>
|
||||
<string name="content_description_entry_save">Eintrag speichern</string>
|
||||
<string name="content_description_password_generator">Passwort-Generator</string>
|
||||
<string name="entry_password_generator">Passwort-Generator</string>
|
||||
<string name="content_description_password_length">Passwortlänge</string>
|
||||
<string name="content_description_add_field">Feld hinzufügen</string>
|
||||
<string name="entry_add_field">Feld hinzufügen</string>
|
||||
<string name="content_description_remove_field">Feld entfernen</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="list_groups_show_number_entries_title">Anzahl der Einträge anzeigen</string>
|
||||
@@ -415,8 +413,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">Durch die Validierung dieses Dialogs wird KeePassDX das Problem (durch Erzeugung neuer UUIDs für Duplikate) beheben und weiter ausgeführt.</string>
|
||||
<string name="database_opened">Datenbank geöffnet</string>
|
||||
<string name="clipboard_explanation_summary">Eintragsfelder mithilfe der Zwischenablage des Geräts kopieren</string>
|
||||
<string name="persistent_notification_title">Dauerhafte Benachrichtigung</string>
|
||||
<string name="persistent_notification_summary">Bei geöffneter Datenbank eine Benachrichtigung hinzufügen</string>
|
||||
<string name="advanced_unlock_explanation_summary">Erweitertes Entsperren verwenden, um eine Datenbank einfacher zu öffnen.</string>
|
||||
<string name="database_data_compression_title">Datenkompression</string>
|
||||
<string name="database_data_compression_summary">Datenkompression reduziert die Datenbankgröße.</string>
|
||||
@@ -453,7 +449,7 @@
|
||||
<string name="keyboard_auto_go_action_summary">Aktion der Go-Taste, die automatisch nach dem Drücken einer Feldtaste ausgeführt wird</string>
|
||||
<string name="download_attachment">%1$s herunterladen</string>
|
||||
<string name="download_initialization">Initialisieren…</string>
|
||||
<string name="download_progression">Fortschritt: %1$d%</string>
|
||||
<string name="download_progression">Fortschritt: %1$d%</string>
|
||||
<string name="download_finalization">Fertigstellung…</string>
|
||||
<string name="download_complete">Vollständig! Tippen Sie, um die Datei zu öffnen.</string>
|
||||
<string name="hide_expired_entries_title">Abgelaufene Einträge ausblenden</string>
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
<string name="error_pass_match">Οι κωδικοί δεν ταιριάζουν.</string>
|
||||
<string name="error_rounds_too_large">Οι \"κύκλοι μετασχηματισμού\" είναι πολύ υψηλοί. Ρύθμιση στο 2147483648.</string>
|
||||
<string name="error_string_key">Κάθε σειρά πρέπει να έχει όνομα πεδίου.</string>
|
||||
<string name="error_title_required">Προσθέστε έναν τίτλο.</string>
|
||||
<string name="error_wrong_length">Εισάγετε ένα θετικό ακέραιο αριθμό στο πεδίο \"Μήκος\".</string>
|
||||
<string name="field_name">Όνομα πεδίου</string>
|
||||
<string name="field_value">Τιμή πεδίου</string>
|
||||
@@ -341,10 +340,9 @@
|
||||
<string name="content_description_keyfile_checkbox">Πλαίσιο ελέγχου κλειδιού-αρχείου</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Επανάληψη της ορατότητας του κωδικού πρόσβασης</string>
|
||||
<string name="content_description_entry_icon">Εικονίδιο καταχώρησης</string>
|
||||
<string name="content_description_entry_save">Αποθήκευση καταχώρησης</string>
|
||||
<string name="content_description_password_generator">Γεννήτρια κωδικού πρόσβασης</string>
|
||||
<string name="entry_password_generator">Γεννήτρια κωδικού πρόσβασης</string>
|
||||
<string name="content_description_password_length">Μήκος κωδικού πρόσβασης</string>
|
||||
<string name="content_description_add_field">Προσθήκη πεδίου</string>
|
||||
<string name="entry_add_field">Προσθήκη πεδίου</string>
|
||||
<string name="content_description_remove_field">Αφαίρεση πεδίου</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">Δεν μπορείτε να μετακινήσετε μια καταχώρηση εδώ.</string>
|
||||
@@ -408,8 +406,6 @@
|
||||
<string name="autofill_explanation_summary">Ενεργοποιήστε την αυτόματη συμπλήρωση για να συμπληρώσετε γρήγορα φόρμες σε άλλες εφαρμογές</string>
|
||||
<string name="database_opened">Η Βάση Δεδομένων άνοιξε</string>
|
||||
<string name="clipboard_explanation_summary">Αντιγράψτε τα πεδία εισαγωγής χρησιμοποιώντας το πρόχειρο της συσκευής σας</string>
|
||||
<string name="persistent_notification_title">Συνεχής ειδοποίηση</string>
|
||||
<string name="persistent_notification_summary">Προσθήκη ειδοποίησης όταν η βάση δεδομένων είναι ανοιχτή</string>
|
||||
<string name="advanced_unlock_explanation_summary">Χρησιμοποιήστε το προηγμένο ξεκλείδωμα για να ανοίξετε μια βάση δεδομένων πιο εύκολα</string>
|
||||
<string name="database_data_compression_title">Συμπίεση Δεδομένων</string>
|
||||
<string name="database_data_compression_summary">Η συμπίεση δεδομένων μειώνει το μέγεθος της βάσης δεδομένων.</string>
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
<string name="error_pass_gen_type">Debe seleccionar al menos un tipo de generación de contraseñas.</string>
|
||||
<string name="error_pass_match">Las contraseñas no coinciden.</string>
|
||||
<string name="error_rounds_too_large">Pasadas demasiado grande. Establecido a 2147483648.</string>
|
||||
<string name="error_title_required">Añada un título.</string>
|
||||
<string name="error_wrong_length">Proporcione un número entero positivo en el campo «Longitud».</string>
|
||||
<string name="file_browser">Explorador de archivos</string>
|
||||
<string name="generate_password">Generar contraseña</string>
|
||||
@@ -355,9 +354,9 @@
|
||||
<string name="content_description_password_checkbox">Casilla de contraseña</string>
|
||||
<string name="content_description_keyfile_checkbox">Casilla de archivo de clave</string>
|
||||
<string name="content_description_entry_icon">Icono de entrada</string>
|
||||
<string name="content_description_password_generator">Generador de contraseñas</string>
|
||||
<string name="entry_password_generator">Generador de contraseñas</string>
|
||||
<string name="content_description_password_length">Longitud de contraseña</string>
|
||||
<string name="content_description_add_field">Añadir campo</string>
|
||||
<string name="entry_add_field">Añadir campo</string>
|
||||
<string name="content_description_remove_field">Quitar campo</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">No puede desplazar entradas aquí.</string>
|
||||
@@ -384,7 +383,6 @@
|
||||
\n\"Modificable\" le permite agregar, eliminar o modificar todos los elementos.</string>
|
||||
<string name="lock_database_back_root_title">Presione hacia atrás en la raíz para bloquear</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Repetir la visibilidad de la contraseña</string>
|
||||
<string name="content_description_entry_save">Guardar entrada</string>
|
||||
<string name="master_key">Llave Maestra</string>
|
||||
<string name="security">Seguridad</string>
|
||||
<string name="entry_history">Historial</string>
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
<string name="error_pass_match">Pasahitzak ez datoz bat.</string>
|
||||
<string name="error_rounds_too_large">Rondak handiegiak. 2147483648 balorean jarrita.</string>
|
||||
<string name="error_string_key">Eremu izen bat behar da testu kate bakoitzerako.</string>
|
||||
<string name="error_title_required">Izenburu bat behar da.</string>
|
||||
<string name="error_wrong_length">Eremuaren luzeran entero positibo bat sartu</string>
|
||||
<string name="field_name">Eremuaren izena</string>
|
||||
<string name="field_value">Eremuaren balorea</string>
|
||||
|
||||
@@ -72,7 +72,6 @@
|
||||
<string name="error_pass_match">Salasanat eivät täsmää.</string>
|
||||
<string name="error_rounds_too_large">Kierroksia on liian paljon. Asetetaan se arvoon 2147483648.</string>
|
||||
<string name="error_string_key">Kentän nimi on pakollinen joka tekstille.</string>
|
||||
<string name="error_title_required">Otsikko on pakollinen.</string>
|
||||
<string name="error_wrong_length">Syötä positiivinen kokonaisluku pituus-kenttään</string>
|
||||
<string name="field_name">Kentän nimi</string>
|
||||
<string name="field_value">Kentän arvo</string>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<string name="decrypting_db">Déchiffrement du contenu de la base de données…</string>
|
||||
<string name="default_checkbox">Utiliser comme base de données par défaut</string>
|
||||
<string name="digits">Chiffres</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft est <strong>open source</strong> et <strong>sans publicité</strong>. Il est fourni tel quel, sous licence <strong>GPLv3</strong>, sans aucune garantie.</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft est <strong>libre</strong> et <strong>sans publicité</strong>. \nIl est fourni tel quel, sous la licence <strong>GPLv3</strong>, sans aucune garantie.</string>
|
||||
<string name="entry_accessed">Dernier accès</string>
|
||||
<string name="entry_cancel">Annuler</string>
|
||||
<string name="entry_notes">Notes</string>
|
||||
@@ -76,7 +76,6 @@
|
||||
<string name="error_pass_match">Les mots de passe ne correspondent pas.</string>
|
||||
<string name="error_rounds_too_large">« Tours de transformation » trop grand. Définition à 2147483648.</string>
|
||||
<string name="error_string_key">Chaque chaîne doit avoir un nom de champ.</string>
|
||||
<string name="error_title_required">Veuillez ajouter un titre.</string>
|
||||
<string name="error_wrong_length">Veuillez saisir un entier positif dans le champ « Longueur ».</string>
|
||||
<string name="error_autofill_enable_service">Impossible d’activer le service de remplissage automatique.</string>
|
||||
<string name="field_name">Nom du champ</string>
|
||||
@@ -275,7 +274,6 @@
|
||||
<string name="html_text_dev_feature_upgrade">N’oubliez pas de garder votre application à jour en installant les nouvelles versions.</string>
|
||||
<string name="download">Télécharger</string>
|
||||
<string name="contribute">Contribuer</string>
|
||||
<!-- Algorithms -->
|
||||
<string name="encryption_rijndael">Rijndael (AES)</string>
|
||||
<string name="encryption_twofish">Twofish</string>
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
@@ -367,10 +365,9 @@
|
||||
<string name="content_description_add_entry">Ajouter une entrée</string>
|
||||
<string name="content_description_add_group">Ajouter un groupe</string>
|
||||
<string name="content_description_entry_icon">Icône de l’entrée</string>
|
||||
<string name="content_description_entry_save">Enregistrer l’entrée</string>
|
||||
<string name="content_description_password_generator">Générateur de mots de passe</string>
|
||||
<string name="entry_password_generator">Générateur de mots de passe</string>
|
||||
<string name="content_description_password_length">Longueur de mot de passe</string>
|
||||
<string name="content_description_add_field">Ajouter un champ</string>
|
||||
<string name="entry_add_field">Ajouter un champ</string>
|
||||
<string name="content_description_remove_field">Supprimer un champ</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="list_groups_show_number_entries_title">Afficher le nombre d’entrées</string>
|
||||
@@ -422,8 +419,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">En validant cette boîte de dialogue, KeePassDX corrigera le problème (en générant de nouveaux UUID pour les doublons) et continuera.</string>
|
||||
<string name="database_opened">Base de données ouverte</string>
|
||||
<string name="clipboard_explanation_summary">Copie les champs d’une entrée à l’aide du presse-papier de votre appareil</string>
|
||||
<string name="persistent_notification_title">Notification persistante</string>
|
||||
<string name="persistent_notification_summary">Ajoute une notification lorsque la base de données est ouverte</string>
|
||||
<string name="advanced_unlock_explanation_summary">Utilise le déverrouillage avancé pour ouvrir plus facilement une base de données</string>
|
||||
<string name="database_data_compression_title">Compression de données</string>
|
||||
<string name="database_data_compression_summary">La compression des données réduit la taille de la base de données.</string>
|
||||
@@ -460,7 +455,7 @@
|
||||
<string name="keyboard_auto_go_action_summary">Action de la touche Go effectuée automatiquement après avoir appuyé sur une touche de champ</string>
|
||||
<string name="download_attachment">Téléchargement %1$s</string>
|
||||
<string name="download_initialization">Initialisation…</string>
|
||||
<string name="download_progression">En cours : %1$d%</string>
|
||||
<string name="download_progression">En cours : %1$d%</string>
|
||||
<string name="download_finalization">Finalisation…</string>
|
||||
<string name="download_complete">Terminé ! Appuyer pour ouvrir le fichier.</string>
|
||||
<string name="hide_expired_entries_title">Masquer les entrées expirées</string>
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
<string name="error_pass_match">पासवर्ड मेल नहीं खाते हैं।</string>
|
||||
<string name="error_rounds_too_large">\"परिवर्तन राउंड\" बहुत अधिक है। 2147483648 पर सेट हो रहा है।</string>
|
||||
<string name="error_string_key">प्रत्येक स्ट्रिंग में फ़ील्ड नाम होना चाहिए।</string>
|
||||
<string name="error_title_required">एक शीर्षक जोड़ें।</string>
|
||||
<string name="content_description_open_file">फ़ाइल खोलें</string>
|
||||
<string name="content_description_node_children">नोड के बच्चे</string>
|
||||
<string name="content_description_add_node">नोड जोड़ें</string>
|
||||
@@ -69,10 +68,9 @@
|
||||
<string name="content_description_keyfile_checkbox">कीफाइल चेकबॉक्स</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">पासवर्ड दृश्यता टॉगल दोहराएं</string>
|
||||
<string name="content_description_entry_icon">प्रवेश आइकन</string>
|
||||
<string name="content_description_entry_save">प्रविष्टि सहेजें</string>
|
||||
<string name="content_description_password_generator">पासवर्ड जनरेटर</string>
|
||||
<string name="entry_password_generator">पासवर्ड जनरेटर</string>
|
||||
<string name="content_description_password_length">पासवर्ड की लंबाई</string>
|
||||
<string name="content_description_add_field">फ़ील्ड जोड़ें</string>
|
||||
<string name="entry_add_field">फ़ील्ड जोड़ें</string>
|
||||
<string name="content_description_remove_field">फ़ील्ड निकालें</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="file_manager_install_description">"डेटाबेस फाइल को बनाने खोलने और सेव करने के लिए आपके फोन में फाइल मैनेजर ऐप होना चाहिए जोकि दिए गए एक्शन को सपोर्ट कर सके ACTION_CREATE_DOCUMENT और ACTION_OPEN_DOCUMENT"</string>
|
||||
|
||||
@@ -30,10 +30,9 @@
|
||||
<string name="content_description_add_group">Dodaj grupu</string>
|
||||
<string name="content_description_file_information">Informacije o datoteci</string>
|
||||
<string name="content_description_entry_icon">Ikona unosa</string>
|
||||
<string name="content_description_entry_save">Spremi unos</string>
|
||||
<string name="content_description_password_generator">Generator lozinke</string>
|
||||
<string name="entry_password_generator">Generator lozinke</string>
|
||||
<string name="content_description_password_length">Duljina lozinke</string>
|
||||
<string name="content_description_add_field">Dodaj polje</string>
|
||||
<string name="entry_add_field">Dodaj polje</string>
|
||||
<string name="content_description_remove_field">Ukloni polje</string>
|
||||
<string name="content_description_update_from_list">Ažuriraj</string>
|
||||
<string name="content_description_remove_from_list">Ukloni</string>
|
||||
@@ -73,7 +72,6 @@
|
||||
<string name="error_nokeyfile">Odaberi datoteku ključa.</string>
|
||||
<string name="error_pass_gen_type">Bar jedan tip generiranja lozinke mora biti odabran.</string>
|
||||
<string name="error_pass_match">Lozinke se ne podudaraju.</string>
|
||||
<string name="error_title_required">Dodaj naslov.</string>
|
||||
<string name="error_wrong_length">Unesi pozitivan cijeli broj u polje \"Duljina\".</string>
|
||||
<string name="error_otp_secret_key">Tajni ključ mora biti u Base32 formatu.</string>
|
||||
<string name="error_otp_counter">Brojač mora biti između %1$d i %2$d.</string>
|
||||
@@ -184,8 +182,6 @@
|
||||
<string name="clipboard_warning">Ako automatsko brisanje međuspremnika ne uspije, izbrišite njegovu povijest ručno.</string>
|
||||
<string name="lock_database_screen_off_summary">Zaključaj bazu podataka kada je ekran ugašen</string>
|
||||
<string name="lock_database_back_root_title">Pritisni \'Natrag\' za zaključavanje</string>
|
||||
<string name="persistent_notification_title">Trajna obavijest</string>
|
||||
<string name="persistent_notification_summary">Dodaj obavijest kada je baza podataka otvorena</string>
|
||||
<string name="advanced_unlock">Napredno otključavanje</string>
|
||||
<string name="advanced_unlock_explanation_summary">Koristite napredno otključavanje za jednostavnije otvaranje baze podataka</string>
|
||||
<string name="biometric_unlock_enable_title">Biometričko otključavanje</string>
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
<string name="error_pass_match">A jelszavak nem egyeznek meg.</string>
|
||||
<string name="error_rounds_too_large">A „Transzformációs körök” száma túl nagy. Beállítás 2147483648-ra.</string>
|
||||
<string name="error_string_key">Minden karakterlánchoz szükséges egy mezőnév.</string>
|
||||
<string name="error_title_required">Adjon hozzá egy címet.</string>
|
||||
<string name="error_wrong_length">Írjon be egy pozitív egész számot a „Hossz” mezőbe.</string>
|
||||
<string name="field_name">Mezőnév</string>
|
||||
<string name="field_value">Mezőérték</string>
|
||||
|
||||
@@ -27,14 +27,14 @@
|
||||
<string name="add_group">Aggiungi gruppo</string>
|
||||
<string name="encryption_algorithm">Algoritmo di cifratura</string>
|
||||
<string name="app_timeout">Scadenza app</string>
|
||||
<string name="app_timeout_summary">Inattività prima del blocco dell\'app</string>
|
||||
<string name="app_timeout_summary">Tempo di inattività prima del blocco dell\'app</string>
|
||||
<string name="application">App</string>
|
||||
<string name="menu_app_settings">Impostazioni app</string>
|
||||
<string name="brackets">Parentesi</string>
|
||||
<string name="file_manager_install_description">Sfoglia i file installando il Gestore File di OpenIntents</string>
|
||||
<string name="file_manager_install_description">È necessario un file manager che accetti gli Intent ACTION_CREATE_DOCUMENT e ACTION_OPEN_DOCUMENT per creare, aprire e salvare i file di database.</string>
|
||||
<string name="clipboard_cleared">Appunti eliminati</string>
|
||||
<string name="clipboard_error_title">Errore negli appunti</string>
|
||||
<string name="clipboard_error">Alcuni telefoni Android di Samsung non permettono alle app di usare gli appunti.</string>
|
||||
<string name="clipboard_error">Alcuni dispositivi non permettono alle app di usare gli appunti.</string>
|
||||
<string name="clipboard_error_clear">Eliminazione degli appunti fallita</string>
|
||||
<string name="clipboard_timeout">Scadenza appunti</string>
|
||||
<string name="clipboard_timeout_summary">Tempo prima di eliminare gli appunti</string>
|
||||
@@ -44,7 +44,8 @@
|
||||
<string name="decrypting_db">Decodifica contenuto database…</string>
|
||||
<string name="default_checkbox">Usa come database predefinito</string>
|
||||
<string name="digits">Numeri</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft viene distribuito assolutamente con nessuna garanzia. Si tratta di software libero e sei invitato a distribuirlo sotto le condizioni della licenza GPL versione 3 o successiva.</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft è un programma <strong>open source</strong> e <strong>senza pubblicità</strong>.
|
||||
\nViene distribuito sotto le condizioni della licenza <strong>GPL versione 3</strong> o successiva, senza alcuna garanzia.</string>
|
||||
<string name="entry_notes">Note</string>
|
||||
<string name="select_database_file">Apri un database esistente</string>
|
||||
<string name="entry_accessed">Ultimo accesso</string>
|
||||
@@ -71,7 +72,6 @@
|
||||
<string name="error_pass_match">Le password non corrispondono.</string>
|
||||
<string name="error_rounds_too_large">\"Livello\" troppo alto. Impostato a 2147483648.</string>
|
||||
<string name="error_string_key">Ogni stringa deve avere un nome.</string>
|
||||
<string name="error_title_required">Aggiungi un titolo.</string>
|
||||
<string name="error_wrong_length">Inserisci un numero naturale positivo nel campo \"lunghezza\".</string>
|
||||
<string name="field_name">Nome campo</string>
|
||||
<string name="field_value">Valore campo</string>
|
||||
@@ -81,13 +81,13 @@
|
||||
<string name="hint_conf_pass">conferma password</string>
|
||||
<string name="hint_generated_password">password generata</string>
|
||||
<string name="hint_group_name">Nome gruppo</string>
|
||||
<string name="hint_keyfile">file chiave</string>
|
||||
<string name="hint_keyfile">File chiave</string>
|
||||
<string name="hint_length">lunghezza</string>
|
||||
<string name="password">Password</string>
|
||||
<string name="hint_pass">password</string>
|
||||
<string name="install_from_play_store">Installa dal Play Store</string>
|
||||
<string name="install_from_f_droid">Installa dal F-Droid</string>
|
||||
<string name="invalid_credentials">Password o file chiave non validi.</string>
|
||||
<string name="invalid_credentials">Non è possibile leggere le credenziali. Se questo dovesse riaccadere, il file del databese potrebbe essere corrotto.</string>
|
||||
<string name="invalid_algorithm">Algoritmo errato.</string>
|
||||
<string name="invalid_db_sig">Formato database non riconosciuto.</string>
|
||||
<string name="keyfile_is_empty">Il file chiave è vuoto.</string>
|
||||
@@ -139,7 +139,7 @@
|
||||
<string name="uppercase">Maiuscole</string>
|
||||
<string name="warning">Attenzione</string>
|
||||
<string name="warning_password_encoding">Evita password con caratteri al di fuori del formato di codifica del testo nel file di database (i caratteri non riconosciuti vengono convertiti nella stessa lettera).</string>
|
||||
<string name="warning_unmounted">Monta la scheda SD per creare o caricare un database.</string>
|
||||
<string name="warning_unmounted">Monta la scheda di memoria per poter creare o caricare un database.</string>
|
||||
<string name="version_label">Versione %1$s</string>
|
||||
<string name="configure_biometric">La scansione di impronte è supportata ma non impostata.</string>
|
||||
<string name="open_biometric_prompt_unlock_database">Scansione impronte</string>
|
||||
@@ -237,7 +237,7 @@
|
||||
<string name="full_file_path_enable_title">Percorso file</string>
|
||||
<string name="full_file_path_enable_summary">Visualizza il percorso file completo</string>
|
||||
<string name="recycle_bin_title">Usa il cestino</string>
|
||||
<string name="recycle_bin_summary">Sposta gruppi ed elementi nel cestino prima di eliminare</string>
|
||||
<string name="recycle_bin_summary">Sposta i gruppi e le voci nel gruppo \"Cestino\" prima di eliminarlo</string>
|
||||
<string name="monospace_font_fields_enable_title">Carattere campi</string>
|
||||
<string name="monospace_font_fields_enable_summary">Cambia il carattere usato nei campi per una migliore visibilità</string>
|
||||
<string name="allow_copy_password_title">Fiducia appunti</string>
|
||||
@@ -347,7 +347,7 @@
|
||||
<string name="keyboard_key_sound_title">Suono alla pressione</string>
|
||||
<string name="selection_mode">Modalità selezione</string>
|
||||
<string name="do_not_kill_app">Non terminare l\'app…</string>
|
||||
<string name="lock_database_back_root_title">Premere Indietro sulla schermata principale per bloccare</string>
|
||||
<string name="lock_database_back_root_title">Premere \'\'Indietro\'\' per bloccare</string>
|
||||
<string name="lock_database_back_root_summary">Bloccare il database quando l\'utente preme il pulsante Indietro nella schermata principale</string>
|
||||
<string name="clear_clipboard_notification_title">Pulisci alla chiusura</string>
|
||||
<string name="clear_clipboard_notification_summary">Chiudere il database alla chiusura della notifica</string>
|
||||
@@ -364,17 +364,47 @@
|
||||
<string name="content_description_file_information">Informazioni sul file</string>
|
||||
<string name="content_description_password_checkbox">Casella di controllo della password</string>
|
||||
<string name="content_description_keyfile_checkbox">Casella di controllo Keyfile</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Ripeti attivare / disattivare la visibilità della password</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Ripeti la richiesta di visibilità della password</string>
|
||||
<string name="content_description_entry_icon">Icona</string>
|
||||
<string name="content_description_password_generator">Generatore di password</string>
|
||||
<string name="entry_password_generator">Generatore di password</string>
|
||||
<string name="content_description_password_length">Lunghezza della password</string>
|
||||
<string name="content_description_add_field">Aggiungi un campo</string>
|
||||
<string name="entry_add_field">Aggiungi un campo</string>
|
||||
<string name="content_description_remove_field">Rimuovi un campo</string>
|
||||
<string name="error_move_entry_here">Non è possibile spostare una voce qui.</string>
|
||||
<string name="error_copy_entry_here">Non è possibile copiare una voce qui.</string>
|
||||
<string name="list_groups_show_number_entries_title">Mostra il numero di voci</string>
|
||||
<string name="list_groups_show_number_entries_summary">Mostra il numero di voci in un gruppo</string>
|
||||
<string name="content_description_entry_save">Salva</string>
|
||||
<string name="content_description_update_from_list">Aggiorna</string>
|
||||
<string name="content_description_keyboard_close_fields">Chiudi campi</string>
|
||||
<string name="security">Sicurezza</string>
|
||||
<string name="content_description_background">Sfondo</string>
|
||||
<string name="entry_UUID">Identificativo univoco universale</string>
|
||||
<string name="error_create_database_file">Impossibile creare un database con questa password e file chiave.</string>
|
||||
<string name="menu_advanced_unlock_settings">Sblocco avanzato</string>
|
||||
<string name="entry_history">Cronologia</string>
|
||||
<string name="entry_setup_otp">Imposta password usa e getta</string>
|
||||
<string name="otp_type">Tipo di password usa e getta</string>
|
||||
<string name="otp_secret">Segreto</string>
|
||||
<string name="otp_period">Periodo (secondi)</string>
|
||||
<string name="otp_counter">Contatore</string>
|
||||
<string name="otp_digits">Cifre</string>
|
||||
<string name="otp_algorithm">Algoritmo</string>
|
||||
<string name="entry_otp">Password usa e getta</string>
|
||||
<string name="error_invalid_OTP">Segreto per password usa e getta (OTP) non valido.</string>
|
||||
<string name="error_disallow_no_credentials">Impostare almeno una credenziale.</string>
|
||||
<string name="error_copy_group_here">Non puoi copiare un gruppo qui.</string>
|
||||
<string name="error_otp_secret_key">La chiave segreta deve essere nel formato Base32.</string>
|
||||
<string name="error_otp_counter">Il contatore deve essere tra %1$d e %2$d.</string>
|
||||
<string name="error_otp_period">Il periodo deve essere tra %1$d e %2$d secondi.</string>
|
||||
<string name="error_otp_digits">Il token deve contenere tra %1$d e %2$d cifre.</string>
|
||||
<string name="invalid_db_same_uuid">%1$s con le stesse credenziali univoche %2$s è già esistente.</string>
|
||||
<string name="creating_database">Sto creando il database…</string>
|
||||
<string name="menu_security_settings">Impostazioni di sicurezza</string>
|
||||
<string name="contains_duplicate_uuid">Il databse contiene identificativi univoci univerali duplicati.</string>
|
||||
<string name="error_save_database">Non è possibile salvare il database.</string>
|
||||
<string name="menu_save_database">Salva il database</string>
|
||||
<string name="menu_empty_recycle_bin">Svuota il cestino</string>
|
||||
<string name="command_execution">Esecuzione del comando…</string>
|
||||
<string name="warning_permanently_delete_nodes">Sei sicuro di voler eliminare definitivamente i nodi selezionati\?</string>
|
||||
<string name="entry_attachments">Allegati</string>
|
||||
</resources>
|
||||
@@ -69,7 +69,6 @@
|
||||
<string name="error_pass_match">הסיסמאות לא תואמות.</string>
|
||||
<string name="error_rounds_too_large">מספר סיבובים גדול מדי. מגדיר ל-2147483648.</string>
|
||||
<string name="error_string_key">שדה שם נדרש לכל מחרוזת.</string>
|
||||
<string name="error_title_required">כותרת נדרשת.</string>
|
||||
<string name="error_wrong_length">הזן מספר חיובי בשדה האורך</string>
|
||||
<string name="field_name">שם השדה</string>
|
||||
<string name="field_value">ערך השדה</string>
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
<string name="error_pass_gen_type">少なくとも1つ以上のパスワード生成タイプを選択する必要があります。</string>
|
||||
<string name="error_pass_match">パスワードが一致しません</string>
|
||||
<string name="error_rounds_too_large">値が大きすぎます。 2147483648にセットしました。</string>
|
||||
<string name="error_title_required">タイトルは必須入力です。</string>
|
||||
<string name="error_wrong_length">\"長さ\"欄には正の整数を入力してください。</string>
|
||||
<string name="file_browser">ファイルブラウザ</string>
|
||||
<string name="generate_password">パスワードを生成する</string>
|
||||
@@ -194,10 +193,9 @@
|
||||
<string name="content_description_add_group">グループの追加</string>
|
||||
<string name="content_description_file_information">ファイル情報</string>
|
||||
<string name="content_description_entry_icon">エントリーのアイコン</string>
|
||||
<string name="content_description_entry_save">エントリーの保存</string>
|
||||
<string name="content_description_password_generator">パスワード生成</string>
|
||||
<string name="entry_password_generator">パスワード生成</string>
|
||||
<string name="content_description_password_length">パスワードの長さ</string>
|
||||
<string name="content_description_add_field">フィールドの追加</string>
|
||||
<string name="entry_add_field">フィールドの追加</string>
|
||||
<string name="content_description_remove_field">フィールドの削除</string>
|
||||
<string name="error_move_entry_here">エントリーを移動できませんでした。</string>
|
||||
<string name="error_copy_entry_here">エントリーをコピーできませんでした。</string>
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
<string name="error_pass_match">비밀번호가 일치하지 않습니다.</string>
|
||||
<string name="error_rounds_too_large">\"Transformation rounds\" 가 너무 높습니다. 2147483648로 설정합니다.</string>
|
||||
<string name="error_string_key">각 항목은 필드 이름을 가져야 합니다.</string>
|
||||
<string name="error_title_required">제목을 입력하십시오.</string>
|
||||
<string name="error_wrong_length">\"길이\" 필드에는 양수를 입력하십시오.</string>
|
||||
<string name="error_autofill_enable_service">자동 채우기 서비스를 활성화할 수 없습니다.</string>
|
||||
<string name="error_move_folder_in_itself">그룹을 자신에게 옮길 수 없습니다.</string>
|
||||
@@ -164,9 +163,9 @@
|
||||
<string name="content_description_password_checkbox">비밀번호 체크박스</string>
|
||||
<string name="content_description_keyfile_checkbox">내용_설명_키파일_체크박스</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">토글 비밀번호 가시성 반복</string>
|
||||
<string name="content_description_password_generator">비밀번호 생성</string>
|
||||
<string name="entry_password_generator">비밀번호 생성</string>
|
||||
<string name="content_description_password_length">비밀번호 길이</string>
|
||||
<string name="content_description_add_field">필드 추가</string>
|
||||
<string name="entry_add_field">필드 추가</string>
|
||||
<string name="content_description_remove_field">필드 제거</string>
|
||||
<string name="error_move_entry_here">항목을 여기로 옮길 수 없습니다.</string>
|
||||
<string name="error_copy_entry_here">항목을 여기로 복사할 수 없습니다.</string>
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
<string name="error_pass_match">Paroles nesakrīt.</string>
|
||||
<string name="error_rounds_too_large">Līmenis pārāk liels. Maksimālais 2147483648</string>
|
||||
<string name="error_string_key">A field name is required for each string.</string>
|
||||
<string name="error_title_required">Nepieciešams nosaukums.</string>
|
||||
<string name="error_wrong_length">Norādiet garumu lielāku par nulli</string>
|
||||
<string name="field_name">Lauka nosaukums</string>
|
||||
<string name="field_value">Lauka vērtība</string>
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
<string name="error_pass_match">Passordene samsvarer ikke.</string>
|
||||
<string name="error_rounds_too_large">\"Omganger\" er for stort. Setter til 2147483648.</string>
|
||||
<string name="error_string_key">Hver streng må ha et feltnavn.</string>
|
||||
<string name="error_title_required">En tittel er påkrevd.</string>
|
||||
<string name="error_wrong_length">Skriv inn et positivt heltall i \"Lengde\"-feltet.</string>
|
||||
<string name="error_autofill_enable_service">Autofyll-tjenesten kan ikke skrus på.</string>
|
||||
<string name="error_move_folder_in_itself">Kan ikke flytte gruppe inn i seg selv.</string>
|
||||
@@ -342,9 +341,9 @@
|
||||
<string name="content_description_add_entry">Legg til oppføring</string>
|
||||
<string name="content_description_add_group">Legg til gruppe</string>
|
||||
<string name="content_description_file_information">Filinfo</string>
|
||||
<string name="content_description_password_generator">Passordgenerator</string>
|
||||
<string name="entry_password_generator">Passordgenerator</string>
|
||||
<string name="content_description_password_length">Passordslengde</string>
|
||||
<string name="content_description_add_field">Legg til felt</string>
|
||||
<string name="entry_add_field">Legg til felt</string>
|
||||
<string name="content_description_remove_field">Fjern felt</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">Du kan ikke flytte en oppføring hit.</string>
|
||||
@@ -389,8 +388,6 @@
|
||||
<string name="menu_security_settings">Sikkerhetsinnstillinger</string>
|
||||
<string name="menu_master_key_settings">Hovednøkkelinnstillinger</string>
|
||||
<string name="contains_duplicate_uuid">Databasen inneholder dupliserte UUID-er.</string>
|
||||
<string name="persistent_notification_title">Vedvarende merknad</string>
|
||||
<string name="persistent_notification_summary">Legg til en merknad når databasen er åpen</string>
|
||||
<string name="database_data_compression_title">Datakomprimering</string>
|
||||
<string name="database_data_compression_summary">Datakomprimering reduserer databasens størrelse.</string>
|
||||
<string name="compression">Komprimering</string>
|
||||
@@ -400,7 +397,6 @@
|
||||
<string name="menu_empty_recycle_bin">Tøm papirkurv</string>
|
||||
<string name="command_execution">Kjører kommandoen…</string>
|
||||
<string name="content_description_node_children">Undernoder</string>
|
||||
<string name="content_description_entry_save">Lagre oppføring</string>
|
||||
<string name="database_default_username_title">Forvalgt brukernavn</string>
|
||||
<string name="database_custom_color_title">Tilpasset databasefarge</string>
|
||||
<string name="recycle_bin_group_title">Papirkurvsgruppe</string>
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
<string name="error_pass_gen_type">Je moet minimaal één soort wachtwoordgenerering kiezen.</string>
|
||||
<string name="error_pass_match">De wachtwoorden komen niet overeen.</string>
|
||||
<string name="error_rounds_too_large">\"Cycli-waarde\" te groot. Wordt ingesteld op 2147483648.</string>
|
||||
<string name="error_title_required">Voeg een titel toe.</string>
|
||||
<string name="error_wrong_length">Voer een positief geheel getal in in het veld \"Lengte\".</string>
|
||||
<string name="file_browser">Bestandsverkenner</string>
|
||||
<string name="generate_password">Wachtwoord genereren</string>
|
||||
@@ -368,10 +367,9 @@
|
||||
<string name="content_description_keyfile_checkbox">Sleutelbestandcheckbox</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Weergave van het wachtwoord wisselen</string>
|
||||
<string name="content_description_entry_icon">Item-icoon</string>
|
||||
<string name="content_description_entry_save">Item opslaan</string>
|
||||
<string name="content_description_password_generator">Wachtwoordgenerator</string>
|
||||
<string name="entry_password_generator">Wachtwoordgenerator</string>
|
||||
<string name="content_description_password_length">Wachtwoordlengte</string>
|
||||
<string name="content_description_add_field">Veld toevoegen</string>
|
||||
<string name="entry_add_field">Veld toevoegen</string>
|
||||
<string name="content_description_remove_field">Veld verwijderen</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">Je kan hier geen item plaatsen.</string>
|
||||
@@ -418,8 +416,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">Door dit dialoogvenster te valideren, zal KeePassDX het probleem oplossen (door nieuwe UUID\'s voor duplicaten te genereren) en doorgaan.</string>
|
||||
<string name="database_opened">Database geopend</string>
|
||||
<string name="clipboard_explanation_summary">Kopieer invoervelden met behulp van het klembord van uw apparaat</string>
|
||||
<string name="persistent_notification_title">Aanhoudende melding</string>
|
||||
<string name="persistent_notification_summary">Voeg een melding toe wanneer de database is geopend</string>
|
||||
<string name="advanced_unlock_explanation_summary">Geavanceerde ontgrendeling gebruiken om een database gemakkelijker te openen</string>
|
||||
<string name="database_data_compression_title">Gegevenscompressie</string>
|
||||
<string name="database_data_compression_summary">Gegevenscompressie verkleint de omvang van de database.</string>
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
<string name="error_pass_gen_type">Du må velja minst éin passordlagingstype</string>
|
||||
<string name="error_pass_match">Passorda samsvarer ikkje.</string>
|
||||
<string name="error_rounds_too_large">For mange omgangar. Bruker 2147483648.</string>
|
||||
<string name="error_title_required">Treng ein tittel.</string>
|
||||
<string name="error_wrong_length">Bruk eit positivt heiltal i lengdfeltet</string>
|
||||
<string name="file_browser">Filbehandlar</string>
|
||||
<string name="generate_password">Lag passord</string>
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
<string name="error_pass_gen_type">Należy wybrać co najmniej jeden rodzaj generowania hasła.</string>
|
||||
<string name="error_pass_match">Hasła nie pasują do siebie.</string>
|
||||
<string name="error_rounds_too_large">\"Rundy szyfrowania\" są zbyt wysokie. Ustaw na 2147483648.</string>
|
||||
<string name="error_title_required">Dodaj tytuł.</string>
|
||||
<string name="error_wrong_length">Wprowadź dodatnią liczbę całkowitą w polu \"Długość\".</string>
|
||||
<string name="file_browser">Przeglądarka plików</string>
|
||||
<string name="generate_password">Generuj hasło</string>
|
||||
@@ -153,7 +152,8 @@
|
||||
<string name="clipboard_error">Niektóre urządzenia nie pozwalają aplikacjom korzystać ze schowka.</string>
|
||||
<string name="clipboard_error_clear">Nie można wyczyścić schowka</string>
|
||||
<string name="clipboard_swipe_clean">Przesuń, by wyczyścić schowek</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft korzystasz absolutnie bez gwarancji. To jest bezpłatne oprogramowanie i możesz go redystrybuować na warunkach GPL w wersji 3 lub późniejszej.</string>
|
||||
<string name="html_about_licence">KeePassDX © %1 $d Kunzisoft jest <strong>open source</strong> i <strong>bez reklam</strong>.
|
||||
\nJest on dostarczany w stanie, zgodnie z licencją <strong>GPLv3</strong> bez żadnych gwarancji.</string>
|
||||
<string name="entry_not_found">Nie znaleziono danych wejściowych.</string>
|
||||
<string name="error_load_database">Nie można załadować bazy danych.</string>
|
||||
<string name="error_load_database_KDF_memory">Nie można załadować klucza. Spróbuj zmniejszyć użycie pamięć KDF.</string>
|
||||
@@ -284,7 +284,7 @@
|
||||
<string name="education_generate_password_title">Utwórz silne hasło do swojego wpisu.</string>
|
||||
<string name="education_generate_password_summary">Wygeneruj silne hasło, które będzie kojarzyć się z Twoim wpisem, łatwo zdefiniuj je zgodnie z kryteriami formularza i nie zapomnij o bezpiecznym haśle.</string>
|
||||
<string name="education_entry_new_field_title">Dodaj niestandardowe pola</string>
|
||||
<string name="education_entry_new_field_summary">Zarejestruj podstawowe pole niedostarczone, wypełniając nowe pole, które możesz również chronić.</string>
|
||||
<string name="education_entry_new_field_summary">Zarejestruj dodatkowe pole, dodaj wartość i opcjonalnie chroń je.</string>
|
||||
<string name="education_unlock_title">Odblokuj swoją bazę danych</string>
|
||||
<string name="education_read_only_title">Zapisz ochronę swojej bazy danych</string>
|
||||
<string name="education_read_only_summary">Zmień tryb otwierania sesji.
|
||||
@@ -301,7 +301,7 @@
|
||||
<string name="education_sort_summary">Wybierz sposób sortowania wpisów i grup.</string>
|
||||
<string name="education_donation_title">Weź udział</string>
|
||||
<string name="education_donation_summary">Pomóż zwiększyć stabilność, bezpieczeństwo i dodawanie kolejnych funkcji.</string>
|
||||
<string name="html_text_ad_free">W przeciwieństwie do wielu aplikacji do zarządzania hasłami, ta jest <strong>wolna od reklam</strong>, <strong>open source</strong> i na licencji <strong>licencjonowanie copyleftted</strong>. <strong>Żadne dane osobowe nie są gromadzone</strong>, w jakiejkolwiek formie, bez względu na to, z której wersji (bezpłatnej lub pro) korzystasz.</string>
|
||||
<string name="html_text_ad_free">W przeciwieństwie do wielu aplikacji do zarządzania hasłami, ta jest wolna od <strong>reklam</strong>, <strong>jest wolnym oprogramowaniem copyleftted</strong> i nie zbiera danych osobowych na swoich serwerach, bez względu na to, jakiej wersji używasz.</string>
|
||||
<string name="html_text_buy_pro">Kupując wersję pro, będziesz mieć dostęp do <strong>stylu wizualnego</strong> a szczególnie pomożesz <strong> zrealizować projekty społecznościowe.</strong></string>
|
||||
<string name="html_text_feature_generosity">Ten <strong>styl wizualny</strong> jest dostępny dzięki Twojej hojności.</string>
|
||||
<string name="html_text_donation">Aby zachować naszą wolność i być zawsze aktywnym, liczymy na Twój <strong>wkład.</strong></string>
|
||||
@@ -355,10 +355,9 @@
|
||||
<string name="content_description_add_group">Dodaj grupę</string>
|
||||
<string name="content_description_file_information">Informacje o pliku</string>
|
||||
<string name="content_description_entry_icon">Ikona wpisu</string>
|
||||
<string name="content_description_entry_save">Zapisz wpis</string>
|
||||
<string name="content_description_password_generator">Generator haseł</string>
|
||||
<string name="entry_password_generator">Generator haseł</string>
|
||||
<string name="content_description_password_length">Długość hasła</string>
|
||||
<string name="content_description_add_field">Dodaj pole</string>
|
||||
<string name="entry_add_field">Dodaj pole</string>
|
||||
<string name="content_description_remove_field">Usuń pole</string>
|
||||
<string name="error_copy_entry_here">Nie możesz tutaj skopiować wpisu.</string>
|
||||
<string name="list_groups_show_number_entries_title">Pokaż liczbę wpisów</string>
|
||||
@@ -402,8 +401,6 @@
|
||||
<string name="menu_master_key_settings">Ustawienia klucza głównego</string>
|
||||
<string name="contains_duplicate_uuid">Baza danych zawiera zduplikowane identyfikatory UUID.</string>
|
||||
<string name="database_opened">Baza danych otwarta</string>
|
||||
<string name="persistent_notification_title">Stałe powiadamianie</string>
|
||||
<string name="persistent_notification_summary">Dodaj powiadomienie, gdy baza danych jest otwarta</string>
|
||||
<string name="database_data_compression_title">Kompresja danych</string>
|
||||
<string name="max_history_items_summary">Ogranicz liczbę elementów historii na wpis</string>
|
||||
<string name="max_history_size_title">Maksymalny rozmiar</string>
|
||||
@@ -449,9 +446,23 @@
|
||||
<string name="keyboard_auto_go_action_summary">Działanie klawisza Go wykonywane jest automatycznie po naciśnięciu klawisza Field</string>
|
||||
<string name="download_attachment">Pobierz %1$s</string>
|
||||
<string name="download_initialization">Inicjowanie…</string>
|
||||
<string name="download_progression">W trakcie realizacji: %1$d%</string>
|
||||
<string name="download_progression">W trakcie realizacji: %1$d%</string>
|
||||
<string name="download_finalization">Kończę…</string>
|
||||
<string name="download_complete">Kompletny! Stuknij, aby otworzyć plik.</string>
|
||||
<string name="hide_expired_entries_title">Ukryj wygasłe wpisy</string>
|
||||
<string name="hide_expired_entries_summary">Wygasłe wpisy zostaną ukryte</string>
|
||||
<string name="contact">Kontakt</string>
|
||||
<string name="html_about_contribution">Aby <strong>zachować naszą wolność</strong>, <strong>sprawdzać błędy</strong>, <strong>dodać funkcje</strong> i <strong>by być zawsze aktywnym</strong>, liczymy na twój <strong>wkład</strong>.</string>
|
||||
<string name="auto_focus_search_title">Szybkie wyszukiwanie</string>
|
||||
<string name="auto_focus_search_summary">Wyszukiwanie po otwarciu bazy danych</string>
|
||||
<string name="remember_database_locations_title">Zapisz lokalizację baz danych</string>
|
||||
<string name="remember_database_locations_summary">Zapamiętaj lokalizację baz danych</string>
|
||||
<string name="remember_keyfile_locations_title">Zapisz lokalizację plików kluczy</string>
|
||||
<string name="remember_keyfile_locations_summary">Zapamiętaj lokalizację plików kluczy baz danych</string>
|
||||
<string name="show_recent_files_title">Pokaż najnowsze pliki</string>
|
||||
<string name="show_recent_files_summary">Pokaż lokalizacje najnowszych baz danych</string>
|
||||
<string name="hide_broken_locations_title">Ukryj uszkodzone łącza do bazy danych</string>
|
||||
<string name="hide_broken_locations_summary">Ukryj uszkodzone łącza na liście najnowszych baz danych</string>
|
||||
<string name="warning_database_read_only">Przyznaj dostęp do zapisu pliku, aby zapisać zmiany w bazie danych</string>
|
||||
<string name="contribution">Wkład</string>
|
||||
</resources>
|
||||
@@ -65,7 +65,6 @@
|
||||
<string name="error_pass_gen_type">Pelo menos um tipo de geração de senhas deve ser selecionado.</string>
|
||||
<string name="error_pass_match">As senhas não combinam.</string>
|
||||
<string name="error_rounds_too_large">\"Número de rodadas\" é muito grande. Modificado para 2147483648.</string>
|
||||
<string name="error_title_required">Insira um título.</string>
|
||||
<string name="error_wrong_length">Digite um número inteiro positivo no campo \"Tamanho\".</string>
|
||||
<string name="file_browser">Localizador de arquivos</string>
|
||||
<string name="generate_password">Gerar senha</string>
|
||||
@@ -360,16 +359,15 @@
|
||||
<string name="content_description_add_group">Adicionar grupo</string>
|
||||
<string name="content_description_file_information">Informações do arquivo</string>
|
||||
<string name="content_description_entry_icon">Ícone da entrada</string>
|
||||
<string name="content_description_password_generator">Gerador de senhas</string>
|
||||
<string name="entry_password_generator">Gerador de senhas</string>
|
||||
<string name="content_description_password_length">Comprimento da senha</string>
|
||||
<string name="content_description_add_field">Adicionar campo</string>
|
||||
<string name="entry_add_field">Adicionar campo</string>
|
||||
<string name="content_description_remove_field">Remover campo</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">Você não pode mover uma entrada para cá.</string>
|
||||
<string name="error_copy_entry_here">Você não pode copiar uma entrada aqui.</string>
|
||||
<string name="list_groups_show_number_entries_title">Mostrar número de entradas</string>
|
||||
<string name="list_groups_show_number_entries_summary">Mostrar o número de entradas dentro de um grupo</string>
|
||||
<string name="content_description_entry_save">Salvar entrada</string>
|
||||
<string name="content_description_node_children">Nó filho</string>
|
||||
<string name="content_description_password_checkbox">Caixa de seleção de senha</string>
|
||||
<string name="content_description_keyfile_checkbox">Caixa de seleção do arquivo-chave</string>
|
||||
@@ -414,8 +412,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">Ao validar este diálogo, o KeePassDX irá consertar o problema (gerando um novo UUID para os duplicados) e continuar.</string>
|
||||
<string name="database_opened">Banco de dados aberto</string>
|
||||
<string name="clipboard_explanation_summary">Copiar campos de entrada usando a área de transferência do seu aparelho</string>
|
||||
<string name="persistent_notification_title">Notificação persistente</string>
|
||||
<string name="persistent_notification_summary">Adicionar uma notificação quando o banco de dados for aberto</string>
|
||||
<string name="advanced_unlock_explanation_summary">Usar destravamento avançado para abrir o banco de dados mais facilmente</string>
|
||||
<string name="database_data_compression_title">Compressão dos dados</string>
|
||||
<string name="database_data_compression_summary">Compressão dos dados reduz o tamanho do banco de dados.</string>
|
||||
|
||||
@@ -72,7 +72,6 @@
|
||||
<string name="error_pass_match">As palavras-passe não coincidem.</string>
|
||||
<string name="error_rounds_too_large">\"Número de rodadas\" é muito grande. Modificado para 2147483648.</string>
|
||||
<string name="error_string_key">Um nome do campo é necessário para cada string.</string>
|
||||
<string name="error_title_required">Adicione um título.</string>
|
||||
<string name="error_wrong_length">Digite um número inteiro positivo no campo \"Tamanho\".</string>
|
||||
<string name="field_name">Nome do campo</string>
|
||||
<string name="field_value">Valor do campo</string>
|
||||
@@ -358,10 +357,9 @@
|
||||
<string name="content_description_keyfile_checkbox">Caixa de seleção keyfile</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Repetir alternar a visibilidade da palavra-passe</string>
|
||||
<string name="content_description_entry_icon">Ícone da entrada</string>
|
||||
<string name="content_description_entry_save">Gravação de entrada</string>
|
||||
<string name="content_description_password_generator">Gerador de palavras-passe</string>
|
||||
<string name="entry_password_generator">Gerador de palavras-passe</string>
|
||||
<string name="content_description_password_length">Comprimento da palavra-passe</string>
|
||||
<string name="content_description_add_field">Adicionar campo</string>
|
||||
<string name="entry_add_field">Adicionar campo</string>
|
||||
<string name="content_description_remove_field">Remover campo</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">Você não pode mover uma entrada para cá.</string>
|
||||
|
||||
@@ -36,10 +36,9 @@
|
||||
<string name="content_description_keyfile_checkbox">Verifica fisierul cheie</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Repetați pentru a comuta vizibilitatea parolei</string>
|
||||
<string name="content_description_entry_icon">Pictograma de intrare</string>
|
||||
<string name="content_description_entry_save">Salvați intrarea</string>
|
||||
<string name="content_description_password_generator">Generator de parole</string>
|
||||
<string name="entry_password_generator">Generator de parole</string>
|
||||
<string name="content_description_password_length">Lungimea parolei</string>
|
||||
<string name="content_description_add_field">Adăugați câmp</string>
|
||||
<string name="entry_add_field">Adăugați câmp</string>
|
||||
<string name="content_description_remove_field">Elimina câmp</string>
|
||||
<string name="content_description_update_from_list">Actualizați</string>
|
||||
<string name="content_description_remove_from_list">Elimina</string>
|
||||
@@ -95,7 +94,6 @@
|
||||
<string name="error_pass_match">Parolele nu se potrivesc.</string>
|
||||
<string name="error_rounds_too_large">\"Transformările rotunde\" prea sus. Setarea la 2147483648.</string>
|
||||
<string name="error_string_key">Fiecare șir trebuie să aibă un nume de câmp.</string>
|
||||
<string name="error_title_required">Adăugați un titlu.</string>
|
||||
<string name="error_wrong_length">Introduceți un număr întreg pozitiv în câmpul \"Lungime\".</string>
|
||||
<string name="error_autofill_enable_service">Nu s-a putut activa serviciul de completare automată.</string>
|
||||
<string name="error_move_folder_in_itself">Nu puteți muta un grup în sine.</string>
|
||||
@@ -175,4 +173,263 @@
|
||||
<string name="hide_password_title">Ascundeți parolele</string>
|
||||
<string name="hide_password_summary">Mascați parolele (***) în mod implicit</string>
|
||||
<string name="about">Despre</string>
|
||||
<string name="no_url_handler">Instalați un browser web pentru a deschide această adresă URL.</string>
|
||||
<string name="select_database_file">Deschide baza de date existentă</string>
|
||||
<string name="create_keepass_file">Creați o bază de date nouă</string>
|
||||
<string name="open_recent">Baze de date recente</string>
|
||||
<string name="progress_create">Crearea noii baze de date …</string>
|
||||
<string name="progress_title">Lucrând …</string>
|
||||
<string name="protection">Protecție</string>
|
||||
<string name="read_only">Protejat la scriere</string>
|
||||
<string name="read_only_warning">În funcție de managerul de fișiere, este posibil ca KeePassDX să nu poată scrie în stocare.</string>
|
||||
<string name="contains_duplicate_uuid">Baza de date conține UUID-uri duplicate.</string>
|
||||
<string name="contains_duplicate_uuid_procedure">Prin validarea acestui dialog, KeePassDX va rezolva problema (prin generarea de noi UUID-uri pentru duplicate) și va continua.</string>
|
||||
<string name="selection_mode">Mod de selectare</string>
|
||||
<string name="root">Rădăcină</string>
|
||||
<string name="encryption_explanation">Algoritmul bazei de date de criptare utilizat pentru toate datele.</string>
|
||||
<string name="kdf_explanation">Pentru a genera cheia pentru algoritmul de criptare, cheia principală este transformată folosind o funcție de derivare a cheilor sărate aleatoriu.</string>
|
||||
<string name="rounds">Rundele de transformare</string>
|
||||
<string name="rounds_explanation">Rundele suplimentare de criptare oferă o protecție mai mare împotriva atacurilor de forță brută, dar pot încetini cu adevărat încărcarea și economisirea.</string>
|
||||
<string name="memory_usage">Utilizarea memoriei</string>
|
||||
<string name="memory_usage_explanation">Cantitatea de memorie (în octeți) care trebuie utilizată de funcția de derivare a cheilor.</string>
|
||||
<string name="parallelism">Paralelism</string>
|
||||
<string name="parallelism_explanation">Gradul de paralelism (adică numărul de fire) utilizat de funcția de derivare a cheilor.</string>
|
||||
<string name="saving_database">Salvarea bazei de date …</string>
|
||||
<string name="command_execution">Executarea comenzii …</string>
|
||||
<string name="do_not_kill_app">Nu omori aplicația …</string>
|
||||
<string name="space">Spatiu</string>
|
||||
<string name="search_label">Cauta</string>
|
||||
<string name="sort_menu">Sorteaza</string>
|
||||
<string name="sort_ascending">Prima cea mai mică ↓</string>
|
||||
<string name="sort_groups_before">Grupuri înainte</string>
|
||||
<string name="sort_recycle_bin_bottom">Reciclați coșul din partea de jos</string>
|
||||
<string name="sort_db">Ordine naturală</string>
|
||||
<string name="sort_title">Titlu</string>
|
||||
<string name="sort_username">Nume de utilizator</string>
|
||||
<string name="sort_creation_time">Creare</string>
|
||||
<string name="sort_last_modify_time">Modificare</string>
|
||||
<string name="sort_last_access_time">Acces</string>
|
||||
<string name="special">Special</string>
|
||||
<string name="search">Căutare</string>
|
||||
<string name="search_results">Rezultatele căutării</string>
|
||||
<string name="underline">Subliniere</string>
|
||||
<string name="unsupported_db_version">Versiunea bazei de date neacceptată.</string>
|
||||
<string name="uppercase">Cu majuscule</string>
|
||||
<string name="warning">Avertizare</string>
|
||||
<string name="warning_password_encoding">Evitați caracterele parole în afara formatului de codare a textului în fișierul bazei de date (caracterele nerecunoscute sunt convertite în aceeași literă).</string>
|
||||
<string name="warning_unmounted">Montați cardul de memorie pentru a crea sau încărca o bază de date.</string>
|
||||
<string name="warning_empty_password">Chiar nu doriți nicio protecție de deblocare a parolei\?</string>
|
||||
<string name="warning_no_encryption_key">Ești sigur că nu vrei să folosești nicio cheie de criptare\?</string>
|
||||
<string name="warning_permanently_delete_nodes">Sigur doriți să ștergeți definitiv nodurile selectate\?</string>
|
||||
<string name="version_label">Versiunea %1$s</string>
|
||||
<string name="build_label">Construiți %1$s</string>
|
||||
<string name="configure_biometric">Indicatorul biometric este acceptat, dar nu este configurat.</string>
|
||||
<string name="keystore_not_accessible">Magazinul de chei nu este inițializat corect.</string>
|
||||
<string name="open_biometric_prompt_unlock_database">Deschideți promptul biometric pentru deblocarea bazei de date</string>
|
||||
<string name="open_biometric_prompt_store_credential">Deschideți promptul biometric pentru a stoca datele de acreditare</string>
|
||||
<string name="biometric_prompt_store_credential_title">Salvați recunoașterea biometrică</string>
|
||||
<string name="biometric_prompt_store_credential_message">Avertisment: trebuie să vă amintiți parola de master dacă utilizați recunoașterea biometrică.</string>
|
||||
<string name="biometric_prompt_extract_credential_title">Baza de date deschisă cu recunoaștere biometrică</string>
|
||||
<string name="biometric_prompt_extract_credential_message">Extrageți datele de bază cu date biometrice</string>
|
||||
<string name="encrypted_value_stored">Parola criptată stocată</string>
|
||||
<string name="biometric_invalid_key">Nu pot citi cheia biometrică. Vă rugăm să îl ștergeți și să repetați procedura de recunoaștere biometrică.</string>
|
||||
<string name="biometric_not_recognized">Nu a putut recunoaște biometric</string>
|
||||
<string name="biometric_scanning_error">Eroare biometrică: %1$s</string>
|
||||
<string name="no_credentials_stored">Această bază de date nu are încă credențiale stocate.</string>
|
||||
<string name="credential_before_click_biometric_button">De acum nu există date creditate stocate.</string>
|
||||
<string name="database_history">Istoric</string>
|
||||
<string name="menu_appearance_settings">Aparenta</string>
|
||||
<string name="biometric">Biometric</string>
|
||||
<string name="general">General</string>
|
||||
<string name="autofill">Autocompletare</string>
|
||||
<string name="autofill_service_name">Completarea automată a formularului KeePassDX</string>
|
||||
<string name="autofill_sign_in_prompt">Conectați-vă cu KeePassDX</string>
|
||||
<string name="autofill_explanation_summary">Permiteți completarea automată pentru a completa rapid formularele din alte aplicații</string>
|
||||
<string name="set_autofill_service_title">Setați serviciul automat de completare automată</string>
|
||||
<string name="password_size_title">Mărimea generată a parolei</string>
|
||||
<string name="password_size_summary">Setează dimensiunea implicită a parolelor generate</string>
|
||||
<string name="list_password_generator_options_title">Caractere parolă</string>
|
||||
<string name="list_password_generator_options_summary">Setați caractere permise generator de parole</string>
|
||||
<string name="database_opened">Baza de date a fost deschisă</string>
|
||||
<string name="clipboard">Clipboard</string>
|
||||
<string name="clipboard_explanation_summary">Copiați câmpurile de intrare cu ajutorul clipboard-ului dispozitivului</string>
|
||||
<string name="clipboard_notifications_title">Clipboard notificări</string>
|
||||
<string name="clipboard_notifications_summary">Activați notificările pentru clipboard pentru a copia câmpurile când vizionați o intrare</string>
|
||||
<string name="clipboard_warning">Dacă ștergerea automată a clipboard-ului nu reușește, ștergeți manual istoricul acestuia.</string>
|
||||
<string name="lock">Blocheaza</string>
|
||||
<string name="lock_database_screen_off_title">Blocare ecran</string>
|
||||
<string name="lock_database_screen_off_summary">Încărcați baza de date când ecranul este deconectat</string>
|
||||
<string name="lock_database_back_root_title">Apăsați „Înapoi” pentru a bloca ecranul</string>
|
||||
<string name="lock_database_back_root_summary">Blocați baza de date atunci când utilizatorul face clic pe butonul înapoi de pe ecranul rădăcină</string>
|
||||
<string name="advanced_unlock">Deblocare avansată</string>
|
||||
<string name="advanced_unlock_explanation_summary">Utilizați deblocarea avansată pentru a deschide o bază de date mai ușor</string>
|
||||
<string name="biometric_unlock_enable_title">Deblocare biometrică</string>
|
||||
<string name="biometric_unlock_enable_summary">Vă permite să scanați biometric pentru a deschide baza de date</string>
|
||||
<string name="biometric_auto_open_prompt_title">Indicator biometric deschis automat</string>
|
||||
<string name="biometric_auto_open_prompt_summary">Deschideți automat biometric prompt atunci când o cheie biometrică este definită pentru o bază de date</string>
|
||||
<string name="biometric_delete_all_key_title">Ștergeți cheile de criptare</string>
|
||||
<string name="biometric_delete_all_key_summary">Ștergeți toate cheile de criptare legate de recunoașterea biometrică</string>
|
||||
<string name="biometric_delete_all_key_warning">Sigur doriți să ștergeți toate cheile legate de recunoașterea biometrică\?</string>
|
||||
<string name="unavailable_feature_text">Nu s-a putut porni această caracteristică.</string>
|
||||
<string name="unavailable_feature_version">Versiunea dvs. de Android %1$s nu corespunde versiunii minime %2$s necesare.</string>
|
||||
<string name="unavailable_feature_hardware">Nu s-a putut găsi hardware-ul corespunzător.</string>
|
||||
<string name="file_name">Nume fișier</string>
|
||||
<string name="path">Cale</string>
|
||||
<string name="assign_master_key">Atribuie o cheie master</string>
|
||||
<string name="full_file_path_enable_title">Calea fișierului</string>
|
||||
<string name="full_file_path_enable_summary">Vizualizați calea completă a fișierului</string>
|
||||
<string name="database_data_compression_title">Compresia datelor</string>
|
||||
<string name="database_data_compression_summary">Compresia datelor reduce dimensiunea bazei de date.</string>
|
||||
<string name="recycle_bin_title">Utilizarea cosului de gunoi</string>
|
||||
<string name="recycle_bin_summary">Mută grupuri și intrări în grupul „Coș de reciclare” înainte de ștergere</string>
|
||||
<string name="recycle_bin_group_title">Grupul cosului de reciclare</string>
|
||||
<string name="max_history_items_title">Număr maxim</string>
|
||||
<string name="max_history_items_summary">Limitați numărul de articole istorice pe intrare</string>
|
||||
<string name="max_history_size_title">Dimensiune maximă</string>
|
||||
<string name="max_history_size_summary">Limitați dimensiunea istoricului (în octeți) pe intrare</string>
|
||||
<string name="settings_database_recommend_changing_master_key_title">Recomandă reînnoirea</string>
|
||||
<string name="settings_database_recommend_changing_master_key_summary">Recomandă schimbarea cheii master (zile)</string>
|
||||
<string name="settings_database_force_changing_master_key_title">Forteaza reinoirea</string>
|
||||
<string name="settings_database_force_changing_master_key_summary">Solicitați schimbarea cheii master (zile)</string>
|
||||
<string name="settings_database_force_changing_master_key_next_time_title">Forteaza reînnoirea data viitoare</string>
|
||||
<string name="settings_database_force_changing_master_key_next_time_summary">Solicitați schimbarea cheii master data viitoare (o dată)</string>
|
||||
<string name="monospace_font_fields_enable_title">Font camp</string>
|
||||
<string name="monospace_font_fields_enable_summary">Schimbați fontul folosit în câmpuri pentru o mai bună vizibilitate a caracterelor</string>
|
||||
<string name="allow_copy_password_title">Clipboard de incredere</string>
|
||||
<string name="allow_copy_password_summary">Permiteți copierea parolei de intrare și câmpurile protejate în clipboard</string>
|
||||
<string name="allow_copy_password_warning">Avertisment: Clipboard-ul este distribuit de toate aplicațiile. Dacă datele sensibile sunt copiate, alt software îl poate recupera.</string>
|
||||
<string name="enable">Activeaza</string>
|
||||
<string name="disable">Dezactiveaza</string>
|
||||
<string name="clear_clipboard_notification_title">Curata la închidere</string>
|
||||
<string name="clear_clipboard_notification_summary">Blocați baza de date la închiderea notificării</string>
|
||||
<string name="database_name_title">Numele bazei de date</string>
|
||||
<string name="database_description_title">Descrierea bazei de date</string>
|
||||
<string name="database_default_username_title">Nume utilizator implicit</string>
|
||||
<string name="database_custom_color_title">Culoare personalizată a bazei de date</string>
|
||||
<string name="database_version_title">Versiunea bazei de date</string>
|
||||
<string name="text_appearance">Text</string>
|
||||
<string name="application_appearance">Aplicație</string>
|
||||
<string name="other">Alta</string>
|
||||
<string name="compression">Compresie</string>
|
||||
<string name="compression_none">Nimic</string>
|
||||
<string name="compression_gzip">gzip</string>
|
||||
<string name="recycle_bin">Cos de reciclare</string>
|
||||
<string name="keyboard">Tastatura</string>
|
||||
<string name="magic_keyboard_title">TastaturaMagica</string>
|
||||
<string name="magic_keyboard_explanation_summary">Activați o tastatură personalizată care conține parolele și toate câmpurile de identitate</string>
|
||||
<string name="device_keyboard_setting_title">Setări tastatură dispozitiv</string>
|
||||
<string name="keyboard_name">TastaturaMagica</string>
|
||||
<string name="keyboard_label">TastaturaMagica (KeePassDX)</string>
|
||||
<string name="keyboard_setting_label">Setări TastaturaMagica</string>
|
||||
<string name="keyboard_entry_category">Intrare</string>
|
||||
<string name="keyboard_selection_entry_title">Selectia de intrare</string>
|
||||
<string name="keyboard_selection_entry_summary">Afișați câmpurile de intrare în TastaturaMagica când vizualizați o intrare</string>
|
||||
<string name="keyboard_notification_entry_title">Informații de notificare</string>
|
||||
<string name="keyboard_notification_entry_summary">Afișați o notificare atunci când este disponibilă o intrare</string>
|
||||
<string name="keyboard_notification_entry_clear_close_title">Curata la închidere</string>
|
||||
<string name="keyboard_notification_entry_clear_close_summary">Închideți baza de date la închiderea notificării</string>
|
||||
<string name="keyboard_entry_timeout_title">Sesiune expirata</string>
|
||||
<string name="keyboard_entry_timeout_summary">Sesiune expirata pentru a șterge intrarea tastaturii</string>
|
||||
<string name="keyboard_notification_entry_content_title_text">Intrare</string>
|
||||
<string name="keyboard_notification_entry_content_title">%1$s disponibil pe TastaturaMagica</string>
|
||||
<string name="keyboard_notification_entry_content_text">%1$s</string>
|
||||
<string name="keyboard_appearance_category">Aparenta</string>
|
||||
<string name="keyboard_theme_title">Tema tastaturii</string>
|
||||
<string name="keyboard_keys_category">Chei</string>
|
||||
<string name="keyboard_auto_go_action_title">Acțiune automată cu cheie</string>
|
||||
<string name="keyboard_auto_go_action_summary">Acțiunea tastei Go se efectuează automat după apăsarea unei taste Field</string>
|
||||
<string name="keyboard_key_vibrate_title">Apăsări de taste vibratoare</string>
|
||||
<string name="keyboard_key_sound_title">Apăsări de taste cheie</string>
|
||||
<string name="allow_no_password_title">Nu permiteți nicio cheie principală</string>
|
||||
<string name="allow_no_password_summary">Activați butonul „Deschide” dacă nu sunt selectate acreditările</string>
|
||||
<string name="delete_entered_password_title">Ștergeți parola</string>
|
||||
<string name="delete_entered_password_summary">Șterge parola introdusă după o încercare de conectare</string>
|
||||
<string name="enable_read_only_title">Protejat la scriere</string>
|
||||
<string name="enable_read_only_summary">Deschideți baza de date numai în citire în mod implicit</string>
|
||||
<string name="enable_auto_save_database_title">Baza de date Autosave</string>
|
||||
<string name="enable_auto_save_database_summary">Salvați automat baza de date după o acțiune importantă (numai în modul „Modificabil”)</string>
|
||||
<string name="enable_education_screens_title">Ecrane educative</string>
|
||||
<string name="enable_education_screens_summary">Evidențiați elementele pentru a afla cum funcționează aplicația</string>
|
||||
<string name="reset_education_screens_title">Resetați ecranele educaționale</string>
|
||||
<string name="reset_education_screens_summary">Afișează din nou toate elementele educaționale</string>
|
||||
<string name="reset_education_screens_text">Ecranele educaționale sunt resetate</string>
|
||||
<string name="education_create_database_title">Creați fișierul dvs. de bază de date</string>
|
||||
<string name="education_create_database_summary">Creați primul dvs. fișier de gestionare a parolelor.</string>
|
||||
<string name="education_select_database_title">Deschideți o bază de date existentă</string>
|
||||
<string name="education_select_database_summary">Deschideți fișierul bazei de date anterioare din browserul de fișiere pentru a-l continua.</string>
|
||||
<string name="education_new_node_title">Adăugați elemente în baza de date</string>
|
||||
<string name="education_new_node_summary">Înscrierile vă ajută să vă gestionați identitățile digitale.
|
||||
\n
|
||||
\nGrupuri (~ foldere) organizează intrări în baza de date.</string>
|
||||
<string name="education_search_title">Căutați prin intrări</string>
|
||||
<string name="education_search_summary">Introduceți titlul, numele de utilizator sau conținutul altor câmpuri pentru a prelua parolele.</string>
|
||||
<string name="education_biometric_title">Deblocarea bazei de date prin biometric</string>
|
||||
<string name="education_biometric_summary">Conectați parola la biometrica scanată pentru a debloca rapid baza de date.</string>
|
||||
<string name="education_entry_edit_title">Modificați intrarea</string>
|
||||
<string name="education_entry_edit_summary">Modificați-vă înregistrarea cu câmpuri personalizate. Datele despre pool pot fi referențiate între diferite câmpuri de intrare.</string>
|
||||
<string name="education_generate_password_title">Creați o parolă puternică pentru intrarea dvs.</string>
|
||||
<string name="education_generate_password_summary">Generați o parolă puternică pentru a vă asocia cu intrarea dvs., definiți-o ușor în funcție de criteriile formularului și nu uitați parola securizată.</string>
|
||||
<string name="education_entry_new_field_title">Adăugați câmpuri personalizate</string>
|
||||
<string name="education_entry_new_field_summary">Înregistrați un câmp suplimentar, adăugați o valoare și protejați-l opțional.</string>
|
||||
<string name="education_unlock_title">Deblocați baza de date</string>
|
||||
<string name="education_unlock_summary">Introduceți parola și / sau fișierul cheie pentru a debloca baza de date.
|
||||
\n
|
||||
\nBackup-ul fișierului dvs. de bază de date într-un loc sigur după fiecare modificare.</string>
|
||||
<string name="education_read_only_title">Protejați-vă baza de date</string>
|
||||
<string name="education_read_only_summary">Schimbați modul de deschidere pentru sesiune.
|
||||
\n
|
||||
\n„Protecție la scriere” previne modificările neintenționate ale bazei de date.
|
||||
\n„Modificabil” vă permite să adăugați, să ștergeți sau să modificați toate elementele.</string>
|
||||
<string name="education_field_copy_title">Copiați un câmp</string>
|
||||
<string name="education_field_copy_summary">Câmpurile copiate pot fi lipite oriunde.
|
||||
\n
|
||||
\nFolosiți metoda de completare a formularului pe care o preferați.</string>
|
||||
<string name="education_lock_title">Blocați baza de date</string>
|
||||
<string name="education_lock_summary">Blocați rapid baza de date, puteți configura aplicația pentru a o bloca după un timp și când ecranul se va opri.</string>
|
||||
<string name="education_sort_title">Sortarea articolelor</string>
|
||||
<string name="education_sort_summary">Alegeți cum sunt sortate intrările și grupurile.</string>
|
||||
<string name="education_donation_title">Participa</string>
|
||||
<string name="education_donation_summary">Ajută la creșterea stabilității, securității și la adăugarea mai multor funcții.</string>
|
||||
<string name="html_text_ad_free">Spre deosebire de multe aplicații de gestionare a parolelor, acesta este <strong> gratuit de anunțuri </strong>, <strong> software liber copilefted </strong> și nu colectează date personale pe serverele sale, indiferent de versiunea pe care o utilizați.</string>
|
||||
<string name="html_text_buy_pro">Cumpărând versiunea pro, veți avea acces la acest <strong> stil vizual </strong> și vă va ajuta în special <strong> implementarea proiectelor comunitare. </strong></string>
|
||||
<string name="html_text_feature_generosity">Acest <strong> stil vizual </strong> este disponibil datorită generozității tale.</string>
|
||||
<string name="html_text_donation">Pentru a ne păstra libertatea și pentru a fi mereu activi, ne bazăm pe contribuția dvs. <strong>. </strong></string>
|
||||
<string name="html_text_dev_feature">Această caracteristică este <strong> în curs de dezvoltare </strong> și necesită ca contribuția dvs <strong> să fie disponibilă în curând.</string>
|
||||
<string name="html_text_dev_feature_buy_pro">Cumpărând versiunea <strong> pro </strong>,</string>
|
||||
<string name="html_text_dev_feature_contibute">Prin <strong> contribuție </strong>,</string>
|
||||
<string name="html_text_dev_feature_encourage">încurajezi dezvoltatorii să creeze <strong> funcții noi </strong> și să <strong> remedieze erori </strong> în conformitate cu observațiile tale.</string>
|
||||
<string name="html_text_dev_feature_thanks">Mulțumesc mult pentru contribuție.</string>
|
||||
<string name="html_text_dev_feature_work_hard">Muncim din greu pentru a lansa rapid această caracteristică.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Nu uitați să mențineți aplicația la zi instalând noi versiuni.</string>
|
||||
<string name="download">Descărcați</string>
|
||||
<string name="contribute">Contribuie</string>
|
||||
<string name="download_attachment">Descărcați %1$s</string>
|
||||
<string name="download_initialization">Inițializare …</string>
|
||||
<string name="download_progression">In progress: %1$d%</string>
|
||||
<string name="download_finalization">Finalizare …</string>
|
||||
<string name="download_complete">Complet! Atingeți pentru a deschide fișierul.</string>
|
||||
<string name="encryption_rijndael">Rijndael (AES)</string>
|
||||
<string name="encryption_twofish">Twofish</string>
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
<string name="kdf_AES">AES</string>
|
||||
<string name="kdf_Argon2">Argon2</string>
|
||||
<string name="style_choose_title">Tema aplicației</string>
|
||||
<string name="style_choose_summary">Tema folosită în aplicație</string>
|
||||
<string name="icon_pack_choose_title">Pachet de pictograme</string>
|
||||
<string name="icon_pack_choose_summary">Pachet de pictograme folosit în aplicație</string>
|
||||
<string name="hide_expired_entries_title">Ascundeți intrările expirate</string>
|
||||
<string name="hide_expired_entries_summary">Înscrierile expirate vor fi ascunse</string>
|
||||
<string name="omit_backup_search_title">Nu căutați prin intrări de rezervă</string>
|
||||
<string name="omit_backup_search_summary">Omite grupurile „Backup” și „Recycle bin” din rezultatele căutării</string>
|
||||
<string name="auto_focus_search_title">Căutare rapidă</string>
|
||||
<string name="auto_focus_search_summary">Solicitați o căutare atunci când deschideți o bază de date</string>
|
||||
<string name="remember_database_locations_title">Salvați locația bazelor de date</string>
|
||||
<string name="remember_database_locations_summary">Amintiți-vă locația bazelor de date</string>
|
||||
<string name="remember_keyfile_locations_title">Salvați locația fișierelor cheie</string>
|
||||
<string name="remember_keyfile_locations_summary">Amintiți-vă locația bazelor de date cheie de date</string>
|
||||
<string name="show_recent_files_title">Afișați fișiere recente</string>
|
||||
<string name="show_recent_files_summary">Afișați locațiile bazelor de date recente</string>
|
||||
<string name="hide_broken_locations_title">Ascundeți linkurile de bază de date stricate</string>
|
||||
<string name="hide_broken_locations_summary">Ascundeți legăturile rupte în lista bazelor de date recente</string>
|
||||
<string name="warning_database_read_only">Acordă acces la scriere fișier pentru a salva modificările bazei de date</string>
|
||||
</resources>
|
||||
@@ -43,8 +43,8 @@
|
||||
<string name="decrypting_db">Расшифровка базы…</string>
|
||||
<string name="default_checkbox">База по умолчанию</string>
|
||||
<string name="digits">Цифры</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft с <strong>открытым исходным кодом<strong> и <strong>без рекламы<strong>.
|
||||
\nРаспространяется под лицензией <strong>GPLv3<strong> без каких-либо гарантий.</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft с <strong>открытым исходным кодом</strong> и <strong>без рекламы</strong>.
|
||||
\nРаспространяется под лицензией <strong>GPLv3</strong> без каких-либо гарантий.</string>
|
||||
<string name="select_database_file">Открыть существующую базу</string>
|
||||
<string name="entry_accessed">Доступ</string>
|
||||
<string name="entry_cancel">Отмена</string>
|
||||
@@ -72,7 +72,6 @@
|
||||
<string name="error_pass_match">Пароли не совпадают.</string>
|
||||
<string name="error_rounds_too_large">Предельное значение 2147483648.</string>
|
||||
<string name="error_string_key">Каждое поле должно иметь название.</string>
|
||||
<string name="error_title_required">Введите название.</string>
|
||||
<string name="error_wrong_length">Поле \"Длина\" должно быть положительным целым числом.</string>
|
||||
<string name="field_name">Название поля</string>
|
||||
<string name="field_value">Значение поля</string>
|
||||
@@ -302,7 +301,7 @@
|
||||
<string name="education_sort_summary">Выберите критерий сортировки записей и групп.</string>
|
||||
<string name="education_donation_title">Участвуйте</string>
|
||||
<string name="education_donation_summary">Примите участие в проекте для повышения стабильности, безопасности и добавления новых возможностей.</string>
|
||||
<string name="html_text_ad_free">В отличие от многих приложений управления паролями, это <strong>без рекламы<strong> и <strong>свободно от лицензирования<strong>. Оно не собирает ваши личные данные на своих серверах независимо от того, какую версию вы используете.</string>
|
||||
<string name="html_text_ad_free">В отличие от многих приложений управления паролями, это <strong>без рекламы</strong> и <strong>свободно от лицензирования</strong>. Оно не собирает ваши личные данные на своих серверах независимо от того, какую версию вы используете.</string>
|
||||
<string name="html_text_buy_pro">При покупке Pro-версии вы будете иметь доступ к этим <strong>визуальным стилям</strong> и особенно поможете <strong>реализации общественных проектов</strong>.</string>
|
||||
<string name="html_text_feature_generosity">Эти <strong>визуальные стили</strong> доступны благодаря вашей щедрости.</string>
|
||||
<string name="html_text_donation">Для того, чтобы сохранить нашу независимость и быть всегда активными, мы рассчитываем на ваш <strong>вклад</strong>.</string>
|
||||
@@ -314,7 +313,7 @@
|
||||
<string name="html_text_dev_feature_work_hard">Мы прилагаем все усилия, чтобы быстро выпустить эту функцию.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Не забывайте обновлять приложение.</string>
|
||||
<string name="download">Скачать</string>
|
||||
<string name="contribute">Помощь проекту</string>
|
||||
<string name="contribute">Вклад</string>
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
<string name="kdf_AES">AES</string>
|
||||
<string name="kdf_Argon2">Argon2</string>
|
||||
@@ -361,10 +360,9 @@
|
||||
<string name="content_description_keyfile_checkbox">Флажок ключевого файла</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Повтор переключения видимости пароля</string>
|
||||
<string name="content_description_entry_icon">Значок записи</string>
|
||||
<string name="content_description_entry_save">Сохранение записи</string>
|
||||
<string name="content_description_password_generator">Генератор паролей</string>
|
||||
<string name="entry_password_generator">Генератор паролей</string>
|
||||
<string name="content_description_password_length">Длина пароля</string>
|
||||
<string name="content_description_add_field">Добавить поле</string>
|
||||
<string name="entry_add_field">Добавить поле</string>
|
||||
<string name="content_description_remove_field">Удалить поле</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">Вы не можете переместить запись сюда.</string>
|
||||
@@ -412,8 +410,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">Если вы разрешите, KeePassDX исправит проблему (путём создания новых UUID для дубликатов) и продолжит работу.</string>
|
||||
<string name="database_opened">База открыта</string>
|
||||
<string name="clipboard_explanation_summary">Копирование полей ввода с помощью буфера обмена устройства</string>
|
||||
<string name="persistent_notification_title">Постоянное уведомление</string>
|
||||
<string name="persistent_notification_summary">Показывать уведомление, пока открыта база</string>
|
||||
<string name="advanced_unlock_explanation_summary">Использовать дополнительную разблокировку для более лёгкого открытия базы данных</string>
|
||||
<string name="database_data_compression_title">Сжатие данных</string>
|
||||
<string name="database_data_compression_summary">Сжатие данных уменьшает размер базы.</string>
|
||||
@@ -450,14 +446,14 @@
|
||||
<string name="keyboard_auto_go_action_summary">Выполнять команду \"Ввод\" автоматически после нажатия кнопки заполнения поля</string>
|
||||
<string name="download_attachment">Скачать %1$s</string>
|
||||
<string name="download_initialization">Инициализация…</string>
|
||||
<string name="download_progression">Выполнение: %1$d%</string>
|
||||
<string name="download_progression">Выполнение: %1$d%</string>
|
||||
<string name="download_finalization">Завершение…</string>
|
||||
<string name="download_complete">Готово! Нажмите, чтобы открыть файл.</string>
|
||||
<string name="hide_expired_entries_title">Скрывать устаревшие записи</string>
|
||||
<string name="hide_expired_entries_summary">Записи с истёкшим сроком окончания будут скрыты</string>
|
||||
<string name="contact">Контактная информация</string>
|
||||
<string name="contribution">Вклад</string>
|
||||
<string name="html_about_contribution">Для <strong>сохранения нашей независимости<strong>, <strong>исправления ошибок<strong>, <strong>добавления новых функций<strong> и <strong>поддержания разработки в активном состоянии<strong>, мы рассчитываем на ваш <strong>вклад<strong>.</string>
|
||||
<string name="contribution">Помощь проекту</string>
|
||||
<string name="html_about_contribution">Для <strong>сохранения нашей независимости</strong>, <strong>исправления ошибок</strong>, <strong>добавления новых функций</strong> и <strong>поддержания разработки в активном состоянии</strong>, мы рассчитываем на ваш <strong>вклад</strong>.</string>
|
||||
<string name="auto_focus_search_title">Быстрый поиск</string>
|
||||
<string name="auto_focus_search_summary">Открывать поисковый запрос при открытии базы</string>
|
||||
<string name="remember_database_locations_title">Хранить расположение баз</string>
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
<string name="error_pass_gen_type">Musí byť vybraý najmenej jeden typ generovania hesla</string>
|
||||
<string name="error_pass_match">Heslá sa nezhodujú.</string>
|
||||
<string name="error_rounds_too_large">Príliš veľa opakovaní. Nastavujem na 2147483648.</string>
|
||||
<string name="error_title_required">Vyžaduje sa názov.</string>
|
||||
<string name="error_wrong_length">Zadajte celé kladné číslo na dĺžku poľa</string>
|
||||
<string name="file_browser">Správca Súborov</string>
|
||||
<string name="generate_password">Generovať Heslo</string>
|
||||
@@ -157,8 +156,7 @@
|
||||
<string name="contact">Kontakt</string>
|
||||
<string name="content_description_open_file">Otvoriť súbor</string>
|
||||
<string name="content_description_file_information">Informácie o súbore</string>
|
||||
<string name="content_description_entry_save">Uložiť záznam</string>
|
||||
<string name="content_description_password_generator">Generátor hesla</string>
|
||||
<string name="entry_password_generator">Generátor hesla</string>
|
||||
<string name="content_description_password_length">Dĺžka hesla</string>
|
||||
<string name="content_description_background">Pozadie</string>
|
||||
<string name="security">Bezpečnosť</string>
|
||||
|
||||
@@ -72,7 +72,6 @@
|
||||
<string name="error_pass_match">Lösenorden matchar inte.</string>
|
||||
<string name="error_rounds_too_large">\"Transformationsrundor\" är för stort. Sätter värdet till 2147483648.</string>
|
||||
<string name="error_string_key">Varje sträng måste ha ett fältnamn.</string>
|
||||
<string name="error_title_required">Lägg till en titel.</string>
|
||||
<string name="error_wrong_length">Ange ett positivt heltal i fältet för längd.</string>
|
||||
<string name="field_name">Fältnamn</string>
|
||||
<string name="field_value">Fältvärde</string>
|
||||
@@ -173,10 +172,9 @@
|
||||
<string name="content_description_keyfile_checkbox">Nyckelfilskryssruta</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Repetera växla lösenordssynlighet</string>
|
||||
<string name="content_description_entry_icon">Post-ikon</string>
|
||||
<string name="content_description_entry_save">Spara post</string>
|
||||
<string name="content_description_password_generator">Lösenordsgenerator</string>
|
||||
<string name="entry_password_generator">Lösenordsgenerator</string>
|
||||
<string name="content_description_password_length">Lösenords längd</string>
|
||||
<string name="content_description_add_field">Lägg till fält</string>
|
||||
<string name="entry_add_field">Lägg till fält</string>
|
||||
<string name="content_description_remove_field">Ta bort fält</string>
|
||||
<string name="content_description_background">Bakgrund</string>
|
||||
<string name="content_description_update_from_list">Uppdatera</string>
|
||||
@@ -410,8 +408,6 @@
|
||||
<string name="autofill_explanation_summary">Aktivera autofyll för att snabbt kunna fylla i formulär i andra appar</string>
|
||||
<string name="database_opened">Databas öppnad</string>
|
||||
<string name="clipboard_explanation_summary">Kopiera post-fält med hjälp av enhetens urklipp</string>
|
||||
<string name="persistent_notification_title">Beständig avisering</string>
|
||||
<string name="persistent_notification_summary">Lägg till en avisering när databasen är öppen</string>
|
||||
<string name="advanced_unlock_explanation_summary">Använd avancerad upplåsning för att öppna en databas enklare</string>
|
||||
<string name="database_data_compression_title">Datakomprimering</string>
|
||||
<string name="database_data_compression_summary">Datakomprimering reducerar databasens storlek.</string>
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
<string name="error_pass_match">Parolalar uyuşmuyor.</string>
|
||||
<string name="error_rounds_too_large">\"Dönüşüm turları\" çok yüksek. 2147483648\'e ayarlayın.</string>
|
||||
<string name="error_string_key">Her dizenin bir alan adı olmalıdır.</string>
|
||||
<string name="error_title_required">Bir başlık ekle.</string>
|
||||
<string name="error_wrong_length">\"Uzunluk\" alanına pozitif bir tam sayı girin.</string>
|
||||
<string name="error_autofill_enable_service">Otomatik doldurma hizmeti etkinleştirilemedi.</string>
|
||||
<string name="error_move_folder_in_itself">Bir grubu kendine taşıyamazsın.</string>
|
||||
@@ -337,9 +336,9 @@
|
||||
<string name="content_description_password_checkbox">Parola onay kutusu</string>
|
||||
<string name="content_description_keyfile_checkbox">Anahtar dosyası onay kutusu</string>
|
||||
<string name="content_description_entry_icon">Giriş simgesi</string>
|
||||
<string name="content_description_password_generator">Parola üreteci</string>
|
||||
<string name="entry_password_generator">Parola üreteci</string>
|
||||
<string name="content_description_password_length">Parola uzunluğu</string>
|
||||
<string name="content_description_add_field">Alan ekle</string>
|
||||
<string name="entry_add_field">Alan ekle</string>
|
||||
<string name="content_description_remove_field">Alanı kaldır</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">Buraya bir girişi taşıyamazsınız.</string>
|
||||
@@ -354,7 +353,6 @@
|
||||
<string name="delete_entered_password_summary">Bir bağlantı denemesinden sonra girilen parolayı siler</string>
|
||||
<string name="content_description_node_children">Alt düğüm</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Geçiş şifresi görünürlüğünü tekrarlayın</string>
|
||||
<string name="content_description_entry_save">Girdiyi kaydet</string>
|
||||
<string name="content_description_background">Arka plan</string>
|
||||
<string name="content_description_update_from_list">Güncelleme</string>
|
||||
<string name="content_description_keyboard_close_fields">Alanları kapat</string>
|
||||
@@ -395,8 +393,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">Bu iletişim kutusunu doğrulayarak, KeePassDX sorunu çözecek (tekrarlananlar için yeni UUID\'ler oluşturarak) ve devam edecektir.</string>
|
||||
<string name="database_opened">Veritabanı açıldı</string>
|
||||
<string name="clipboard_explanation_summary">Cihazınızın panosunu kullanarak giriş alanlarını kopyala</string>
|
||||
<string name="persistent_notification_title">Kalıcı bildirim</string>
|
||||
<string name="persistent_notification_summary">Veritabanı açıkken bir bildirim ekle</string>
|
||||
<string name="advanced_unlock_explanation_summary">Veritabanını daha kolay açmak için gelişmiş kilit açma özelliğini kullan</string>
|
||||
<string name="database_data_compression_title">Veri sıkıştırma</string>
|
||||
<string name="database_data_compression_summary">Veri sıkıştırma veritabanı boyutunu azaltır.</string>
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
<string name="error_pass_gen_type">Принаймні один тип генерації пароля необхідно вибрати.</string>
|
||||
<string name="error_pass_match">Паролі не співпадають.</string>
|
||||
<string name="error_rounds_too_large">Надто багато циклів. Установлено 2147483648.</string>
|
||||
<string name="error_title_required">Необхідно вказати заголовок.</string>
|
||||
<string name="error_wrong_length">Введіть ціле число на усю довжину поля</string>
|
||||
<string name="file_browser">Перегляд файлів</string>
|
||||
<string name="generate_password">Згенерувати пароль</string>
|
||||
|
||||
@@ -22,10 +22,14 @@
|
||||
<style name="KeepassDXStyle.Light" parent="KeepassDXStyle.Light.v21" >
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
|
||||
<item name="android:timePickerDialogTheme">@style/KeepassDXStyle.Light.DateTime.Dialog</item>
|
||||
<item name="android:datePickerDialogTheme">@style/KeepassDXStyle.Light.DateTime.Dialog</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.Night" parent="KeepassDXStyle.Night.v21" >
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
|
||||
<item name="android:timePickerDialogTheme">@style/KeepassDXStyle.Night.DateTime.Dialog</item>
|
||||
<item name="android:datePickerDialogTheme">@style/KeepassDXStyle.Night.DateTime.Dialog</item>
|
||||
</style>
|
||||
|
||||
<!-- Button Style -->
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
<string name="decrypting_db">正在解密数据库内容…</string>
|
||||
<string name="default_checkbox">设为默认数据库</string>
|
||||
<string name="digits">数字</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d 是Kunzisoft的一个<strong>开源<strong>和<strong>无广告<strong>软件。
|
||||
\n它是根据<strong>GPLv3 <strong>许可证分发的,您可在遵循GPL 3或者更高版本的协议下重新发布。对软件的质量和性能等问题不提供任何形式的担保。</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d 是Kunzisoft的一个<strong>开源</strong>和<strong>无广告</strong>软件。
|
||||
\n它是根据<strong>GPLv3</strong>许可证分发的,您可在遵循GPL 3或者更高版本的协议下重新发布。Kunzisoft对软件的质量和性能等问题不提供任何形式的担保。</string>
|
||||
<string name="select_database_file">打开已有数据库</string>
|
||||
<string name="entry_accessed">访问时间</string>
|
||||
<string name="entry_cancel">取消</string>
|
||||
@@ -66,7 +66,6 @@
|
||||
<string name="error_pass_gen_type">必须至少选择一种密码生成类型。</string>
|
||||
<string name="error_pass_match">密码不匹配。</string>
|
||||
<string name="error_rounds_too_large">“变换次数”过多。已设置为2147483648。</string>
|
||||
<string name="error_title_required">请添加标题。</string>
|
||||
<string name="error_wrong_length">请在“长度”字段输入正整数。</string>
|
||||
<string name="file_browser">文件浏览器</string>
|
||||
<string name="generate_password">生成密码</string>
|
||||
@@ -332,7 +331,7 @@
|
||||
<string name="education_sort_summary">选择条目和群组的排序方式。</string>
|
||||
<string name="education_donation_title">参与开发</string>
|
||||
<string name="education_donation_summary">帮助增加稳定性,安全性并添加更多的功能。</string>
|
||||
<string name="html_text_ad_free">不同于大多数的密码管理程序,无论您是使用免费版本还是付费版本的KeePassDX,这都是一款<strong>没有广告<strong>,<strong>基于copylefted版权协议的免费软件<strong>,同样的本软件的任何版本也不会收集您的个人信息。</string>
|
||||
<string name="html_text_ad_free">不同于大多数的密码管理程序,无论您是使用免费版本还是付费版本的KeePassDX,这都是一款<strong>没有广告</strong>,<strong>基于copylefted版权协议的免费软件</strong>,同样的本软件的任何版本也不会收集您的个人信息。</string>
|
||||
<string name="html_text_buy_pro">通过购买高级版本,您将解锁全部<strong>主题样式</strong>,重要的是,您会为<strong>社区项目的进行</strong>提供的帮助</string>
|
||||
<string name="html_text_feature_generosity">此<strong>主题样式</strong>现在已经可用,感谢慷慨相助。</string>
|
||||
<string name="html_text_donation">为继续建设此自由项目,我们需要<strong>捐助。</strong></string>
|
||||
@@ -364,10 +363,9 @@
|
||||
<string name="content_description_keyfile_checkbox">密钥文件选框</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">重复切换密码可见性</string>
|
||||
<string name="content_description_entry_icon">条目图标</string>
|
||||
<string name="content_description_entry_save">保存条目</string>
|
||||
<string name="content_description_password_generator">密码生成器</string>
|
||||
<string name="entry_password_generator">密码生成器</string>
|
||||
<string name="content_description_password_length">密码长度</string>
|
||||
<string name="content_description_add_field">添加字段</string>
|
||||
<string name="entry_add_field">添加字段</string>
|
||||
<string name="content_description_remove_field">删除字段</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">无法移动条目到此处。</string>
|
||||
@@ -414,8 +412,6 @@
|
||||
<string name="contains_duplicate_uuid_procedure">通过验证此对话框,KeePassDX将解决这个问题(通过给重复项生成新的UUID)并继续。</string>
|
||||
<string name="database_opened">数据库开启</string>
|
||||
<string name="clipboard_explanation_summary">使用设备的剪贴板来复制输入字段</string>
|
||||
<string name="persistent_notification_title">持久通知</string>
|
||||
<string name="persistent_notification_summary">当数据库打开时产生一条通知</string>
|
||||
<string name="advanced_unlock_explanation_summary">使用高级解锁轻松打开数据库</string>
|
||||
<string name="database_data_compression_title">数据压缩</string>
|
||||
<string name="database_data_compression_summary">数据压缩可降低数据库大小。</string>
|
||||
@@ -452,14 +448,14 @@
|
||||
<string name="keyboard_auto_go_action_summary">填入用户名或密码后直接登录</string>
|
||||
<string name="download_attachment">下载%1$s</string>
|
||||
<string name="download_initialization">正在初始化…</string>
|
||||
<string name="download_progression">进行中:%1$d%</string>
|
||||
<string name="download_progression">进行中:%1$d%</string>
|
||||
<string name="download_finalization">正在完成…</string>
|
||||
<string name="download_complete">完成!点击打开文件。</string>
|
||||
<string name="hide_expired_entries_title">隐藏过期条目</string>
|
||||
<string name="hide_expired_entries_summary">过期条目将被隐藏</string>
|
||||
<string name="contact">联系我们</string>
|
||||
<string name="contribution">贡献</string>
|
||||
<string name="html_about_contribution">为了<strong>保持我们的自由<strong>,<strong>修复错误<strong>,<strong>添加功能<strong>和<strong>始终保持活跃<strong>,我们期待您的 <strong>贡献。<strong></string>
|
||||
<string name="html_about_contribution">为了<strong>保持我们的自由</strong>,<strong>修复错误</strong>,<strong>添加功能</strong>和<strong>始终保持活跃</strong>,我们期待您的 <strong>贡献</strong>。</string>
|
||||
<string name="auto_focus_search_title">快速搜索</string>
|
||||
<string name="auto_focus_search_summary">打开数据库时询问是否进行搜索</string>
|
||||
<string name="remember_database_locations_title">数据库保存的路径</string>
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
<string name="error_pass_gen_type">必須至少選擇一個密碼生成類型。</string>
|
||||
<string name="error_pass_match">密碼不正確。</string>
|
||||
<string name="error_rounds_too_large">次數太多。最大設置到2147483648。</string>
|
||||
<string name="error_title_required">添加標題。</string>
|
||||
<string name="error_wrong_length">長度欄位輸入一個正整數</string>
|
||||
<string name="file_browser">檔案管理器</string>
|
||||
<string name="generate_password">生成密碼</string>
|
||||
@@ -167,7 +166,7 @@
|
||||
<string name="key_derivation_function">金鑰推算函數</string>
|
||||
<string name="edit_entry">編輯入口</string>
|
||||
<string name="content_description_open_file">開啟檔案</string>
|
||||
<string name="content_description_password_generator">密碼產生器</string>
|
||||
<string name="entry_password_generator">密碼產生器</string>
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="content_description_background">背景</string>
|
||||
<string name="content_description_update_from_list">更新</string>
|
||||
@@ -186,9 +185,8 @@
|
||||
<string name="content_description_keyfile_checkbox">金鑰檔案核取方塊</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">重複切換密碼可見性</string>
|
||||
<string name="content_description_entry_icon">條目圖示</string>
|
||||
<string name="content_description_entry_save">條目保存</string>
|
||||
<string name="content_description_password_length">密碼長度</string>
|
||||
<string name="content_description_add_field">添加欄位</string>
|
||||
<string name="entry_add_field">添加欄位</string>
|
||||
<string name="content_description_remove_field">刪除欄位</string>
|
||||
<string name="master_key">主密鑰</string>
|
||||
<string name="menu_master_key_settings">主密鑰設定</string>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<dimen name="image_button_margin">8dp</dimen>
|
||||
<dimen name="image_list_margin">12dp</dimen>
|
||||
<dimen name="button_margin">6dp</dimen>
|
||||
<dimen name="card_view_margin">12dp</dimen>
|
||||
|
||||
<dimen name="icon_size">32dp</dimen>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user