Merge branch 'feature/EmptyPassword' into develop #2

This commit is contained in:
J-Jamet
2017-12-08 20:02:36 +01:00
57 changed files with 1651 additions and 789 deletions

View File

@@ -4,13 +4,14 @@
### Features
- Create database file / entries and groups
- Simplified creation of the database file
- Create entries and groups
- Open database, copy username / password, open URI / URL
- Fingerprint for fast unlocking
- Material design with themes
- Device integration and AutoFill (In progress)
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen0.jpg" width="220">
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen1.jpg" width="220">
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen2.jpg" width="220">
## What is KeePass?

View File

@@ -63,8 +63,10 @@ dependencies {
compile "com.android.support:design:$supportVersion"
compile "com.android.support:preference-v7:$supportVersion"
compile "com.android.support:preference-v14:$supportVersion"
compile "com.android.support:cardview-v7:$supportVersion"
compile "com.madgag.spongycastle:core:$spongycastleVersion"
compile "com.madgag.spongycastle:prov:$spongycastleVersion"
compile "joda-time:joda-time:2.9.9"
compile "org.sufficientlysecure:html-textview:3.5"
compile "com.nononsenseapps:filepicker:4.1.0"
}

View File

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kunzisoft.keepass"
android:installLocation="auto">
xmlns:tools="http://schemas.android.com/tools"
package="com.kunzisoft.keepass"
android:installLocation="auto">
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
@@ -19,10 +20,31 @@
android:allowBackup="true"
android:fullBackupContent="@xml/backup"
android:backupAgent="com.keepassdroid.backup.SettingsBackupAgent"
android:theme="@style/KeepassDXStyle.Light">
android:theme="@style/KeepassDXStyle.Light"
tools:replace="android:theme">
<!-- TODO backup API Key -->
<meta-data android:name="com.google.android.backup.api_key"
android:value="" />
<!-- Folder picker -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/nnf_provider_paths" />
</provider>
<activity
android:name="com.keepassdroid.FilePickerStylishActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".KeePass"
android:label="@string/app_name">
<intent-filter>

View File

@@ -0,0 +1,274 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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 2 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.Toast;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.UriUtil;
import com.keepassdroid.view.KeyFileHelper;
import com.kunzisoft.keepass.R;
public class AssignMasterKeyDialog extends DialogFragment {
private String masterPassword;
private Uri mKeyfile;
private View rootView;
private CompoundButton passwordCheckBox;
private TextView passView;
private TextView passConfView;
private CompoundButton keyfileCheckBox;
private TextView keyfileView;
private AssignPasswordDialogListener mListener;
private KeyFileHelper keyFileHelper;
public interface AssignPasswordDialogListener {
void onAssignKeyDialogPositiveClick(boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile);
void onAssignKeyDialogNegativeClick(boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile);
}
@Override
public void onAttach(Context activity) {
super.onAttach(activity);
try {
mListener = (AssignPasswordDialogListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement " + AssignPasswordDialogListener.class.getName());
}
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
rootView = inflater.inflate(R.layout.set_password, null);
builder.setView(rootView)
.setTitle(R.string.assign_master_key)
// Add action buttons
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
passwordCheckBox = (CompoundButton) rootView.findViewById(R.id.password_checkbox);
passView = (TextView) rootView.findViewById(R.id.pass_password);
passView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable editable) {
passwordCheckBox.setChecked(true);
}
});
passConfView = (TextView) rootView.findViewById(R.id.pass_conf_password);
keyfileCheckBox = (CompoundButton) rootView.findViewById(R.id.keyfile_checkox);
keyfileView = (TextView) rootView.findViewById(R.id.pass_keyfile);
keyfileView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable editable) {
keyfileCheckBox.setChecked(true);
}
});
keyFileHelper = new KeyFileHelper(this);
rootView.findViewById(R.id.browse_button)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
keyFileHelper.getOpenFileOnClickViewListener().onClick(view);
}
});
AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(final DialogInterface dialog) {
Button positiveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
masterPassword = "";
mKeyfile = null;
boolean error = verifyPassword() || verifyFile();
if (!passwordCheckBox.isChecked() && !keyfileCheckBox.isChecked()) {
error = true;
showNoKeyConfirmationDialog();
}
if (!error) {
mListener.onAssignKeyDialogPositiveClick(
passwordCheckBox.isChecked(), masterPassword,
keyfileCheckBox.isChecked(), mKeyfile);
dismiss();
}
}
});
Button negativeButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_NEGATIVE);
negativeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
mListener.onAssignKeyDialogNegativeClick(
passwordCheckBox.isChecked(), masterPassword,
keyfileCheckBox.isChecked(), mKeyfile);
dismiss();
}
});
}
});
return dialog;
}
private boolean verifyPassword() {
boolean error = false;
if (passwordCheckBox.isChecked()) {
masterPassword = passView.getText().toString();
String confpass = passConfView.getText().toString();
// Verify that passwords match
if (!masterPassword.equals(confpass)) {
error = true;
// Passwords do not match
Toast.makeText(getContext(), R.string.error_pass_match, Toast.LENGTH_LONG).show();
}
if (masterPassword == null || masterPassword.isEmpty()) {
error = true;
showEmptyPasswordConfirmationDialog();
}
}
return error;
}
private boolean verifyFile() {
boolean error = false;
if (keyfileCheckBox.isChecked()) {
Uri keyfile = UriUtil.parseDefaultFile(keyfileView.getText().toString());
mKeyfile = keyfile;
// Verify that a keyfile is set
if (EmptyUtils.isNullOrEmpty(keyfile)) {
error = true;
Toast.makeText(getContext(), R.string.error_nokeyfile, Toast.LENGTH_LONG).show();
}
}
return error;
}
private void showEmptyPasswordConfirmationDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.warning_empty_password)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if (!verifyFile()) {
mListener.onAssignKeyDialogPositiveClick(
passwordCheckBox.isChecked(), masterPassword,
keyfileCheckBox.isChecked(), mKeyfile);
AssignMasterKeyDialog.this.dismiss();
}
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {}
});
builder.create().show();
}
private void showNoKeyConfirmationDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.warning_no_encryption_key)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mListener.onAssignKeyDialogPositiveClick(
passwordCheckBox.isChecked(), masterPassword,
keyfileCheckBox.isChecked(), mKeyfile);
AssignMasterKeyDialog.this.dismiss();
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {}
});
builder.create().show();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
new KeyFileHelper.KeyFileCallback() {
@Override
public void onKeyFileResultCallback(Uri uri) {
if(uri != null) {
Uri pathString = UriUtil.parseDefaultFile(uri.toString());
if (pathString != null) {
keyfileCheckBox.setChecked(true);
keyfileView.setText(pathString.toString());
}
}
}
});
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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 2 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.app.Dialog;
import android.content.Context;
public class CancelDialog extends Dialog {
private boolean mCanceled = false;
public CancelDialog(Context context) {
super(context);
}
public boolean canceled() {
return mCanceled;
}
@Override
public void cancel() {
super.cancel();
mCanceled = true;
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright 2017 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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 2 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import com.keepassdroid.utils.UriUtil;
import com.kunzisoft.keepass.R;
import com.nononsenseapps.filepicker.FilePickerActivity;
import com.nononsenseapps.filepicker.Utils;
import java.io.File;
public class CreateFileDialog extends DialogFragment implements AdapterView.OnItemSelectedListener{
private final int FILE_CODE = 3853;
private EditText folderPathView;
private EditText fileNameView;
private DefinePathDialogListener mListener;
private String extension;
private Uri uriPath;
public interface DefinePathDialogListener {
boolean onDefinePathDialogPositiveClick(Uri pathFile);
boolean onDefinePathDialogNegativeClick(Uri pathFile);
}
@Override
public void onAttach(Context activity) {
super.onAttach(activity);
try {
mListener = (DefinePathDialogListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement " + DefinePathDialogListener.class.getName());
}
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View rootView = inflater.inflate(R.layout.file_creation, null);
builder.setView(rootView)
.setTitle(R.string.create_keepass_file)
// Add action buttons
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {}
});
// Folder selection
View browseView = rootView.findViewById(R.id.browse_button);
folderPathView = (EditText) rootView.findViewById(R.id.folder_path);
fileNameView = (EditText) rootView.findViewById(R.id.filename);
String defaultPath = Environment.getExternalStorageDirectory().getPath()
+ getString(R.string.database_file_path_default);
folderPathView.setText(defaultPath);
browseView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(getContext(), FilePickerStylishActivity.class);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true);
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
Environment.getExternalStorageDirectory().getPath());
startActivityForResult(i, FILE_CODE);
}
});
// Init path
uriPath = null;
// Extension
extension = getString(R.string.database_file_extension_default);
Spinner spinner = (Spinner) rootView.findViewById(R.id.file_types);
spinner.setOnItemSelectedListener(this);
// Spinner Drop down elements
String[] fileTypes = getResources().getStringArray(R.array.file_types);
ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, fileTypes);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(dataAdapter);
AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(final DialogInterface dialog) {
Button positiveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
if(mListener.onDefinePathDialogPositiveClick(buildPath()))
CreateFileDialog.this.dismiss();
}
});
Button negativeButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_NEGATIVE);
negativeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
if(mListener.onDefinePathDialogNegativeClick(buildPath()))
CreateFileDialog.this.dismiss();
}
});
}
});
return dialog;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FILE_CODE && resultCode == Activity.RESULT_OK) {
uriPath = data.getData();
if (uriPath != null) {
File file = Utils.getFileForUri(uriPath);
folderPathView.setText(file.getPath());
}
}
}
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
extension = adapterView.getItemAtPosition(position).toString();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
// Do nothing
}
private Uri buildPath() {
Uri path = new Uri.Builder().path(folderPathView.getText().toString())
.appendPath(fileNameView.getText().toString() + extension)
.build();
path = UriUtil.translate(getContext(), path);
return path;
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2017 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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 2 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.util.Log;
import com.keepassdroid.stylish.Stylish;
import com.kunzisoft.keepass.R;
import com.nononsenseapps.filepicker.FilePickerActivity;
public class FilePickerStylishActivity extends FilePickerActivity {
private @StyleRes
int themeId;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
this.themeId = FilePickerStylish.getThemeId(this);
setTheme(themeId);
super.onCreate(savedInstanceState);
}
@Override
protected void onResume() {
super.onResume();
if(FilePickerStylish.getThemeId(this) != this.themeId) {
Log.d(this.getClass().getName(), "Theme change detected, restarting activity");
this.recreate();
}
}
public static class FilePickerStylish extends Stylish {
public static @StyleRes int getThemeId(Context context) {
if (themeString.equals(context.getString(R.string.list_style_name_night)))
return R.style.KeepassDXStyle_FilePickerStyle_Night;
return R.style.KeepassDXStyle_FilePickerStyle_Light;
}
}
}

View File

@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
@@ -40,8 +41,6 @@ import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.ActivityCompat;
import com.keepassdroid.compat.EditorCompat;
@@ -49,10 +48,14 @@ import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.search.SearchResultsActivity;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.view.AssignPasswordHelper;
import com.keepassdroid.view.ClickView;
import com.keepassdroid.view.GroupViewOnlyView;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
public abstract class GroupBaseActivity extends LockCloseListActivity {
public abstract class GroupBaseActivity extends LockCloseListActivity
implements AssignMasterKeyDialog.AssignPasswordDialogListener {
protected ListView mList;
protected ListAdapter mAdapter;
@@ -265,8 +268,26 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
}
@Override
public void onAssignKeyDialogPositiveClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
AssignPasswordHelper assignPasswordHelper =
new AssignPasswordHelper(this,
masterPassword, keyFile);
assignPasswordHelper.assignPasswordInDatabase(null);
}
@Override
public void onAssignKeyDialogNegativeClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
}
private void setPassword() {
SetPasswordDialog dialog = new SetPasswordDialog();
AssignMasterKeyDialog dialog = new AssignMasterKeyDialog();
dialog.show(getSupportFragmentManager(), "passwordDialog");
}

View File

@@ -20,7 +20,6 @@
package com.keepassdroid;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -52,21 +51,18 @@ import com.keepassdroid.app.App;
import com.keepassdroid.compat.BackupManagerCompat;
import com.keepassdroid.compat.ClipDataCompat;
import com.keepassdroid.compat.EditorCompat;
import com.keepassdroid.compat.StorageAF;
import com.keepassdroid.database.edit.LoadDB;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.dialog.PasswordEncodingDialogHelper;
import com.keepassdroid.fileselect.BrowserDialog;
import com.keepassdroid.fingerprint.FingerPrintAnimatedVector;
import com.keepassdroid.fingerprint.FingerPrintHelper;
import com.keepassdroid.intents.Intents;
import com.keepassdroid.settings.PrefsUtil;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.Interaction;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.utils.UriUtil;
import com.keepassdroid.utils.Util;
import com.keepassdroid.view.FingerPrintDialog;
import com.keepassdroid.view.KeyFileHelper;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
@@ -84,10 +80,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private static final String KEY_LAUNCH_IMMEDIATELY = "launchImmediately";
private static final String VIEW_INTENT = "android.intent.action.VIEW";
private static final int FILE_BROWSE = 256;
public static final int GET_CONTENT = 257;
private static final int OPEN_DOC = 258;
private Uri mDbUri = null;
private Uri mKeyUri = null;
private boolean mRememberKeyfile;
@@ -100,12 +92,19 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private int mode;
private static final String PREF_KEY_VALUE_PREFIX = "valueFor_"; // key is a combination of db file name and this prefix
private static final String PREF_KEY_IV_PREFIX = "ivFor_"; // key is a combination of db file name and this prefix
private View fingerprintContainerView;
private View fingerprintImageView;
private FingerPrintAnimatedVector fingerPrintAnimatedVector;
private TextView fingerprintTextView;
private TextView filenameView;
private EditText passwordView;
private Button confirmButton;
private EditText keyFileView;
private Button confirmButtonView;
private CheckBox checkboxPasswordView;
private CheckBox checkboxKeyfileView;
private KeyFileHelper keyFileHelper;
public static void Launch(
Activity act,
@@ -122,6 +121,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
}
Uri uri = UriUtil.parseDefaultFile(fileName);
assert uri != null;
String scheme = uri.getScheme();
if (!EmptyUtils.isNullOrEmpty(scheme) && scheme.equalsIgnoreCase("file")) {
@@ -146,49 +146,30 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
new KeyFileHelper.KeyFileCallback() {
@Override
public void onKeyFileResultCallback(Uri uri) {
if(uri != null) {
keyFileView.setText(uri.toString());
}
}
});
switch (requestCode) {
case KeePass.EXIT_NORMAL:
setEditText(R.id.password, "");
setEmptyViews();
App.getDB().clear();
break;
case KeePass.EXIT_LOCK:
setResult(KeePass.EXIT_LOCK);
setEditText(R.id.password, "");
setEmptyViews();
finish();
App.getDB().clear();
break;
case FILE_BROWSE:
if (resultCode == RESULT_OK) {
String filename = data.getDataString();
if (filename != null) {
EditText fn = (EditText) findViewById(R.id.pass_keyfile);
fn.setText(filename);
mKeyUri = UriUtil.parseDefaultFile(filename);
}
}
break;
case GET_CONTENT:
case OPEN_DOC:
if (resultCode == RESULT_OK) {
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
if (requestCode == GET_CONTENT) {
uri = UriUtil.translate(this, uri);
}
String path = uri.toString();
if (path != null) {
EditText fn = (EditText) findViewById(R.id.pass_keyfile);
fn.setText(path);
}
mKeyUri = uri;
}
}
}
break;
}
}
@Override
@@ -210,11 +191,40 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
confirmButton = (Button) findViewById(R.id.pass_ok);
confirmButtonView = (Button) findViewById(R.id.pass_ok);
fingerprintContainerView = findViewById(R.id.fingerprint_container);
fingerprintImageView = findViewById(R.id.fingerprint_image);
fingerprintTextView = (TextView) findViewById(R.id.fingerprint_label);
filenameView = (TextView) findViewById(R.id.filename);
passwordView = (EditText) findViewById(R.id.password);
keyFileView = (EditText) findViewById(R.id.pass_keyfile);
checkboxPasswordView = (CheckBox) findViewById(R.id.password_checkbox);
checkboxKeyfileView = (CheckBox) findViewById(R.id.keyfile_checkox);
passwordView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable editable) {
checkboxPasswordView.setChecked(true);
}
});
keyFileView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable editable) {
checkboxKeyfileView.setChecked(true);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fingerPrintAnimatedVector = new FingerPrintAnimatedVector(this,
@@ -231,8 +241,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
// If the application was shutdown make sure to clear the password field, if it
// was saved in the instance state
if (App.isShutdown()) {
TextView password = (TextView) findViewById(R.id.password);
password.setText("");
setEmptyViews();
}
// Clear the shutdown flag
@@ -248,10 +257,17 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
}
}
private void setEmptyViews() {
passwordView.setText("");
keyFileView.setText("");
checkboxPasswordView.setChecked(false);
checkboxKeyfileView.setChecked(false);
}
private void retrieveSettings() {
String defaultFilename = prefs.getString(KEY_DEFAULT_FILENAME, "");
if (!EmptyUtils.isNullOrEmpty(mDbUri.getPath()) && UriUtil.equalsDefaultfile(mDbUri, defaultFilename)) {
CheckBox checkbox = (CheckBox) findViewById(R.id.default_database);
CompoundButton checkbox = (CompoundButton) findViewById(R.id.default_database);
checkbox.setChecked(true);
}
}
@@ -266,14 +282,12 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private void populateView() {
String db = (mDbUri == null) ? "" : mDbUri.toString();
setEditText(R.id.filename, db);
if (!db.isEmpty())
filenameView.setText(db);
String key = (mKeyUri == null) ? "" : mKeyUri.toString();
setEditText(R.id.pass_keyfile, key);
}
private void errorMessage(int resId) {
Toast.makeText(this, resId, Toast.LENGTH_LONG).show();
if (!key.isEmpty())
keyFileView.setText(key);
}
// fingerprint related code here
@@ -456,7 +470,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
.putString(getPreferenceKeyIvSpec(), ivSpec)
.apply();
// and remove visual input to reset UI
confirmButton.performClick();
confirmButtonView.performClick();
fingerprintTextView.setText(R.string.encrypted_value_stored);
}
@@ -464,7 +478,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
public void handleDecryptedResult(final String value) {
// on decrypt enter it for the purchase/login action
passwordView.setText(value);
confirmButton.performClick();
confirmButtonView.performClick();
}
@RequiresApi(api = Build.VERSION_CODES.M)
@@ -511,8 +525,8 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private class OkClickHandler implements View.OnClickListener {
public void onClick(View view) {
String pass = getEditText(R.id.password);
String key = getEditText(R.id.pass_keyfile);
String pass = passwordView.getText().toString();
String key = keyFileView.getText().toString();
loadDatabase(pass, key);
}
}
@@ -526,10 +540,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private void loadDatabase(
String pass,
Uri keyfile) {
if (pass.length() == 0 && (keyfile == null || keyfile.toString().length() == 0)) {
errorMessage(R.string.error_nopass);
return;
}
// Clear before we load
Database db = App.getDB();
@@ -538,6 +548,13 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
// Clear the shutdown flag
App.clearShutdown();
if (!checkboxPasswordView.isChecked()) {
pass = "";
}
if (!checkboxKeyfileView.isChecked()) {
keyfile = null;
}
Handler handler = new Handler();
LoadDB task = new LoadDB(db, PasswordActivity.this, mDbUri, pass, keyfile, new AfterLoad(handler, db));
ProgressTask pt = new ProgressTask(PasswordActivity.this, task, R.string.loading_database);
@@ -548,15 +565,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
return Util.getEditText(this, resId);
}
private void setEditText(
int resId,
String str) {
TextView te = (TextView) findViewById(resId);
if (te != null) {
te.setText(str);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@@ -583,7 +591,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private Database db;
public AfterLoad(
AfterLoad(
Handler handler,
Database db) {
super(handler);
@@ -683,69 +691,15 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
confirmButton.setOnClickListener(new OkClickHandler());
if (password != null) {
TextView tv_password = (TextView) findViewById(R.id.password);
tv_password.setText(password);
passwordView.setText(password);
}
CheckBox defaultCheck = (CheckBox) findViewById(R.id.default_database);
CompoundButton defaultCheck = (CompoundButton) findViewById(R.id.default_database);
defaultCheck.setOnCheckedChangeListener(new DefaultCheckChange());
View browse = findViewById(R.id.browse_button);
browse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (StorageAF.useStorageFramework(PasswordActivity.this)) {
Intent i = new Intent(StorageAF.ACTION_OPEN_DOCUMENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
startActivityForResult(i, OPEN_DOC);
} else {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
try {
startActivityForResult(i, GET_CONTENT);
} catch (ActivityNotFoundException e) {
lookForOpenIntentsFilePicker();
}
}
}
private void lookForOpenIntentsFilePicker() {
if (Interaction.isIntentAvailable(PasswordActivity.this, Intents.OPEN_INTENTS_FILE_BROWSE)) {
Intent i = new Intent(Intents.OPEN_INTENTS_FILE_BROWSE);
// Get file path parent if possible
try {
if (mDbUri != null && mDbUri.toString().length() > 0) {
if (mDbUri.getScheme().equals("file")) {
File keyfile = new File(mDbUri.getPath());
File parent = keyfile.getParentFile();
if (parent != null) {
i.setData(Uri.parse("file://" + parent.getAbsolutePath()));
}
}
}
} catch (Exception e) {
// Ignore
}
try {
startActivityForResult(i, FILE_BROWSE);
} catch (ActivityNotFoundException e) {
showBrowserDialog();
}
} else {
showBrowserDialog();
}
}
private void showBrowserDialog() {
BrowserDialog browserDialog = new BrowserDialog(PasswordActivity.this);
browserDialog.show();
}
});
View browseView = findViewById(R.id.browse_button);
keyFileHelper = new KeyFileHelper(PasswordActivity.this);
browseView.setOnClickListener(keyFileHelper.getOpenFileOnClickViewListener());
retrieveSettings();

View File

@@ -1,156 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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 2 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.app.Dialog;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.database.edit.FileOnFinish;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.SetPassword;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.UriUtil;
public class SetPasswordDialog extends DialogFragment {
private final static String FINISH_TAG = "FINISH_TAG";
private byte[] masterKey;
private Uri mKeyfile;
private FileOnFinish mFinish;
private View rootView;
public byte[] getKey() {
return masterKey;
}
public Uri keyfile() {
return mKeyfile;
}
public static SetPasswordDialog newInstance(FileOnFinish finish) {
SetPasswordDialog setPasswordDialog = new SetPasswordDialog();
Bundle args = new Bundle();
args.putSerializable(FINISH_TAG, finish);
setPasswordDialog.setArguments(args);
return setPasswordDialog;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
if(getArguments() != null && getArguments().containsKey(FINISH_TAG)) {
mFinish = (FileOnFinish) getArguments().getSerializable(FINISH_TAG);
}
rootView = inflater.inflate(R.layout.set_password, null);
builder.setView(rootView)
// Add action buttons
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
TextView passView = (TextView) rootView.findViewById(R.id.pass_password);
String pass = passView.getText().toString();
TextView passConfView = (TextView) rootView.findViewById(R.id.pass_conf_password);
String confpass = passConfView.getText().toString();
// Verify that passwords match
if ( ! pass.equals(confpass) ) {
// Passwords do not match
Toast.makeText(getContext(), R.string.error_pass_match, Toast.LENGTH_LONG).show();
return;
}
TextView keyfileView = (TextView) rootView.findViewById(R.id.pass_keyfile);
Uri keyfile = UriUtil.parseDefaultFile(keyfileView.getText().toString());
mKeyfile = keyfile;
// Verify that a password or keyfile is set
if ( pass.length() == 0 && EmptyUtils.isNullOrEmpty(keyfile)) {
Toast.makeText(getContext(), R.string.error_nopass, Toast.LENGTH_LONG).show();
return;
}
SetPassword sp = new SetPassword(getContext(), App.getDB(), pass, keyfile, new AfterSave(mFinish, new Handler()));
final ProgressTask pt = new ProgressTask(getContext(), sp, R.string.saving_database);
boolean valid = sp.validatePassword(getContext(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
pt.run();
}
});
if (valid) {
pt.run();
}
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
SetPasswordDialog.this.getDialog().cancel();
if ( mFinish != null ) {
mFinish.run();
}
}
});
return builder.create();
}
private class AfterSave extends OnFinish {
private FileOnFinish mFinish;
public AfterSave(FileOnFinish finish, Handler handler) {
super(finish, handler);
mFinish = finish;
}
@Override
public void run() {
if ( mSuccess ) {
if ( mFinish != null ) {
mFinish.setFilename(mKeyfile);
}
dismiss();
} else {
displayMessage(getContext());
}
super.run();
}
}
}

View File

@@ -19,12 +19,29 @@
*/
package com.keepassdroid.database;
import java.io.FileInputStream;
import android.webkit.URLUtil;
import com.keepassdroid.collections.VariantDictionary;
import com.keepassdroid.crypto.CryptoUtil;
import com.keepassdroid.crypto.engine.AesEngine;
import com.keepassdroid.crypto.engine.CipherEngine;
import com.keepassdroid.crypto.keyDerivation.AesKdf;
import com.keepassdroid.crypto.keyDerivation.KdfEngine;
import com.keepassdroid.crypto.keyDerivation.KdfFactory;
import com.keepassdroid.crypto.keyDerivation.KdfParameters;
import com.keepassdroid.database.exception.InvalidKeyFileException;
import com.keepassdroid.utils.EmptyUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@@ -36,29 +53,8 @@ import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.spongycastle.crypto.engines.AESEngine;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import android.webkit.URLUtil;
import biz.source_code.base64Coder.Base64Coder;
import com.keepassdroid.collections.VariantDictionary;
import com.keepassdroid.crypto.CipherFactory;
import com.keepassdroid.crypto.CryptoUtil;
import com.keepassdroid.crypto.PwStreamCipherFactory;
import com.keepassdroid.crypto.engine.AesEngine;
import com.keepassdroid.crypto.engine.CipherEngine;
import com.keepassdroid.crypto.keyDerivation.AesKdf;
import com.keepassdroid.crypto.keyDerivation.KdfEngine;
import com.keepassdroid.crypto.keyDerivation.KdfFactory;
import com.keepassdroid.crypto.keyDerivation.KdfParameters;
import com.keepassdroid.database.exception.InvalidKeyFileException;
import com.keepassdroid.utils.EmptyUtils;
public class PwDatabaseV4 extends PwDatabase {
@@ -131,7 +127,7 @@ public class PwDatabaseV4 extends PwDatabase {
throws InvalidKeyFileException, IOException {
assert(key != null);
byte[] fKey;
byte[] fKey = new byte[]{};
if ( key.length() > 0 && keyInputStream != null) {
return getCompositeKey(key, keyInputStream);
@@ -139,8 +135,6 @@ public class PwDatabaseV4 extends PwDatabase {
fKey = getPasswordKey(key);
} else if ( keyInputStream != null) {
fKey = getFileKey(keyInputStream);
} else {
throw new IllegalArgumentException( "Key cannot be empty." );
}
MessageDigest md;

View File

@@ -19,20 +19,14 @@
*/
package com.keepassdroid.database.edit;
import android.content.Context;
import android.net.Uri;
import com.keepassdroid.Database;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwEncryptionAlgorithm;
import com.keepassdroid.utils.UriUtil;
public class CreateDB extends RunnableOnFinish {
private final int DEFAULT_ENCRYPTION_ROUNDS = 300;
private String mFilename;
private boolean mDontSave;
@@ -57,7 +51,6 @@ public class CreateDB extends RunnableOnFinish {
// Set Database state
db.pm = pm;
Uri.Builder b = new Uri.Builder();
db.mUri = UriUtil.parseDefaultFile(mFilename);
db.setLoaded();
App.clearShutdown();

View File

@@ -19,9 +19,6 @@
*/
package com.keepassdroid.database.edit;
import java.io.IOException;
import java.io.InputStream;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
@@ -32,6 +29,9 @@ import com.keepassdroid.database.exception.InvalidKeyFileException;
import com.keepassdroid.dialog.PasswordEncodingDialogHelper;
import com.keepassdroid.utils.UriUtil;
import java.io.IOException;
import java.io.InputStream;
public class SetPassword extends RunnableOnFinish {
private String mPassword;

View File

@@ -19,8 +19,8 @@
*/
package com.keepassdroid.fileselect;
import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Intent;
@@ -35,6 +35,7 @@ import android.preference.PreferenceManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
@@ -44,18 +45,16 @@ import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.keepassdroid.AssignMasterKeyDialog;
import com.keepassdroid.CreateFileDialog;
import com.keepassdroid.GroupActivity;
import com.keepassdroid.PasswordActivity;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.SetPasswordDialog;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.ContentResolverCompat;
import com.keepassdroid.compat.StorageAF;
@@ -69,18 +68,25 @@ import com.keepassdroid.utils.Interaction;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.utils.UriUtil;
import com.keepassdroid.utils.Util;
import com.keepassdroid.view.AssignPasswordHelper;
import com.keepassdroid.view.FileNameView;
import com.kunzisoft.keepass.R;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URLDecoder;
public class FileSelectActivity extends StylishActivity {
public class FileSelectActivity extends StylishActivity implements
CreateFileDialog.DefinePathDialogListener ,
AssignMasterKeyDialog.AssignPasswordDialogListener {
private static final String TAG = "FileSelectActivity";
private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 111;
private ListView mList;
private ListAdapter mAdapter;
private BaseAdapter mAdapter;
private static final int CMENU_CLEAR = Menu.FIRST;
@@ -92,18 +98,23 @@ public class FileSelectActivity extends StylishActivity {
private boolean recentMode = false;
private EditText openFileNameView;
private AssignPasswordHelper assignPasswordHelper;
private Uri databaseUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fileHistory = App.getFileHistory();
setContentView(R.layout.file_selection);
if (fileHistory.hasRecentFiles()) {
recentMode = true;
setContentView(R.layout.file_selection);
} else {
setContentView(R.layout.file_selection_no_recent);
}
findViewById(R.id.file_listtop).setVisibility(View.INVISIBLE);
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.app_name));
@@ -112,22 +123,20 @@ public class FileSelectActivity extends StylishActivity {
mList = (ListView)findViewById(R.id.file_list);
mList.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
onListItemClick((ListView)parent, v, position, id);
}
}
new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onListItemClick((ListView)parent, v, position, id);
}
}
);
// Open button
Button openButton = (Button) findViewById(R.id.open);
View openButton = findViewById(R.id.open_database);
openButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String fileName = Util.getEditText(FileSelectActivity.this,
R.id.file_filename);
try {
PasswordActivity.Launch(FileSelectActivity.this, fileName);
}
@@ -139,80 +148,16 @@ public class FileSelectActivity extends StylishActivity {
Toast.makeText(FileSelectActivity.this,
R.string.FileNotFound, Toast.LENGTH_LONG).show();
}
}
});
// Create button
Button createButton = (Button) findViewById(R.id.create);
View createButton = findViewById(R.id.create_database);
createButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String filename = Util.getEditText(FileSelectActivity.this,
R.id.file_filename);
// Make sure file name exists
if (filename.length() == 0) {
Toast
.makeText(FileSelectActivity.this,
R.string.error_filename_required,
Toast.LENGTH_LONG).show();
return;
}
// Try to create the file
File file = new File(filename);
try {
if (file.exists()) {
Toast.makeText(FileSelectActivity.this,
R.string.error_database_exists,
Toast.LENGTH_LONG).show();
return;
}
File parent = file.getParentFile();
if ( parent == null || (parent.exists() && ! parent.isDirectory()) ) {
Toast.makeText(FileSelectActivity.this,
R.string.error_invalid_path,
Toast.LENGTH_LONG).show();
return;
}
if ( ! parent.exists() ) {
// Create parent dircetory
if ( ! parent.mkdirs() ) {
Toast.makeText(FileSelectActivity.this,
R.string.error_could_not_create_parent,
Toast.LENGTH_LONG).show();
return;
}
}
file.createNewFile();
} catch (IOException e) {
Toast.makeText(
FileSelectActivity.this,
getText(R.string.error_file_not_create) + " "
+ e.getLocalizedMessage(),
Toast.LENGTH_LONG).show();
return;
}
// Prep an object to collect a password once the database has
// been created
CollectPassword password = new CollectPassword(
new LaunchGroupActivity(filename));
// Create the new database
CreateDB create = new CreateDB(FileSelectActivity.this, filename, password, true);
ProgressTask createTask = new ProgressTask(
FileSelectActivity.this, create,
R.string.progress_create);
createTask.run();
CreateFileDialog createFileDialog = new CreateFileDialog();
createFileDialog.show(getSupportFragmentManager(), "createFileDialog");
}
});
View browseButton = findViewById(R.id.browse_button);
@@ -223,7 +168,9 @@ public class FileSelectActivity extends StylishActivity {
Intent i = new Intent(StorageAF.ACTION_OPEN_DOCUMENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION|
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
startActivityForResult(i, OPEN_DOC);
}
else {
@@ -247,7 +194,6 @@ public class FileSelectActivity extends StylishActivity {
}
private void lookForOpenIntentsFilePicker() {
if (Interaction.isIntentAvailable(FileSelectActivity.this, Intents.OPEN_INTENTS_FILE_BROWSE)) {
Intent i = new Intent(Intents.OPEN_INTENTS_FILE_BROWSE);
i.setData(Uri.parse("file://" + Util.getEditText(FileSelectActivity.this, R.id.file_filename)));
@@ -256,7 +202,6 @@ public class FileSelectActivity extends StylishActivity {
} catch (ActivityNotFoundException e) {
showBrowserDialog();
}
} else {
showBrowserDialog();
}
@@ -268,6 +213,14 @@ public class FileSelectActivity extends StylishActivity {
}
});
// Set the initial value of the filename
openFileNameView = (EditText) findViewById(R.id.file_filename);
String defaultPath = Environment.getExternalStorageDirectory().getAbsolutePath()
+ getString(R.string.database_file_path_default)
+ getString(R.string.database_file_name_default)
+ getString(R.string.database_file_extension_default);
openFileNameView.setText(defaultPath);
fillData();
registerForContextMenu(mList);
@@ -278,7 +231,9 @@ public class FileSelectActivity extends StylishActivity {
if (fileName.length() > 0) {
Uri dbUri = UriUtil.parseDefaultFile(fileName);
String scheme = dbUri.getScheme();
String scheme = null;
if (dbUri!=null)
scheme = dbUri.getScheme();
if (!EmptyUtils.isNullOrEmpty(scheme) && scheme.equalsIgnoreCase("file")) {
String path = dbUri.getPath();
@@ -302,12 +257,135 @@ public class FileSelectActivity extends StylishActivity {
}
}
/**
* Create file for database
* @return If not created, return false
*/
private boolean createDatabaseFile(Uri path) {
String pathString = URLDecoder.decode(path.getPath());
// Make sure file name exists
if (pathString.length() == 0) {
Log.e(TAG, getString(R.string.error_filename_required));
Toast.makeText(FileSelectActivity.this,
R.string.error_filename_required,
Toast.LENGTH_LONG).show();
return false;
}
// Try to create the file
File file = new File(pathString);
try {
if (file.exists()) {
Log.e(TAG, getString(R.string.error_database_exists) + " " + file);
Toast.makeText(FileSelectActivity.this,
R.string.error_database_exists,
Toast.LENGTH_LONG).show();
return false;
}
File parent = file.getParentFile();
if ( parent == null || (parent.exists() && ! parent.isDirectory()) ) {
Log.e(TAG, getString(R.string.error_invalid_path) + " " + file);
Toast.makeText(FileSelectActivity.this,
R.string.error_invalid_path,
Toast.LENGTH_LONG).show();
return false;
}
if ( ! parent.exists() ) {
// Create parent directory
if ( ! parent.mkdirs() ) {
Log.e(TAG, getString(R.string.error_could_not_create_parent) + " " + parent);
Toast.makeText(FileSelectActivity.this,
R.string.error_could_not_create_parent,
Toast.LENGTH_LONG).show();
return false;
}
}
return file.createNewFile();
} catch (IOException e) {
Log.e(TAG, getString(R.string.error_could_not_create_parent) + " " + e.getLocalizedMessage());
e.printStackTrace();
Toast.makeText(
FileSelectActivity.this,
getText(R.string.error_file_not_create) + " "
+ e.getLocalizedMessage(),
Toast.LENGTH_LONG).show();
return false;
}
}
@Override
public boolean onDefinePathDialogPositiveClick(Uri pathFile) {
databaseUri = pathFile;
if(createDatabaseFile(pathFile)) {
AssignMasterKeyDialog assignMasterKeyDialog = new AssignMasterKeyDialog();
assignMasterKeyDialog.show(getSupportFragmentManager(), "passwordDialog");
return true;
} else
return false;
}
@Override
public boolean onDefinePathDialogNegativeClick(Uri pathFile) {
return true;
}
@Override
public void onAssignKeyDialogPositiveClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
String databaseFilename = databaseUri.getPath();
// Prep an object to collect a password once the database has
// been created
FileOnFinish launchActivityOnFinish = new FileOnFinish(
new LaunchGroupActivity(databaseFilename));
AssignPasswordOnFinish assignPasswordOnFinish =
new AssignPasswordOnFinish(launchActivityOnFinish);
// Create the new database
CreateDB create = new CreateDB(FileSelectActivity.this,
databaseFilename, assignPasswordOnFinish, true);
ProgressTask createTask = new ProgressTask(
FileSelectActivity.this, create,
R.string.progress_create);
createTask.run();
assignPasswordHelper =
new AssignPasswordHelper(this,
masterPassword, keyFile);
}
@Override
public void onAssignKeyDialogNegativeClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
}
private class AssignPasswordOnFinish extends FileOnFinish {
AssignPasswordOnFinish(FileOnFinish fileOnFinish) {
super(fileOnFinish);
}
@Override
public void run() {
if (mSuccess) {
assignPasswordHelper.assignPasswordInDatabase(mOnFinish);
}
}
}
private class LaunchGroupActivity extends FileOnFinish {
private Uri mUri;
public LaunchGroupActivity(String filename) {
LaunchGroupActivity(String filename) {
super(null);
mUri = UriUtil.parseDefaultFile(filename);
}
@@ -316,61 +394,19 @@ public class FileSelectActivity extends StylishActivity {
if (mSuccess) {
// Add to recent files
fileHistory.createFile(mUri, getFilename());
mAdapter.notifyDataSetChanged();
GroupActivity.Launch(FileSelectActivity.this);
}
}
}
private class CollectPassword extends FileOnFinish {
public CollectPassword(FileOnFinish finish) {
super(finish);
}
@Override
public void run() {
SetPasswordDialog dialog = SetPasswordDialog.newInstance(mOnFinish);
dialog.show(getSupportFragmentManager(), "passwordDialog");
}
}
private void fillData() {
// Set the initial value of the filename
EditText filename = (EditText) findViewById(R.id.file_filename);
filename.setText(Environment.getExternalStorageDirectory().getAbsolutePath() + getString(R.string.default_file_path));
mAdapter = new ArrayAdapter<String>(this, R.layout.file_row, R.id.file_filename, fileHistory.getDbList());
mList.setAdapter(mAdapter);
mAdapter = new ArrayAdapter<>(FileSelectActivity.this, R.layout.file_row, R.id.file_filename, fileHistory.getDbList());
mList.setAdapter(mAdapter);
}
protected void onListItemClick(ListView l, View v, int position, long id) {
new AsyncTask<Integer, Void, Void>() {
String fileName;
String keyFile;
protected Void doInBackground(Integer... args) {
int position = args[0];
fileName = fileHistory.getDatabaseAt(position);
keyFile = fileHistory.getKeyfileAt(position);
return null;
}
protected void onPostExecute(Void v) {
try {
PasswordActivity.Launch(FileSelectActivity.this, fileName, keyFile);
}
catch (ContentFileNotFoundException e) {
Toast.makeText(FileSelectActivity.this, R.string.file_not_found_content, Toast.LENGTH_LONG)
.show();
}
catch (FileNotFoundException e) {
Toast.makeText(FileSelectActivity.this, R.string.FileNotFound, Toast.LENGTH_LONG)
.show();
}
}
}.execute(position);
new OpenFileHistoryAsyncTask(this, fileHistory).execute(position);
}
@Override
@@ -414,8 +450,7 @@ public class FileSelectActivity extends StylishActivity {
}
if (filename != null) {
EditText fn = (EditText) findViewById(R.id.file_filename);
fn.setText(filename);
openFileNameView.setText(filename);
}
}
@@ -522,25 +557,65 @@ public class FileSelectActivity extends StylishActivity {
TextView tv = (TextView) acmi.targetView;
String filename = tv.getText().toString();
new AsyncTask<String, Void, Void>() {
protected java.lang.Void doInBackground(String... args) {
String filename = args[0];
fileHistory.deleteFile(Uri.parse(args[0]));
return null;
}
protected void onPostExecute(Void v) {
refreshList();
}
}.execute(filename);
new DeleteFileHistoryAsyncTask(fileHistory, mAdapter).execute(filename);
return true;
}
return false;
}
private void refreshList() {
((BaseAdapter) mAdapter).notifyDataSetChanged();
}
private static class OpenFileHistoryAsyncTask extends AsyncTask<Integer, Void, Void> {
private WeakReference<Activity> weakActivity;
private RecentFileHistory fileHistory;
private String fileName;
private String keyFile;
OpenFileHistoryAsyncTask(Activity activity, RecentFileHistory fileHistory) {
this.weakActivity = new WeakReference<>(activity);
this.fileHistory = fileHistory;
}
protected Void doInBackground(Integer... args) {
int position = args[0];
fileName = fileHistory.getDatabaseAt(position);
keyFile = fileHistory.getKeyfileAt(position);
return null;
}
protected void onPostExecute(Void v) {
try {
PasswordActivity.Launch(weakActivity.get(), fileName, keyFile);
}
catch (ContentFileNotFoundException e) {
Toast.makeText(weakActivity.get(), R.string.file_not_found_content, Toast.LENGTH_LONG)
.show();
}
catch (FileNotFoundException e) {
Toast.makeText(weakActivity.get(), R.string.FileNotFound, Toast.LENGTH_LONG)
.show();
}
}
}
private static class DeleteFileHistoryAsyncTask extends AsyncTask<String, Void, Void> {
private RecentFileHistory fileHistory;
private BaseAdapter adapter;
DeleteFileHistoryAsyncTask(RecentFileHistory fileHistory, BaseAdapter adapter) {
this.fileHistory = fileHistory;
this.adapter = adapter;
}
protected java.lang.Void doInBackground(String... args) {
fileHistory.deleteFile(Uri.parse(args[0]));
return null;
}
protected void onPostExecute(Void v) {
adapter.notifyDataSetChanged();
}
}
}

View File

@@ -9,9 +9,9 @@ import com.kunzisoft.keepass.R;
public class Stylish {
private static String stylishPrefKey;
protected static String stylishPrefKey;
private static String themeString;
protected static String themeString;
public static void init(Context context) {
stylishPrefKey = context.getString(R.string.setting_style_key);
@@ -23,7 +23,7 @@ public class Stylish {
themeString = styleString;
}
static @StyleRes int getThemeId(Context context) {
public static @StyleRes int getThemeId(Context context) {
if (themeString.equals(context.getString(R.string.list_style_name_night)))
return R.style.KeepassDXStyle_Night;

View File

@@ -19,12 +19,6 @@
*/
package com.keepassdroid.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.keepassdroid.database.exception.SamsungClipboardException;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -33,6 +27,12 @@ import android.net.Uri;
import android.text.ClipboardManager;
import android.widget.TextView;
import com.keepassdroid.database.exception.SamsungClipboardException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Util {
public static String getClipboard(Context context) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
@@ -75,14 +75,6 @@ public class Util {
}
}
public static void setEditText(Activity act, int resId, String str) {
TextView te = (TextView) act.findViewById(resId);
if (te != null) {
te.setText(str);
}
}
public static void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[1024];
int read;

View File

@@ -0,0 +1,67 @@
package com.keepassdroid.view;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Handler;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.app.App;
import com.keepassdroid.database.edit.FileOnFinish;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.SetPassword;
import com.kunzisoft.keepass.R;
public class AssignPasswordHelper {
private Context context;
private String masterPassword;
private Uri keyfile;
public AssignPasswordHelper(Context context,
String masterPassword,
Uri keyfile) {
this.context = context;
this.masterPassword = masterPassword;
this.keyfile = keyfile;
}
public void assignPasswordInDatabase(FileOnFinish fileOnFinish) {
SetPassword sp = new SetPassword(context, App.getDB(), masterPassword, keyfile, new AfterSave(fileOnFinish, new Handler()));
final ProgressTask pt = new ProgressTask(context, sp, R.string.saving_database);
boolean valid = sp.validatePassword(context, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
pt.run();
}
});
if (valid) {
pt.run();
}
}
private class AfterSave extends OnFinish {
private FileOnFinish mFinish;
public AfterSave(FileOnFinish finish, Handler handler) {
super(finish, handler);
mFinish = finish;
}
@Override
public void run() {
if ( mSuccess ) {
if ( mFinish != null ) {
mFinish.setFilename(keyfile);
}
} else {
displayMessage(context);
}
super.run();
}
}
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright 2017 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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 2 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.view;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.Fragment;
import android.view.View;
import com.keepassdroid.compat.StorageAF;
import com.keepassdroid.fileselect.BrowserDialog;
import com.keepassdroid.intents.Intents;
import com.keepassdroid.utils.Interaction;
import com.keepassdroid.utils.UriUtil;
import java.io.File;
import static android.app.Activity.RESULT_OK;
public class KeyFileHelper {
public static final int GET_CONTENT = 25745;
private static final int OPEN_DOC = 25845;
private static final int FILE_BROWSE = 25645;
private Activity activity;
private Fragment fragment;
private Uri mDbUri;
public KeyFileHelper(Activity context) {
this(context, null);
}
public KeyFileHelper(Activity context, Uri mDbUri) {
this.activity = context;
this.fragment = null;
this.mDbUri = mDbUri;
}
public KeyFileHelper(Fragment context) {
this(context, null);
}
public KeyFileHelper(Fragment context, Uri mDbUri) {
this.activity = context.getActivity();
this.fragment = context;
this.mDbUri = mDbUri;
}
public View.OnClickListener getOpenFileOnClickViewListener() {
return new View.OnClickListener() {
public void onClick(View v) {
if (StorageAF.useStorageFramework(activity)) {
Intent i = new Intent(StorageAF.ACTION_OPEN_DOCUMENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
if(fragment != null)
fragment.startActivityForResult(i, OPEN_DOC);
else
activity.startActivityForResult(i, OPEN_DOC);
} else {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
try {
if(fragment != null)
fragment.startActivityForResult(i, GET_CONTENT);
else
activity.startActivityForResult(i, GET_CONTENT);
} catch (ActivityNotFoundException e) {
lookForOpenIntentsFilePicker();
}
}
}
};
}
private void lookForOpenIntentsFilePicker() {
if (Interaction.isIntentAvailable(activity, Intents.OPEN_INTENTS_FILE_BROWSE)) {
Intent i = new Intent(Intents.OPEN_INTENTS_FILE_BROWSE);
// Get file path parent if possible
try {
if (mDbUri != null && mDbUri.toString().length() > 0) {
if (mDbUri.getScheme().equals("file")) {
File keyfile = new File(mDbUri.getPath());
File parent = keyfile.getParentFile();
if (parent != null) {
i.setData(Uri.parse("file://" + parent.getAbsolutePath()));
}
}
}
} catch (Exception e) {
// Ignore
}
try {
if(fragment != null)
fragment.startActivityForResult(i, FILE_BROWSE);
else
activity.startActivityForResult(i, FILE_BROWSE);
} catch (ActivityNotFoundException e) {
showBrowserDialog();
}
} else {
showBrowserDialog();
}
}
private void showBrowserDialog() {
BrowserDialog browserDialog = new BrowserDialog(activity);
browserDialog.show();
}
public void onActivityResultCallback(
int requestCode,
int resultCode,
Intent data,
KeyFileCallback keyFileCallback) {
switch (requestCode) {
case FILE_BROWSE:
if (resultCode == RESULT_OK) {
String filename = data.getDataString();
Uri keyUri = null;
if (filename != null) {
keyUri = UriUtil.parseDefaultFile(filename);
}
if (keyFileCallback != null)
keyFileCallback.onKeyFileResultCallback(keyUri);
}
break;
case GET_CONTENT:
case OPEN_DOC:
if (resultCode == RESULT_OK) {
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
if (requestCode == GET_CONTENT) {
uri = UriUtil.translate(activity, uri);
}
if (keyFileCallback != null)
keyFileCallback.onKeyFileResultCallback(uri);
}
}
}
break;
}
}
public interface KeyFileCallback {
void onKeyFileResultCallback(Uri uri);
}
}

View File

@@ -0,0 +1,10 @@
<!-- drawable/database_plus.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M9,3C4.58,3 1,4.79 1,7C1,9.21 4.58,11 9,11C13.42,11 17,9.21 17,7C17,4.79 13.42,3 9,3M1,9V12C1,14.21 4.58,16 9,16C13.42,16 17,14.21 17,12V9C17,11.21 13.42,13 9,13C4.58,13 1,11.21 1,9M1,14V17C1,19.21 4.58,21 9,21C10.41,21 11.79,20.81 13,20.46V17.46C11.79,17.81 10.41,18 9,18C4.58,18 1,16.21 1,14M18,14V17H15V19H18V22H20V19H23V17H20V14" />
</vector>

View File

@@ -0,0 +1,10 @@
<!-- drawable/folder_open.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" />
</vector>

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/default_margin">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="@+id/folder_path_input_layout"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.design.widget.TextInputLayout
android:id="@+id/folder_path_input_layout"
android:layout_toLeftOf="@id/browse_button"
android:layout_toStartOf="@id/browse_button"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="@+id/folder_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/path"
android:inputType="textUri"
android:maxLines="1"
android:singleLine="true"/>
</android.support.design.widget.TextInputLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputLayout
android:id="@+id/filename_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/file_types"
android:layout_toStartOf="@+id/file_types">
<android.support.design.widget.TextInputEditText
android:id="@+id/filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/file_name"
android:text="@string/database_file_name_default"
android:inputType="textUri"
android:maxLines="1"
android:singleLine="true"/>
</android.support.design.widget.TextInputLayout>
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/file_types"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/filename_input_layout"
android:layout_marginBottom="8dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -17,32 +17,47 @@
You should have received a copy of the GNU General Public License
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_default" />
<com.keepassdroid.view.FileNameView android:id="@+id/file_select"
android:layout_marginBottom="@dimen/default_margin"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="match_parent"
android:orientation="vertical">
<TextView android:id="@+id/file_listtop"
android:layout_marginTop="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_width="match_parent"
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_default" />
<com.keepassdroid.view.FileNameView android:id="@+id/file_select"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/file_listtop"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/open_recent" />
<ListView android:id="@+id/file_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/create_database"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/open_recent" />
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:src="@drawable/ic_database_plus_white_24dp"
style="@style/KeepassDXStyle.Fab"/>
<ListView android:id="@+id/file_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</RelativeLayout>

View File

@@ -17,62 +17,76 @@
You should have received a copy of the GNU General Public License
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_margin="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView android:id="@+id/label_warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:visibility="invisible" />
<TextView android:id="@+id/label_open_by_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/enter_filename"/>
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/file_filename"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@id/label_open_by_filename"
android:padding="6dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.v7.widget.AppCompatEditText
android:id="@+id/file_filename"
<android.support.v7.widget.CardView
android:id="@+id/filename_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/label_open_by_filename"
android:inputType="textUri"
android:layout_toLeftOf="@+id/browse_button"
android:layout_toStartOf="@+id/browse_button"
android:maxLines="1" />
android:layout_marginBottom="32dp">
<android.support.v7.widget.AppCompatButton android:id="@+id/open"
android:layout_margin="@dimen/button_margin"
android:text="@string/menu_open"
android:layout_below="@id/file_filename"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_toLeftOf="@+id/create"
android:layout_toStartOf="@+id/create"
android:width="100sp"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_marginBottom="12dp">
<android.support.v7.widget.AppCompatButton android:id="@+id/create"
android:layout_margin="@dimen/button_margin"
android:text="@string/menu_create"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_below="@id/file_filename"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:width="100sp"/>
</RelativeLayout>
<TextView android:id="@+id/label_warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:visibility="invisible" />
<TextView android:id="@+id/label_open_by_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/enter_filename"/>
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/file_filename"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@id/label_open_by_filename"
android:padding="6dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.v7.widget.AppCompatEditText
android:id="@+id/file_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/label_open_by_filename"
android:inputType="textUri"
android:layout_toLeftOf="@+id/browse_button"
android:layout_toStartOf="@+id/browse_button"
android:maxLines="1" />
</RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/open_database"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/filename_container"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
app:fabSize="mini"
app:layout_anchor="@id/filename_container"
app:layout_anchorGravity="bottom|start"
android:src="@drawable/ic_open_folder_white_24dp" />
</android.support.design.widget.CoordinatorLayout>

View File

@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
This file is part of KeePass DX.
KeePass DX 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 2 of the License, or
(at your option) any later version.
KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_default" />
<com.keepassdroid.view.FileNameView android:id="@+id/file_select"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar" />
<!-- Small hack because I need to include a list since this is a list activity -->
<ListView android:id="@+id/file_list"
android:layout_width="0sp"
android:layout_height="0sp" />
</RelativeLayout>

View File

@@ -59,66 +59,73 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/toolbar"
android:layout_above="@+id/pass_ok">
android:layout_below="@+id/toolbar">
<RelativeLayout
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/default_margin">
<TextView
android:id="@+id/password_label"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/entry_and_or" />
<!-- Fingerprint -->
<RelativeLayout
android:id="@+id/password_container"
android:id="@+id/fingerprint_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- added these 2 fingerprint related views -->
<android.support.v7.widget.AppCompatImageView
android:id="@+id/fingerprint_image"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_margin="4dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:elevation="4dp"
android:src="@drawable/fingerprint"
android:background="@drawable/circle"
android:backgroundTint="?attr/colorAccent"
tools:targetApi="lollipop" />
<TextView
android:id="@+id/password_label"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:id="@+id/fingerprint_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/entry_and_or" />
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/fingerprint_image"
android:layout_toStartOf="@+id/fingerprint_image"
android:gravity="center_vertical|end"
android:text="@string/entry_and_or"
android:textColor="?attr/colorAccent"
tools:visibility="visible" />
</RelativeLayout>
<!-- Fingerprint -->
<RelativeLayout
android:id="@+id/fingerprint_container"
android:layout_width="match_parent"
<!-- Password Input -->
<RelativeLayout
android:id="@+id/password_input_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/password_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/password_label">
<!-- added these 2 fingerprint related views -->
<android.support.v7.widget.AppCompatImageView
android:id="@+id/fingerprint_image"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_margin="4dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:elevation="4dp"
android:src="@drawable/fingerprint"
android:background="@drawable/circle"
android:backgroundTint="?attr/colorAccent"
tools:targetApi="lollipop" />
android:layout_alignParentBottom="true"
android:paddingBottom="20dp"
android:gravity="center_vertical" />
<TextView
android:id="@+id/fingerprint_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/fingerprint_image"
android:layout_toStartOf="@+id/fingerprint_image"
android:gravity="center_vertical|end"
android:text="@string/entry_and_or"
android:textColor="?attr/colorAccent"
tools:visibility="visible" />
</RelativeLayout>
<!-- Password Input -->
<android.support.design.widget.TextInputLayout
android:id="@+id/password_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/fingerprint_container"
android:layout_toRightOf="@+id/password_checkbox"
android:layout_toEndOf="@+id/password_checkbox"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?attr/colorAccent">
@@ -130,8 +137,21 @@
android:inputType="textPassword"
android:maxLines="1"/>
</android.support.design.widget.TextInputLayout>
</RelativeLayout>
<!-- File Input -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/keyfile_checkox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingBottom="20dp"
android:gravity="center_vertical" />
<!-- File Input -->
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
@@ -139,36 +159,37 @@
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/password_input_layout"
android:padding="12dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:id="@+id/input_entry_keyfile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/password_input_layout"
android:layout_toLeftOf="@id/browse_button"
android:layout_toStartOf="@id/browse_button" >
android:layout_toEndOf="@+id/keyfile_checkox"
android:layout_toRightOf="@+id/keyfile_checkox"
android:layout_toLeftOf="@+id/browse_button"
android:layout_toStartOf="@+id/browse_button">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:hint="@string/entry_keyfile"
android:inputType="text"
android:hint="@string/entry_keyfile" />
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
</RelativeLayout>
<android.support.v7.widget.AppCompatCheckBox
<android.support.v7.widget.SwitchCompat
android:id="@+id/default_database"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/password_container"
android:layout_marginTop="8dp"
android:layout_margin="16dp"
android:text="@string/default_checkbox" />
</RelativeLayout>
</LinearLayout>
</ScrollView>

View File

@@ -17,27 +17,109 @@
You should have received a copy of the GNU General Public License
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText android:id="@+id/pass_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:maxLines="1"
android:hint="@string/hint_pass"/>
<EditText android:id="@+id/pass_conf_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/pass_password"
android:inputType="textPassword"
android:maxLines="1"
android:hint="@string/hint_conf_pass"/>
<EditText android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/pass_conf_password"
android:maxLines="1"
android:hint="@string/hint_keyfile"/>
</RelativeLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="@dimen/default_margin"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:id="@+id/card_view_master_password"
android:layout_margin="4dp"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:orientation="vertical">
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/password_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/password"/>
<!-- Password Input -->
<android.support.design.widget.TextInputLayout
android:id="@+id/password_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?attr/colorAccent">
<android.support.design.widget.TextInputEditText
android:id="@+id/pass_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:maxLines="1"
android:hint="@string/hint_pass"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/password_repeat_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?attr/colorAccent">
<EditText android:id="@+id/pass_conf_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:maxLines="1"
android:hint="@string/hint_conf_pass"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/card_view_key_file"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:orientation="vertical">
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/keyfile_checkox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_keyfile"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:padding="12dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.v7.widget.AppCompatEditText
android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/browse_button"
android:layout_toStartOf="@+id/browse_button"
android:hint="@string/hint_keyfile"
android:maxLines="1"
android:singleLine="true"/>
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>

View File

@@ -61,7 +61,7 @@
<string name="entry_confpassword">Confirma contrasenya:</string>
<string name="entry_created">Creada: </string>
<string name="entry_expires">Expira: </string>
<string name="entry_keyfile">Arxiu clau (opcional)</string>
<string name="entry_keyfile">Arxiu clau</string>
<string name="entry_modified">Modificada: </string>
<string name="entry_password">Contrasenya:</string>
<string name="entry_save">Guarda</string>
@@ -80,7 +80,7 @@
<string name="error_invalid_db">Base de dades invàlida.</string>
<string name="error_invalid_path">Camí invàlid.</string>
<string name="error_no_name">És necessari un nom.</string>
<string name="error_nopass">És necessaria una contrasenya o un arxiu clau.</string>
<string name="error_nokeyfile">És necessaria una contrasenya o un arxiu clau.</string>
<string name="error_out_of_memory">El telèfon sha quedat sense memòria processant la teva base de dades. Potser és massa gran pel teu telèfon.</string>
<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>

View File

@@ -66,7 +66,7 @@
<string name="entry_confpassword">Potvrďte heslo:</string>
<string name="entry_created">Vytvořeno: </string>
<string name="entry_expires">Vyprší: </string>
<string name="entry_keyfile">Klíčový soubor (nepovinné)</string>
<string name="entry_keyfile">Klíčový soubor</string>
<string name="entry_modified">Změněno: </string>
<string name="entry_not_found">Vstupní data nenalezena.</string>
<string name="entry_password">Heslo:</string>
@@ -86,7 +86,7 @@
<string name="error_invalid_db">Chybná databáze.</string>
<string name="error_invalid_path">Chybná cesta.</string>
<string name="error_no_name">Jméno je povinné.</string>
<string name="error_nopass">Heslo nebo klíčový soubor jsou povinné.</string>
<string name="error_nokeyfile">Heslo nebo klíčový soubor jsou povinné.</string>
<string name="error_out_of_memory">Přístroj má málo paměti pro zpracování databáze. Možná je příliš velká pro Váš přístroj.</string>
<string name="error_pass_gen_type">Minimálně jeden typ generování hesla musí být zvolen</string>
<string name="error_pass_match">Hesla se neshodují.</string>

View File

@@ -65,7 +65,7 @@
<string name="entry_confpassword">Bekræft adgangskode:</string>
<string name="entry_created">Oprettet: </string>
<string name="entry_expires">Udløber: </string>
<string name="entry_keyfile">Nøglefil (valgfri)</string>
<string name="entry_keyfile">Nøglefil</string>
<string name="entry_modified">Ændret: </string>
<string name="entry_not_found">Data for posten blev ikke fundet.</string>
<string name="entry_password">Adgangskode:</string>
@@ -85,7 +85,7 @@
<string name="error_invalid_db">Ugyldig database.</string>
<string name="error_invalid_path">Ugyldig sti.</string>
<string name="error_no_name">Et navn er påkrævet.</string>
<string name="error_nopass">En adgangskode eller nøglefil er påkrævet.</string>
<string name="error_nokeyfile">En adgangskode eller nøglefil er påkrævet.</string>
<string name="error_out_of_memory">Telefonen løb tør for hukommelse under analysen af din database. Den kan være for stor til, at din telefon kan håndtere den.</string>
<string name="error_pass_gen_type">Mindst én adgangskode-genererings-type skal vælges</string>
<string name="error_pass_match">Adgangskoder matcher ikke.</string>

View File

@@ -69,7 +69,7 @@
<string name="entry_confpassword">Passwort wiederholen:</string>
<string name="entry_created">Erstelldatum:</string>
<string name="entry_expires">Ablaufdatum:</string>
<string name="entry_keyfile">Schlüsseldatei (optional)</string>
<string name="entry_keyfile">Schlüsseldatei</string>
<string name="entry_modified">Änderungsdatum:</string>
<string name="entry_not_found">Eintrag wurde nicht gefunden.</string>
<string name="entry_password">Passwort:</string>
@@ -89,7 +89,7 @@
<string name="error_invalid_db">Ungültige Datenbank.</string>
<string name="error_invalid_path">Ungültiger Pfad.</string>
<string name="error_no_name">Ein Name wird benötigt.</string>
<string name="error_nopass">Ein Passwort oder eine Schlüsseldatei wird benötigt.</string>
<string name="error_nokeyfile">Ein Passwort oder eine Schlüsseldatei wird benötigt.</string>
<string name="error_out_of_memory">Der Speicher Ihres Smartphones reicht nicht aus, um die Datenbank zu analysieren. Sie ist wahrscheinlich zu groß.</string>
<string name="error_pass_gen_type">Mindestens ein Passwort-Generierungstyp muss ausgewählt werden.</string>
<string name="error_pass_match">Die Passwörter stimmen nicht überein.</string>

View File

@@ -63,7 +63,7 @@
<string name="entry_confpassword">Επιβεβαίωση κωδικού πρόσβασης:</string>
<string name="entry_created">Δημιουργήθηκε: </string>
<string name="entry_expires">Λήγει: </string>
<string name="entry_keyfile">Αρχείο Κλειδιού (προαιρετικό)</string>
<string name="entry_keyfile">Αρχείο Κλειδιού</string>
<string name="entry_modified">Τροποποιήθηκε: </string>
<string name="entry_not_found">Δεν βρέθηκαν δεδομένα εγγραφών.</string>
<string name="entry_password">Κωδικός Πρόσβασης:</string>
@@ -83,7 +83,7 @@
<string name="error_invalid_db">Μη έγκυρη βάση δεδομένων.</string>
<string name="error_invalid_path">Μη έγκυρη διαδρομή.</string>
<string name="error_no_name">Απαιτείται ένα όνομα.</string>
<string name="error_nopass">Απαιτείται ο κωδικός πρόσβασης ή ένα αρχείο κλειδιού.</string>
<string name="error_nokeyfile">Απαιτείται ο κωδικός πρόσβασης ή ένα αρχείο κλειδιού.</string>
<string name="error_out_of_memory">Το τηλέφωνο ξέμεινε από μνήμη κατά τη διάρκεια προσπέλασης της βάσης δεδομένων σας. Μπορεί να είναι πολύ μεγάλη για το τηλέφωνο σας.</string>
<string name="error_pass_gen_type">Πρέπει να επιλεγεί τουλάχιστον ένας τύπος δημιουργίας κωδικού πρόσβασης</string>
<string name="error_pass_match">Οι κωδικοί δεν ταιριάζουν.</string>

View File

@@ -60,7 +60,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
<string name="entry_confpassword">Confirmar contraseña:</string>
<string name="entry_created">Creación: </string>
<string name="entry_expires">Caducidad: </string>
<string name="entry_keyfile">Archivo de clave (opcional)</string>
<string name="entry_keyfile">Archivo de clave</string>
<string name="entry_modified">Modificación: </string>
<string name="entry_password">Contraseña:</string>
<string name="entry_save">Guardar</string>
@@ -79,7 +79,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
<string name="error_invalid_db">Base de datos no válida.</string>
<string name="error_invalid_path">Ruta no válida.</string>
<string name="error_no_name">Se necesita un nombre.</string>
<string name="error_nopass">Se necesita una contraseña o un archivo de clave.</string>
<string name="error_nokeyfile">Se necesita una contraseña o un archivo de clave.</string>
<string name="error_out_of_memory">El dispositivo se quedó sin memory mientras analizada la base de datos. Puede ser demasiado grande para este dispositivo.</string>
<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>

View File

@@ -65,7 +65,7 @@
<string name="entry_confpassword">Pasahitza berretsi:</string>
<string name="entry_created">Sortua: </string>
<string name="entry_expires">Iraungitzen da: </string>
<string name="entry_keyfile">Gako fitxategia (aukerazkoa)</string>
<string name="entry_keyfile">Gako fitxategia</string>
<string name="entry_modified">Aldatua: </string>
<string name="entry_not_found">Sarreraren datuak ez aurkituak.</string>
<string name="entry_password">Pasahitza:</string>
@@ -85,7 +85,7 @@
<string name="error_invalid_db">Datubase baliogabea.</string>
<string name="error_invalid_path">Fitxategirako bide baliogabea.</string>
<string name="error_no_name">Izen bat behar da.</string>
<string name="error_nopass">Pasahitz edo gako fitxategi bat beharrezkoak dira.</string>
<string name="error_nokeyfile">Pasahitz edo gako fitxategi bat beharrezkoak dira.</string>
<string name="error_out_of_memory">Telefonoa memoriarik gabe gelditu da zure datubasea arakatzean. Handiegia izan daiteke zure telefonorako.</string>
<string name="error_pass_gen_type">Pasahitza sortzeko mota bat gutxienez aukeratu behar da</string>
<string name="error_pass_match">Pasahitzak ez datoz bat.</string>

View File

@@ -63,7 +63,7 @@
<string name="entry_confpassword">Vahvista salasana:</string>
<string name="entry_created">Luotu: </string>
<string name="entry_expires">Vanhenee: </string>
<string name="entry_keyfile">Avaintiedosto (valinnainen)</string>
<string name="entry_keyfile">Avaintiedosto</string>
<string name="entry_modified">Muokattu: </string>
<string name="entry_not_found">Tietueen tietoja ei löytynyt.</string>
<string name="entry_password">Salasana:</string>
@@ -83,7 +83,7 @@
<string name="error_invalid_db">Viallinen salasanatietokanta.</string>
<string name="error_invalid_path">Viallinen hakemistopolku.</string>
<string name="error_no_name">Nimi puuttuu.</string>
<string name="error_nopass">Salasana tai avaintiedosto puuttuu.</string>
<string name="error_nokeyfile">Salasana tai avaintiedosto puuttuu.</string>
<string name="error_out_of_memory">Puhelimesta loppui muisti salasanatietokantaa avatessa. Tietokanta voi olla liian suuri tälle puhelinmallille.</string>
<string name="error_pass_gen_type">Vähintään yksi salasanagenerointitapa täytyy olla valittuna.</string>
<string name="error_pass_match">Salasanat eivät täsmää.</string>

View File

@@ -66,7 +66,7 @@
<string name="entry_confpassword">Confirmer mot de passe</string>
<string name="entry_created">Créé</string>
<string name="entry_expires">Expire</string>
<string name="entry_keyfile">Clé (facultative)</string>
<string name="entry_keyfile">Fichier clé</string>
<string name="entry_modified">Modifié</string>
<string name="entry_not_found">Entry data not found.</string>
<string name="entry_password">Mot de passe</string>
@@ -86,7 +86,7 @@
<string name="error_invalid_db">Base de données invalide.</string>
<string name="error_invalid_path">Chemin invalide.</string>
<string name="error_no_name">Le nom est obligatoire.</string>
<string name="error_nopass">Un mot de passe ou clé de fichier est requis.</string>
<string name="error_nokeyfile">Un fichier clé est requis.</string>
<string name="error_out_of_memory">Votre appareil ne dispose pas de suffisamment de mémoire pour ouvrir votre base de données. Elle est probablement trop grosse pour votre appareil.</string>
<string name="error_pass_gen_type">Au moins un type de génération de mot de passe doit être sélectionné</string>
<string name="error_pass_match">Les mots de passe ne correspondent pas.</string>
@@ -191,6 +191,8 @@
<string name="warning_password_encoding">Le format .kdb ne supporte que le jeu de caractère Latin1. Votre mot de passe doit contenir des caractères en dehors de ce jeu. Tous les caractères non-Latin1 sont convertis en un même caractère, ce qui diminue la sécurité de votre mot de passe. Le changement de votre mot de passe est recommandé.</string>
<string name="warning_read_only">Votre carte SD est actuellement en lecture seule. Vous ne pourrez pas enregistrer les changements dans la base de données.</string>
<string name="warning_unmounted">Votre carte SD n\'est actuellement pas montée sur votre appareil. Vous ne pourrez pas charger ou créer votre base de données.</string>
<string name="warning_empty_password">Voulez-vous vraiment utiliser une chaine de caractères vide comme mot de passe ?</string>
<string name="warning_no_encryption_key">Etes-vous sûr de ne vouloir utiliser aucune clé de chiffrement.</string>
<string name="version_label">Version\u00A0:</string>
<string name="configure_fingerprint">Reconnaissance d\'empreinte digitale non configuré pour cet appareil</string>
<string name="scanning_fingerprint">Attente d\'une reconnaissance d\'empreinte digitale</string>
@@ -221,6 +223,10 @@
<string name="fingerprint_enable_title">Écoute d\'empreintes digitales</string>
<string name="fingerprint_enable_summary">Activer l\'ouverture de la base de données par empreinte digitale</string>
<string name="unavailable_feature_text">Impossible de démarrer cette fonctionnalité\nVotre version Android %1$d n\'est pas la version minimale %2$d requise</string>
<string name="file_name">Nom de fichier</string>
<string name="path">Chemin</string>
<string name="assign_master_key">Assigner une clé maître</string>
<string name="create_keepass_file">Créer un fichier keepass</string>
<string-array name="clipboard_timeout_options">
<item>30 secondes</item>

View File

@@ -45,7 +45,7 @@
<string name="entry_confpassword">Jelszó megerősítése:</string>
<string name="entry_created">Létrehozva:</string>
<string name="entry_expires">Lejárat:</string>
<string name="entry_keyfile">Kulcsfájl (opcionális)</string>
<string name="entry_keyfile">Kulcsfájl</string>
<string name="entry_modified">Módosítva:</string>
<string name="entry_password">Jelszó:</string>
<string name="entry_save">Mentés</string>
@@ -64,7 +64,7 @@
<string name="error_invalid_db">Érvénytelen adatbázis.</string>
<string name="error_invalid_path">Érvénytelen útvonal.</string>
<string name="error_no_name">Egy névre van szükség.</string>
<string name="error_nopass">Jelszóra vagy kulcsfájlra van szükség.</string>
<string name="error_nokeyfile">Jelszóra vagy kulcsfájlra van szükség.</string>
<string name="error_out_of_memory">A telefon memóriája megtelt az adatbázis feldolgozása közben. Lehet túl sok ez a telefonnak.</string>
<string name="error_pass_gen_type">Legalább egy jelszógenerálási típust kell választania</string>
<string name="error_pass_match">A jelszavak nem egyeznek meg.</string>

View File

@@ -61,7 +61,7 @@
<string name="entry_confpassword">Conferma password:</string>
<string name="entry_created">Creato: </string>
<string name="entry_expires">Scade: </string>
<string name="entry_keyfile">File chiave (opzionale)</string>
<string name="entry_keyfile">File chiave</string>
<string name="entry_modified">Modificato: </string>
<string name="entry_password">Password</string>
<string name="entry_save">Salva</string>
@@ -80,7 +80,7 @@
<string name="error_invalid_db">Database non valido.</string>
<string name="error_invalid_path">Percorso non valido.</string>
<string name="error_no_name">E\' necessario un nome.</string>
<string name="error_nopass">E\' necessaria una password o un file chiave.</string>
<string name="error_nokeyfile">E\' necessaria una password o un file chiave.</string>
<string name="error_out_of_memory">Il telefono ha esaurito la memoria durante l\'elaborazione del database. Potrebbe essere troppo grande per il tuo telefono.</string>
<string name="error_pass_gen_type">Almeno un tipo di generazione password deve essere selezionato</string>
<string name="error_pass_match">Le password non corrispondono.</string>

View File

@@ -62,7 +62,7 @@
<string name="entry_confpassword">אשר סיסמה:</string>
<string name="entry_created">תאריך יצירה: </string>
<string name="entry_expires">פג תוקף: </string>
<string name="entry_keyfile">קובץ מפתח (רשות)</string>
<string name="entry_keyfile">קובץ מפתח</string>
<string name="entry_modified">נערך לאחרונה: </string>
<string name="entry_not_found">נתוני ערך לא נמצאו.</string>
<string name="entry_password">סיסמה:</string>
@@ -81,7 +81,7 @@
<string name="error_invalid_db">מסד נתונים לא חוקי.</string>
<string name="error_invalid_path">נתיב לא חוקי.</string>
<string name="error_no_name">שם נדרש.</string>
<string name="error_nopass">סיסמה או קובץ מפתח נדרשים.</string>
<string name="error_nokeyfile">סיסמה או קובץ מפתח נדרשים.</string>
<string name="error_out_of_memory">זיכרון המכשיר אזל בזמן ניתוח מסד הנתונים. יתכן והוא גדול מדי למכשירך.</string>
<string name="error_pass_gen_type">לפחות סוג אחד ליצירת סיסמה צריך להיבחר</string>
<string name="error_pass_match">הסיסמאות לא תואמות.</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">パスワードの確認:</string>
<string name="entry_created">作成日: </string>
<string name="entry_expires">有効期限: </string>
<string name="entry_keyfile">キーファイル(オプション)</string>
<string name="entry_keyfile">キーファイル</string>
<string name="entry_modified">更新日: </string>
<string name="entry_password">パスワード:</string>
<string name="entry_save">保存</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">無効なデータベースです。</string>
<string name="error_invalid_path">パスが無効です。</string>
<string name="error_no_name">タイトルは必須入力です。</string>
<string name="error_nopass">パスワードかキーファイルが必要です。</string>
<string name="error_nokeyfile">パスワードかキーファイルが必要です。</string>
<string name="error_out_of_memory">データベース解析中にメモリ不足になりました。</string>
<string name="error_pass_gen_type">少なくとも1つ以上のパスワード生成タイプを選択する必要があります。</string>
<string name="error_pass_match">パスワードが一致しません</string>

View File

@@ -102,7 +102,7 @@
<string name="entry_not_found">Įrašo duomenys nerasti.</string>
<string name="keyfile_is_empty">Rakto failas yra tuščias.</string>
<string name="keyfile_does_not_exist">Rakto failas neegzistuoja.</string>
<string name="entry_keyfile">Rakto failas (pasirinktinis)</string>
<string name="entry_keyfile">Rakto failas</string>
<string name="search_hint">Įrašo pavadinimas/aprašymas</string>
<string name="menu_change_key">Pakeisti master raktą</string>
<string name="entry_accessed">Naudota:</string>

View File

@@ -45,7 +45,7 @@
<string name="entry_confpassword">Apstipriniet paroli:</string>
<string name="entry_created">Izveidots:</string>
<string name="entry_expires">Derīguma termiņš beidzas:</string>
<string name="entry_keyfile">Atslēgas fails (pēc izvēles)</string>
<string name="entry_keyfile">Atslēgas fails</string>
<string name="entry_modified">Modificēts:</string>
<string name="entry_password">Parole:</string>
<string name="entry_save">Saglabāt</string>
@@ -64,7 +64,7 @@
<string name="error_invalid_db">Nederīga datu bāze.</string>
<string name="error_invalid_path">Nederīgs ceļš.</string>
<string name="error_no_name">Vajag ievadīt faila nosaukumu</string>
<string name="error_nopass">Vajadzīga parole vai atslēgas fails.</string>
<string name="error_nokeyfile">Vajadzīga parole vai atslēgas fails.</string>
<string name="error_out_of_memory">Darbam ar datu bāzi, tālrunī nepietiek atmiņas.</string>
<string name="error_pass_gen_type">Ir jāatlasa vismaz viens paroles ģenerēšanas tips</string>
<string name="error_pass_match">Paroles nesakrīt.</string>

View File

@@ -60,7 +60,7 @@
<string name="entry_confpassword">Bevestig wachtwoord:</string>
<string name="entry_created">Aangemaakt op: </string>
<string name="entry_expires">Verloopt op: </string>
<string name="entry_keyfile">Sleutelbestand (optioneel)</string>
<string name="entry_keyfile">Sleutelbestand</string>
<string name="entry_modified">Gewijzigd op: </string>
<string name="entry_password">Wachtwoord:</string>
<string name="entry_save">Opslaan</string>
@@ -79,7 +79,7 @@
<string name="error_invalid_db">Ongeldige database.</string>
<string name="error_invalid_path">Ongeldige padnaam.</string>
<string name="error_no_name">Een naam ontbreekt.</string>
<string name="error_nopass">Een wachtwoord of sleutenbestand ontbreekt.</string>
<string name="error_nokeyfile">Een wachtwoord of sleutenbestand ontbreekt.</string>
<string name="error_out_of_memory">Onvoldoende vrij geheugen om de database te lezen. Misschien is de database te groot voor deze telefoon.</string>
<string name="error_pass_gen_type">U moet minstens één type van wachtwoordgeneratie kiezen.</string>
<string name="error_pass_match">Wachtwoorden zijn niet gelijk.</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">Stadfest passordet:</string>
<string name="entry_created">Laga: </string>
<string name="entry_expires">Går ut: </string>
<string name="entry_keyfile">Nøkkelfil (valfri)</string>
<string name="entry_keyfile">Nøkkelfil</string>
<string name="entry_modified">Endra: </string>
<string name="entry_password">Passord:</string>
<string name="entry_save">Lagra</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">Ugyldig database.</string>
<string name="error_invalid_path">Ugyldig stig.</string>
<string name="error_no_name">Treng eit namn.</string>
<string name="error_nopass">Treng eit passord eller ei nøkkelfil.</string>
<string name="error_nokeyfile">Treng eit passord eller ei nøkkelfil.</string>
<string name="error_out_of_memory">Telefonen gjekk tom for minne ved lesinga av databasen din. Databasen er kanskje for stor.</string>
<string name="error_pass_gen_type">Du må velja minst éin passordlagingstype</string>
<string name="error_pass_match">Passorda samsvarer ikkje.</string>

View File

@@ -56,7 +56,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="entry_confpassword">Potwierdź hasło:</string>
<string name="entry_created">Utworzono: </string>
<string name="entry_expires">Wygasa: </string>
<string name="entry_keyfile">Plik klucza (opcjonalnie)</string>
<string name="entry_keyfile">Plik klucza</string>
<string name="entry_modified">Zmodyfikowano: </string>
<string name="entry_password">Hasło</string>
<string name="entry_save">Zapisz</string>
@@ -75,7 +75,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="error_invalid_db">Nieprawidłowa baza danych.</string>
<string name="error_invalid_path">Nieprawidłowa ścieżka dostępu.</string>
<string name="error_no_name">Wymagana nazwa.</string>
<string name="error_nopass">Wymagane hasło lub plik klucza.</string>
<string name="error_nokeyfile">Wymagane hasło lub plik klucza.</string>
<string name="error_out_of_memory">Podczas parsowania bazy danych zabrakło pamięci. Być może ta baza danych jest za duża dla Twojego urządzenia.</string>
<string name="error_pass_gen_type">Przynajmniej jeden sposób generowania hasła musi być wybrany</string>
<string name="error_pass_match">Hasła nie pasują do siebie.</string>

View File

@@ -61,7 +61,7 @@
<string name="entry_confpassword">Confirmar senha:</string>
<string name="entry_created">Criado: </string>
<string name="entry_expires">Expira: </string>
<string name="entry_keyfile">Arquivo de chave (opcional)</string>
<string name="entry_keyfile">Arquivo de chave</string>
<string name="entry_modified">Modificado: </string>
<string name="entry_password">Senha:</string>
<string name="entry_save">Salvar</string>
@@ -80,7 +80,7 @@
<string name="error_invalid_db">Banco de dados inválido.</string>
<string name="error_invalid_path">Caminho inválido.</string>
<string name="error_no_name">É necessário um nome.</string>
<string name="error_nopass">São necessários uma senha ou um arquivo de chaves.</string>
<string name="error_nokeyfile">São necessários uma senha ou um arquivo de chaves.</string>
<string name="error_out_of_memory">Foi atingida a capacidade máxima de memória do seu dispositivo ao carregar o banco de dados. O banco de dados pode ser muito grande para este dispositivo.</string>
<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>

View File

@@ -66,7 +66,7 @@
<string name="entry_confpassword">Confirmar palavra-passe:</string>
<string name="entry_created">Criado: </string>
<string name="entry_expires">Expira: </string>
<string name="entry_keyfile">Ficheiro chave (opcional)</string>
<string name="entry_keyfile">Ficheiro chave</string>
<string name="entry_modified">Modificado: </string>
<string name="entry_not_found">Dados da entrada não encontrados.</string>
<string name="entry_password">Palavra-passe:</string>
@@ -86,7 +86,7 @@
<string name="error_invalid_db">Base de dados inválida.</string>
<string name="error_invalid_path">Caminho inválido.</string>
<string name="error_no_name">É obrigatório introduzir um nome.</string>
<string name="error_nopass">É obrigatório introduzir uma palavra-passe ou um ficheiro chave.</string>
<string name="error_nokeyfile">É obrigatório introduzir uma palavra-passe ou um ficheiro chave.</string>
<string name="error_out_of_memory">O dispositivo ficou sem memória ao analisar a base de dados. Poderá ser muito grande para o seu dispositivo.</string>
<string name="error_pass_gen_type">Pelo menos um tipo de geração de palavra-passe deve ser selecionado</string>
<string name="error_pass_match">As palavra-passe não coincidem.</string>

View File

@@ -86,7 +86,7 @@
<string name="error_invalid_db">Неверный формат базы</string>
<string name="error_invalid_path">Путь указан неверно</string>
<string name="error_no_name">Необходимо ввести имя файла</string>
<string name="error_nopass">Необходим пароль или файл-ключ</string>
<string name="error_nokeyfile">Необходим пароль или файл-ключ</string>
<string name="error_out_of_memory">Недостаточно памяти для работы с базой</string>
<string name="error_pass_gen_type">Выберите один или несколько типов символов</string>
<string name="error_pass_match">Пароли не совпадают</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">Potvrdiť heslo:</string>
<string name="entry_created">Vytvorené: </string>
<string name="entry_expires">Expirácia: </string>
<string name="entry_keyfile">Súbor Keyfile (voliteľné)</string>
<string name="entry_keyfile">Súbor Keyfile</string>
<string name="entry_modified">Upravené: </string>
<string name="entry_password">Heslo:</string>
<string name="entry_save">Uložiť</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">Chybná databáza.</string>
<string name="error_invalid_path">Chybná cesta.</string>
<string name="error_no_name">Vyžaduje sa meno.</string>
<string name="error_nopass">Vyžaduje sa heslo, alebo súbor keyfile.</string>
<string name="error_nokeyfile">Vyžaduje sa heslo, alebo súbor keyfile.</string>
<string name="error_out_of_memory">Telefón vyčerpal pamäť pri analýze databázy. Možno je to príliš na Váš telefón.</string>
<string name="error_pass_gen_type">Musí byť vybraý najmenej jeden typ generovania hesla</string>
<string name="error_pass_match">Heslá sa nezhodujú.</string>

View File

@@ -65,7 +65,7 @@
<string name="entry_confpassword">Bekräfta lösenord:</string>
<string name="entry_created">Skapad: </string>
<string name="entry_expires">Upphör att gälla: </string>
<string name="entry_keyfile">Nyckelfil (valfri)</string>
<string name="entry_keyfile">Nyckelfil</string>
<string name="entry_modified">Senast ändrad: </string>
<string name="entry_password">Lösenord:</string>
<string name="entry_save">Spara</string>
@@ -84,7 +84,7 @@
<string name="error_invalid_db">Ogiltig databas.</string>
<string name="error_invalid_path">Ogiltig sökväg.</string>
<string name="error_no_name">Ett namn krävs.</string>
<string name="error_nopass">Ett lösenord eller en nyckelfil är ett krav.</string>
<string name="error_nokeyfile">Ett lösenord eller en nyckelfil är ett krav.</string>
<string name="error_out_of_memory">The phone ran out of memory while parsing your database. It may be too large for your phone.</string>
<string name="error_pass_gen_type">At least one password generation type must be selected</string>
<string name="error_pass_match">Lösenorden matchar inte.</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">Підтвердження паролю:</string>
<string name="entry_created">Створено: </string>
<string name="entry_expires">Закінчується: </string>
<string name="entry_keyfile">Файл ключа (необов’язково)</string>
<string name="entry_keyfile">Файл ключа</string>
<string name="entry_modified">Змінено: </string>
<string name="entry_password">Пароль:</string>
<string name="entry_save">Зберегти</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">Невірна база даних.</string>
<string name="error_invalid_path">Невірний шлях.</string>
<string name="error_no_name">Потрібне ім’я.</string>
<string name="error_nopass">Необхідно пароль або файл ключа.</string>
<string name="error_nokeyfile">Необхідно пароль або файл ключа.</string>
<string name="error_out_of_memory">Телефону не вистачило пам’яті при аналізі вашої бази даних. Можливо база надто велика для вашог телефона.</string>
<string name="error_pass_gen_type">Принаймні один тип генерації пароля необхідно вибрати.</string>
<string name="error_pass_match">Паролі не співпадають.</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">确认密码:</string>
<string name="entry_created">创建:</string>
<string name="entry_expires">失效时间:</string>
<string name="entry_keyfile">密钥文件(可选)</string>
<string name="entry_keyfile">密钥文件</string>
<string name="entry_modified">修改时间:: </string>
<string name="entry_password">密码:</string>
<string name="entry_save">保存</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">非法数据库。</string>
<string name="error_invalid_path">非法路径。</string>
<string name="error_no_name">用户名是必须的。</string>
<string name="error_nopass">密码或者密钥文件是必须的。</string>
<string name="error_nokeyfile">密码或者密钥文件是必须的。</string>
<string name="error_out_of_memory">这款手机运行内存不足而不能解析数据库。这可能是数据库太大的缘故。</string>
<string name="error_pass_gen_type">至少必须选择一个密码生成类型</string>
<string name="error_pass_match">密码不匹配。</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">確認密碼:</string>
<string name="entry_created">創建:</string>
<string name="entry_expires">失效時間:</string>
<string name="entry_keyfile">密鑰文件(可選)</string>
<string name="entry_keyfile">密鑰文件</string>
<string name="entry_modified">修改時間:: </string>
<string name="entry_password">密碼:</string>
<string name="entry_save">保存</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">非法資料庫。</string>
<string name="error_invalid_path">非法路徑。</string>
<string name="error_no_name">用戶名是必須的。</string>
<string name="error_nopass">密碼或者密鑰檔是必須的。</string>
<string name="error_nokeyfile">密碼或者密鑰檔是必須的。</string>
<string name="error_out_of_memory">這款手機運行記憶體不足而不能解析資料庫。這可能是資料庫太大的緣故。</string>
<string name="error_pass_gen_type">至少必須選擇一個密碼生成類型</string>
<string name="error_pass_match">密碼不匹配。</string>

View File

@@ -21,7 +21,6 @@
<string name="app_name" translatable="false">KeePass DX</string>
<string name="clipboard_error_url" translatable="false">http://code.google.com/p/android/issues/detail?id=35732</string>
<string name="default_file_path" translatable="false">/keepass/keepass.kdbx</string>
<string name="donate_url" translatable="false"><![CDATA[https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KM6QMDAXZM3UU]]></string>
<string name="homepage" translatable="false">http://www.kunzisoft.com/KeepassDX</string>
<string name="issues" translatable="false">https://github.com/Kunzisoft/KeePassDX/issues</string>
@@ -136,4 +135,12 @@
<string name="chapter_3">III</string>
<string name="chapter_4">IV</string>
<string name="chapter_5">V</string>
<string name="database_file_path_default" translatable="false">/keepass/</string>
<string name="database_file_name_default" translatable="false">keepass</string>
<string name="database_file_extension_default" translatable="false">.kdbx</string>
<string-array name="file_types">
<item translatable="false">@string/database_file_extension_default</item>
</string-array>
</resources>

View File

@@ -65,7 +65,7 @@
<string name="entry_confpassword">Confirm password:</string>
<string name="entry_created">Created: </string>
<string name="entry_expires">Expires: </string>
<string name="entry_keyfile">Key file (optional)</string>
<string name="entry_keyfile">Key file</string>
<string name="entry_modified">Modified: </string>
<string name="entry_not_found">Entry data not found.</string>
<string name="entry_password">Password:</string>
@@ -85,7 +85,7 @@
<string name="error_invalid_db">Invalid database.</string>
<string name="error_invalid_path">Invalid path.</string>
<string name="error_no_name">A name is required.</string>
<string name="error_nopass">A password or a keyfile is required.</string>
<string name="error_nokeyfile">A keyfile is required.</string>
<string name="error_out_of_memory">The phone ran out of memory while parsing your database. It may be too large for your phone.</string>
<string name="error_pass_gen_type">At least one password generation type must be selected</string>
<string name="error_pass_match">Passwords do not match.</string>
@@ -191,6 +191,8 @@
<string name="warning_password_encoding">The .kdb format only supports the Latin1 character set. Your password may contain characters outside of this character set. All non-Latin1 charaters are converted to the same character, which reduces the security of your password. Changing your password is recommended.</string>
<string name="warning_read_only">Your sd card is currently read-only. You may not be able to save changes to your database.</string>
<string name="warning_unmounted">Your sd card is not currently mounted on your device. You will not be able to load or create your database.</string>
<string name="warning_empty_password">Do you really want to use an empty string as password ?</string>
<string name="warning_no_encryption_key">Are you sure you do not want to use any encryption key ?</string>
<string name="version_label">Version:</string>
<string name="configure_fingerprint">Fingerprint supported but not configured for device</string>
<string name="scanning_fingerprint">Listening for fingerprints</string>
@@ -222,6 +224,10 @@
<string name="fingerprint_enable_title">Fingerprint listening</string>
<string name="fingerprint_enable_summary">Enable database opening by fingerprint</string>
<string name="unavailable_feature_text">Can not start this feature\nYour Android version %1$d is not the minimum version %2$d required</string>
<string name="file_name">File name</string>
<string name="path">Path</string>
<string name="assign_master_key">Assign a master key</string>
<string name="create_keepass_file">Create a keepass file</string>
<string-array name="clipboard_timeout_options">
<item>30 seconds</item>
@@ -241,4 +247,5 @@
<item>Light Theme</item>
<item>Night Theme</item>
</string-array>
</resources>

View File

@@ -237,4 +237,34 @@
<item name="android:textSize">16sp</item>
</style>
<!-- File Picker Theme -->
<style name="KeepassDXStyle.FilePickerStyle.Night" parent="Theme.AppCompat.DialogWhenLarge">
<!-- You can override this in your sub theme -->
<item name="nnf_toolbarTheme">@style/ThemeOverlay.AppCompat.ActionBar</item>
<item name="nnf_separator_color">@color/nnf_dark_separator_color</item>
<item name="nnf_save_icon_color">?attr/colorAccent</item>
<item name="nnf_dir_icon_color">?attr/colorAccent</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">@color/green</item>
<item name="colorPrimaryDark">@color/green_dark</item>
<item name="colorAccent">@color/orange</item>
</style>
<style name="KeepassDXStyle.FilePickerStyle.Light" parent="Theme.AppCompat.Light.DialogWhenLarge">
<item name="nnf_toolbarTheme">@style/ThemeOverlay.AppCompat.ActionBar</item>
<item name="nnf_separator_color">@color/nnf_light_separator_color</item>
<item name="nnf_save_icon_color">?attr/colorAccent</item>
<item name="nnf_dir_icon_color">?attr/colorAccent</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">@color/green</item>
<item name="colorPrimaryDark">@color/green_dark</item>
<item name="colorAccent">@color/orange</item>
</style>
</resources>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 47 KiB