mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Compare commits
64 Commits
2.5.0.0bet
...
2.5.0.0bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57f71afb98 | ||
|
|
d8ec198f6f | ||
|
|
34deea5d32 | ||
|
|
edc7324c1d | ||
|
|
b9190e8254 | ||
|
|
534878ae99 | ||
|
|
99bfd21ecc | ||
|
|
cb5c324c9d | ||
|
|
55dc504f26 | ||
|
|
ecb0138c90 | ||
|
|
0860eeb87f | ||
|
|
f08bff61cf | ||
|
|
432aca6465 | ||
|
|
7cdb8db146 | ||
|
|
6ba9dedcb8 | ||
|
|
6d603608f4 | ||
|
|
64f4d9fb84 | ||
|
|
60ccc450ae | ||
|
|
ddb5f327a3 | ||
|
|
df90ea42eb | ||
|
|
a062d648b3 | ||
|
|
a59ae820b5 | ||
|
|
228831acdd | ||
|
|
bf15ee43da | ||
|
|
608f45677c | ||
|
|
1cb15f214b | ||
|
|
cd4a9e9b03 | ||
|
|
d6eae56d4f | ||
|
|
b5a87a63dc | ||
|
|
1eb17c4f34 | ||
|
|
8a6ce1f711 | ||
|
|
0f22f8af45 | ||
|
|
b2e81e6fd9 | ||
|
|
f82eab942d | ||
|
|
aa29aec40f | ||
|
|
181def52ab | ||
|
|
96d2bd63cc | ||
|
|
194021a957 | ||
|
|
9e307f94ea | ||
|
|
155b2de138 | ||
|
|
c76c3fd2be | ||
|
|
01c5554944 | ||
|
|
542cf65b41 | ||
|
|
f037561a67 | ||
|
|
379263a6d3 | ||
|
|
c420ca01f6 | ||
|
|
a1f9db6eee | ||
|
|
c9212174c4 | ||
|
|
0065336377 | ||
|
|
4f9625a3e1 | ||
|
|
7688ebd29b | ||
|
|
3f2a7f1eb3 | ||
|
|
b3d067d0c8 | ||
|
|
a3b4ad5ac1 | ||
|
|
e3b329d27f | ||
|
|
7d10c43822 | ||
|
|
fcb0d45d39 | ||
|
|
5492db0223 | ||
|
|
2207b05f5f | ||
|
|
f15a0c2591 | ||
|
|
92fb22129c | ||
|
|
ccca9c4400 | ||
|
|
0597cb4416 | ||
|
|
0602174e50 |
18
CHANGELOG
18
CHANGELOG
@@ -1,3 +1,21 @@
|
||||
KeepassDX (2.5.0.0beta16)
|
||||
* Fix font and search
|
||||
|
||||
KeepassDX (2.5.0.0beta16)
|
||||
* New search in a single fragment
|
||||
* Search suggestions
|
||||
* Added the display of usernames
|
||||
* Added translations
|
||||
* Fix read-only mode
|
||||
* Fix parcelable / toolbar / back
|
||||
|
||||
KeepassDX (2.5.0.0beta15)
|
||||
* Read only mode
|
||||
* Best group recovery for the navigation fragment
|
||||
* Fix copies in notifications
|
||||
* Fix orientation
|
||||
* Added translations
|
||||
|
||||
KeepassDX (2.5.0.0beta14)
|
||||
* Optimize all the memory with parcelables / fix search
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ KeePass DX is a **free open source password manager for Android**, which helps y
|
||||
|
||||
Yes, KeePass DX is under **free license (OSI certified)** and **without advertising**. You can have a look at its full source and check whether the encryption algorithms are implemented correctly.
|
||||
|
||||
*Note : If you access the application from a store, visual features may not be available to incentivize the contribution to the work of open source projects. These optional visuals are accessible after a donation (and a small congratulation message :) or the purchase of an extended version, but do not worry, the main features remain completely free.*
|
||||
*Note : If you access the application from a store, visual features may not be available to incentivize the contribution to the work of open source projects. These optional visuals are accessible after a donation (and a small congratulation message :) or the purchase of an extended version, but do not worry, the main features remain completely free. If you contribute to the project and you do not have access to the themes, do not hesitate to contact me at [contact@kunzisoft.com](contact@kunzisoft.com), I will give you the procedure.*
|
||||
|
||||
## Contributions
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.kunzisoft.keepass"
|
||||
minSdkVersion 15
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 27
|
||||
versionCode = 14
|
||||
versionName = "2.5.0.0beta14"
|
||||
versionCode = 17
|
||||
versionName = "2.5.0.0beta17"
|
||||
multiDexEnabled true
|
||||
|
||||
testApplicationId = "com.kunzisoft.keepass.tests"
|
||||
@@ -94,7 +94,7 @@ dependencies {
|
||||
implementation 'joda-time:joda-time:2.9.9'
|
||||
implementation 'org.sufficientlysecure:html-textview:3.5'
|
||||
implementation 'com.nononsenseapps:filepicker:4.1.0'
|
||||
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.11.0'
|
||||
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.12.0'
|
||||
// Permissions
|
||||
implementation("com.github.hotchemi:permissionsdispatcher:$permissionDispatcherVersion") {
|
||||
// if you don't use android.app.Fragment you can exclude support for them
|
||||
|
||||
@@ -45,10 +45,10 @@ public class PwEntryTestV4 extends TestCase {
|
||||
|
||||
entry.setBackgroupColor("blue");
|
||||
entry.putProtectedBinary("key1", new ProtectedBinary(false, new byte[] {0,1}));
|
||||
entry.setCustomIcon(new PwIconCustom(UUID.randomUUID(), new byte[0]));
|
||||
entry.setIconCustom(new PwIconCustom(UUID.randomUUID(), new byte[0]));
|
||||
entry.setForegroundColor("red");
|
||||
entry.addToHistory(new PwEntryV4());
|
||||
entry.setIcon(new PwIconStandard(5));
|
||||
entry.setIconStandard(new PwIconStandard(5));
|
||||
entry.setOverrideURL("override");
|
||||
entry.setParent(new PwGroupV4());
|
||||
entry.addExtraField("key2", new ProtectedString(false, "value2"));
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwEntryV3;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.database.action.node.DeleteGroupRunnable;
|
||||
import com.kunzisoft.keepass.search.SearchDbHelper;
|
||||
import com.kunzisoft.keepass.database.search.SearchDbHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -72,8 +72,8 @@ public class DeleteEntry extends AndroidTestCase {
|
||||
|
||||
// Verify the entries were removed from the search index
|
||||
SearchDbHelper dbHelp = new SearchDbHelper(ctx);
|
||||
PwGroup results1 = dbHelp.search(db.getPwDatabase(), ENTRY1_NAME);
|
||||
PwGroup results2 = dbHelp.search(db.getPwDatabase(), ENTRY2_NAME);
|
||||
PwGroup results1 = dbHelp.search(db.getPwDatabase(), ENTRY1_NAME, 100);
|
||||
PwGroup results2 = dbHelp.search(db.getPwDatabase(), ENTRY2_NAME, 100);
|
||||
|
||||
assertEquals("Entry1 was not removed from the search results", 0, results1.numbersOfChildEntries());
|
||||
assertEquals("Entry2 was not removed from the search results", 0, results2.numbersOfChildEntries());
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.tests.database;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.kunzisoft.keepass.database.PwDatabaseV4;
|
||||
import com.kunzisoft.keepass.database.PwEntryV4;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class EntryV4 extends TestCase {
|
||||
|
||||
public void testBackup() {
|
||||
@@ -46,7 +46,7 @@ public class EntryV4 extends TestCase {
|
||||
entry.createBackup(db);
|
||||
|
||||
PwEntryV4 backup = entry.getHistory().get(0);
|
||||
entry.endToManageFieldReferences();
|
||||
entry.stopToManageFieldReferences();
|
||||
assertEquals("Title2", backup.getTitle());
|
||||
assertEquals("User2", backup.getUsername());
|
||||
}
|
||||
|
||||
@@ -104,11 +104,19 @@
|
||||
<activity
|
||||
android:name="com.kunzisoft.keepass.activities.GroupActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
android:windowSoftInputMode="adjustPan"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.app.default_searchable"
|
||||
android:value="com.kunzisoft.keepass.search.SearchResults"
|
||||
android:exported="false"/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.kunzisoft.keepass.activities.EntryActivity"
|
||||
@@ -118,17 +126,6 @@
|
||||
android:name="com.kunzisoft.keepass.activities.EntryEditActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name="com.kunzisoft.keepass.search.SearchResultsActivity"
|
||||
android:launchMode="standard">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
</activity>
|
||||
<activity android:name="com.kunzisoft.keepass.settings.SettingsActivity" />
|
||||
<activity android:name="com.kunzisoft.keepass.autofill.AutoFillAuthActivity"
|
||||
android:configChanges="orientation|keyboardHidden" />
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
@@ -46,7 +47,6 @@ import com.kunzisoft.keepass.database.ExtraFields;
|
||||
import com.kunzisoft.keepass.database.PwDatabase;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
import com.kunzisoft.keepass.lock.LockingHideActivity;
|
||||
import com.kunzisoft.keepass.notifications.NotificationCopyingService;
|
||||
@@ -65,6 +65,7 @@ import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.kunzisoft.keepass.settings.PreferencesUtil.isClipboardNotificationsEnable;
|
||||
import static com.kunzisoft.keepass.settings.PreferencesUtil.isFirstTimeAskAllowCopyPasswordAndProtectedFields;
|
||||
|
||||
public class EntryActivity extends LockingHideActivity {
|
||||
private final static String TAG = EntryActivity.class.getName();
|
||||
@@ -78,15 +79,17 @@ public class EntryActivity extends LockingHideActivity {
|
||||
|
||||
protected PwEntry mEntry;
|
||||
private boolean mShowPassword;
|
||||
protected boolean readOnly = false;
|
||||
|
||||
private ClipboardHelper clipboardHelper;
|
||||
private boolean firstLaunchOfActivity;
|
||||
|
||||
public static void launch(Activity act, PwEntry pw) {
|
||||
private int iconColor;
|
||||
|
||||
public static void launch(Activity act, PwEntry pw, boolean readOnly) {
|
||||
if (LockingActivity.checkTimeIsAllowedOrFinish(act)) {
|
||||
Intent intent = new Intent(act, EntryActivity.class);
|
||||
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
|
||||
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
|
||||
act.startActivityForResult(intent, EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
|
||||
}
|
||||
}
|
||||
@@ -110,7 +113,7 @@ public class EntryActivity extends LockingHideActivity {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
readOnly = db.isReadOnly();
|
||||
readOnly = db.isReadOnly() || readOnly;
|
||||
|
||||
mShowPassword = !PreferencesUtil.isPasswordMask(this);
|
||||
|
||||
@@ -123,6 +126,11 @@ public class EntryActivity extends LockingHideActivity {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the textColor to tint the icon
|
||||
int[] attrs = {R.attr.textColorInverse};
|
||||
TypedArray ta = getTheme().obtainStyledAttributes(attrs);
|
||||
iconColor = ta.getColor(0, Color.WHITE);
|
||||
|
||||
// Refresh Menu contents in case onCreateMenuOptions was called before mEntry was set
|
||||
invalidateOptionsMenu();
|
||||
@@ -225,7 +233,7 @@ public class EntryActivity extends LockingHideActivity {
|
||||
|
||||
startService(intent);
|
||||
}
|
||||
mEntry.endToManageFieldReferences();
|
||||
mEntry.stopToManageFieldReferences();
|
||||
}
|
||||
firstLaunchOfActivity = false;
|
||||
}
|
||||
@@ -310,18 +318,10 @@ public class EntryActivity extends LockingHideActivity {
|
||||
mEntry.startToManageFieldReferences(pm);
|
||||
|
||||
// Assign title icon
|
||||
if (IconPackChooser.getSelectedIconPack(this).tintable()) {
|
||||
// Retrieve the textColor to tint the icon
|
||||
int[] attrs = {R.attr.textColorInverse};
|
||||
TypedArray ta = getTheme().obtainStyledAttributes(attrs);
|
||||
int iconColor = ta.getColor(0, Color.WHITE);
|
||||
App.getDB().getDrawFactory().assignDatabaseIconTo(this, titleIconView, mEntry.getIcon(), true, iconColor);
|
||||
} else {
|
||||
App.getDB().getDrawFactory().assignDatabaseIconTo(this, titleIconView, mEntry.getIcon());
|
||||
}
|
||||
db.getDrawFactory().assignDatabaseIconTo(this, titleIconView, mEntry.getIcon(), iconColor);
|
||||
|
||||
// Assign title text
|
||||
titleView.setText(mEntry.getTitle());
|
||||
titleView.setText(mEntry.getVisualTitle());
|
||||
|
||||
// Assign basic fields
|
||||
entryContentsView.assignUserName(mEntry.getUsername());
|
||||
@@ -330,12 +330,39 @@ public class EntryActivity extends LockingHideActivity {
|
||||
getString(R.string.copy_field, getString(R.string.entry_user_name)))
|
||||
);
|
||||
|
||||
entryContentsView.assignPassword(mEntry.getPassword());
|
||||
if (PreferencesUtil.allowCopyPasswordAndProtectedFields(this)) {
|
||||
boolean allowCopyPassword = PreferencesUtil.allowCopyPasswordAndProtectedFields(this);
|
||||
entryContentsView.assignPassword(mEntry.getPassword(), allowCopyPassword);
|
||||
if (allowCopyPassword) {
|
||||
entryContentsView.assignPasswordCopyListener(view ->
|
||||
clipboardHelper.timeoutCopyToClipboard(mEntry.getPassword(),
|
||||
getString(R.string.copy_field, getString(R.string.entry_password)))
|
||||
);
|
||||
} else {
|
||||
// If dialog not already shown
|
||||
if (isFirstTimeAskAllowCopyPasswordAndProtectedFields(this)) {
|
||||
entryContentsView.assignPasswordCopyListener(v -> {
|
||||
String message = getString(R.string.allow_copy_password_warning) +
|
||||
"\n\n" +
|
||||
getString(R.string.clipboard_warning);
|
||||
AlertDialog warningDialog = new AlertDialog.Builder(EntryActivity.this)
|
||||
.setMessage(message).create();
|
||||
warningDialog.setButton(AlertDialog.BUTTON1, getText(android.R.string.ok),
|
||||
(dialog, which) -> {
|
||||
PreferencesUtil.setAllowCopyPasswordAndProtectedFields(EntryActivity.this, true);
|
||||
dialog.dismiss();
|
||||
fillData();
|
||||
});
|
||||
warningDialog.setButton(AlertDialog.BUTTON2, getText(android.R.string.cancel),
|
||||
(dialog, which) -> {
|
||||
PreferencesUtil.setAllowCopyPasswordAndProtectedFields(EntryActivity.this, false);
|
||||
dialog.dismiss();
|
||||
fillData();
|
||||
});
|
||||
warningDialog.show();
|
||||
});
|
||||
} else {
|
||||
entryContentsView.assignPasswordCopyListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
entryContentsView.assignURL(mEntry.getUrl());
|
||||
@@ -369,7 +396,7 @@ public class EntryActivity extends LockingHideActivity {
|
||||
entryContentsView.assignExpiresDate(getString(R.string.never));
|
||||
}
|
||||
|
||||
mEntry.endToManageFieldReferences();
|
||||
mEntry.stopToManageFieldReferences();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,7 +56,6 @@ import com.kunzisoft.keepass.database.action.node.UpdateEntryRunnable;
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
import com.kunzisoft.keepass.dialogs.GeneratePasswordDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
import com.kunzisoft.keepass.lock.LockingHideActivity;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
@@ -71,7 +70,7 @@ import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.kunzisoft.keepass.dialogs.IconPickerDialogFragment.UNDEFINED_ICON_ID;
|
||||
import static com.kunzisoft.keepass.dialogs.IconPickerDialogFragment.KEY_ICON_STANDARD;
|
||||
|
||||
public class EntryEditActivity extends LockingHideActivity
|
||||
implements IconPickerDialogFragment.IconPickerListener,
|
||||
@@ -89,10 +88,12 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
public static final int ADD_OR_UPDATE_ENTRY_REQUEST_CODE = 7129;
|
||||
public static final String ADD_OR_UPDATE_ENTRY_KEY = "ADD_OR_UPDATE_ENTRY_KEY";
|
||||
|
||||
private Database database;
|
||||
|
||||
protected PwEntry mEntry;
|
||||
protected PwEntry mCallbackNewEntry;
|
||||
protected boolean mIsNew;
|
||||
protected int mSelectedIconID = UNDEFINED_ICON_ID;
|
||||
protected PwIconStandard mSelectedIconStandard;
|
||||
|
||||
// Views
|
||||
private ScrollView scrollView;
|
||||
@@ -143,7 +144,6 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
setContentView(R.layout.entry_edit);
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(getString(R.string.app_name));
|
||||
setSupportActionBar(toolbar);
|
||||
assert getSupportActionBar() != null;
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
@@ -162,8 +162,8 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
entryExtraFieldsContainer = findViewById(R.id.advanced_container);
|
||||
|
||||
// Likely the app has been killed exit the activity
|
||||
Database db = App.getDB();
|
||||
if ( ! db.getLoaded() ) {
|
||||
database = App.getDB();
|
||||
if ( ! database.getLoaded() ) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
@@ -176,18 +176,16 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
TypedArray ta = getTheme().obtainStyledAttributes(attrs);
|
||||
iconColor = ta.getColor(0, Color.WHITE);
|
||||
|
||||
PwDatabase pm = db.getPwDatabase();
|
||||
mSelectedIconStandard = database.getPwDatabase().getIconFactory().getUnknownIcon();
|
||||
|
||||
PwDatabase pm = database.getPwDatabase();
|
||||
if ( uuidBytes == null ) {
|
||||
PwGroupId parentId = intent.getParcelableExtra(KEY_PARENT);
|
||||
PwGroup parent = pm.getGroupByGroupId(parentId);
|
||||
mEntry = db.createEntry(parent);
|
||||
mEntry = database.createEntry(parent);
|
||||
mIsNew = true;
|
||||
// Add the default icon
|
||||
if (IconPackChooser.getSelectedIconPack(this).tintable()) {
|
||||
App.getDB().getDrawFactory().assignDefaultDatabaseIconTo(this, entryIconView, true, iconColor);
|
||||
} else {
|
||||
App.getDB().getDrawFactory().assignDefaultDatabaseIconTo(this, entryIconView);
|
||||
}
|
||||
database.getDrawFactory().assignDefaultDatabaseIconTo(this, entryIconView, iconColor);
|
||||
} else {
|
||||
UUID uuid = Types.bytestoUUID(uuidBytes);
|
||||
mEntry = pm.getEntryByUUIDId(uuid);
|
||||
@@ -195,8 +193,12 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
fillData();
|
||||
}
|
||||
|
||||
// Assign title
|
||||
setTitle((mIsNew) ? getString(R.string.add_entry) : getString(R.string.edit_entry));
|
||||
|
||||
// Retrieve the icon after an orientation change
|
||||
if (savedInstanceState != null && savedInstanceState.containsKey(IconPickerDialogFragment.KEY_ICON_ID)) {
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(KEY_ICON_STANDARD)) {
|
||||
iconPicked(savedInstanceState);
|
||||
}
|
||||
|
||||
@@ -259,9 +261,9 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
EntryEditActivity act = EntryEditActivity.this;
|
||||
RunnableOnFinish task;
|
||||
if ( mIsNew ) {
|
||||
task = new AddEntryRunnable(act, App.getDB(), mCallbackNewEntry, onFinish);
|
||||
task = new AddEntryRunnable(act, database, mCallbackNewEntry, onFinish);
|
||||
} else {
|
||||
task = new UpdateEntryRunnable(act, App.getDB(), mEntry, mCallbackNewEntry, onFinish);
|
||||
task = new UpdateEntryRunnable(act, database, mEntry, mCallbackNewEntry, onFinish);
|
||||
}
|
||||
task.setUpdateProgressTaskStatus(
|
||||
new UpdateProgressTaskStatus(this,
|
||||
@@ -409,7 +411,7 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
newEntry.setLastModificationTime(new PwDate());
|
||||
|
||||
newEntry.setTitle(entryTitleView.getText().toString());
|
||||
newEntry.setIcon(retrieveIcon());
|
||||
newEntry.setIconStandard(retrieveIcon());
|
||||
|
||||
newEntry.setUrl(entryUrlView.getText().toString());
|
||||
newEntry.setUsername(entryUserNameView.getText().toString());
|
||||
@@ -429,21 +431,21 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
}
|
||||
}
|
||||
|
||||
newEntry.endToManageFieldReferences();
|
||||
newEntry.stopToManageFieldReferences();
|
||||
|
||||
return newEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the icon by the selection, or the first icon in the list if the entry is new or the last one
|
||||
* @return
|
||||
*/
|
||||
private PwIconStandard retrieveIcon() {
|
||||
if(mSelectedIconID != UNDEFINED_ICON_ID)
|
||||
return App.getDB().getPwDatabase().getIconFactory().getIcon(mSelectedIconID);
|
||||
|
||||
if (!mSelectedIconStandard.isUnknown())
|
||||
return mSelectedIconStandard;
|
||||
else {
|
||||
if (mIsNew) {
|
||||
return App.getDB().getPwDatabase().getIconFactory().getKeyIcon();
|
||||
return database.getPwDatabase().getIconFactory().getKeyIcon();
|
||||
}
|
||||
else {
|
||||
// Keep previous icon, if no new one was selected
|
||||
@@ -475,16 +477,21 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void assignIconView() {
|
||||
database.getDrawFactory()
|
||||
.assignDatabaseIconTo(
|
||||
this,
|
||||
entryIconView,
|
||||
mEntry.getIcon(),
|
||||
iconColor);
|
||||
}
|
||||
|
||||
protected void fillData() {
|
||||
|
||||
if (IconPackChooser.getSelectedIconPack(this).tintable()) {
|
||||
App.getDB().getDrawFactory().assignDatabaseIconTo(this, entryIconView, mEntry.getIcon(), true, iconColor);
|
||||
} else {
|
||||
App.getDB().getDrawFactory().assignDatabaseIconTo(this, entryIconView, mEntry.getIcon());
|
||||
}
|
||||
assignIconView();
|
||||
|
||||
// Don't start the field reference manager, we want to see the raw ref
|
||||
mEntry.endToManageFieldReferences();
|
||||
mEntry.stopToManageFieldReferences();
|
||||
|
||||
entryTitleView.setText(mEntry.getTitle());
|
||||
entryUserNameView.setText(mEntry.getUsername());
|
||||
@@ -515,14 +522,15 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
|
||||
@Override
|
||||
public void iconPicked(Bundle bundle) {
|
||||
mSelectedIconID = bundle.getInt(IconPickerDialogFragment.KEY_ICON_ID);
|
||||
entryIconView.setImageResource(IconPackChooser.getSelectedIconPack(this).iconToResId(mSelectedIconID));
|
||||
mSelectedIconStandard = bundle.getParcelable(KEY_ICON_STANDARD);
|
||||
mEntry.setIconStandard(mSelectedIconStandard);
|
||||
assignIconView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
if (mSelectedIconID != UNDEFINED_ICON_ID) {
|
||||
outState.putInt(IconPickerDialogFragment.KEY_ICON_ID, mSelectedIconID);
|
||||
if (!mSelectedIconStandard.isUnknown()) {
|
||||
outState.putParcelable(KEY_ICON_STANDARD, mSelectedIconStandard);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.SearchManager;
|
||||
@@ -29,24 +30,31 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.adapters.NodeAdapter;
|
||||
import com.kunzisoft.keepass.adapters.SearchEntryCursorAdapter;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.autofill.AutofillHelper;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
@@ -54,9 +62,11 @@ import com.kunzisoft.keepass.database.PwDatabase;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.database.PwGroupId;
|
||||
import com.kunzisoft.keepass.database.PwGroupV4;
|
||||
import com.kunzisoft.keepass.database.PwIcon;
|
||||
import com.kunzisoft.keepass.database.PwIconStandard;
|
||||
import com.kunzisoft.keepass.database.PwNode;
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||
import com.kunzisoft.keepass.database.action.node.AddGroupRunnable;
|
||||
import com.kunzisoft.keepass.database.action.node.AfterActionNodeOnFinish;
|
||||
import com.kunzisoft.keepass.database.action.node.CopyEntryRunnable;
|
||||
@@ -69,140 +79,161 @@ import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.ReadOnlyDialog;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.search.SearchResultsActivity;
|
||||
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
import com.kunzisoft.keepass.password.AssignPasswordHelper;
|
||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
import com.kunzisoft.keepass.tasks.SaveDatabaseProgressTaskDialogFragment;
|
||||
import com.kunzisoft.keepass.tasks.UIToastTask;
|
||||
import com.kunzisoft.keepass.tasks.UpdateProgressTaskStatus;
|
||||
import com.kunzisoft.keepass.utils.MenuUtil;
|
||||
import com.kunzisoft.keepass.view.AddNodeButtonView;
|
||||
|
||||
import net.cachapa.expandablelayout.ExpandableLayout;
|
||||
|
||||
public class GroupActivity extends ListNodesActivity
|
||||
import static com.kunzisoft.keepass.activities.ReadOnlyHelper.READ_ONLY_DEFAULT;
|
||||
|
||||
public class GroupActivity extends LockingActivity
|
||||
implements GroupEditDialogFragment.EditGroupListener,
|
||||
IconPickerDialogFragment.IconPickerListener,
|
||||
NodeAdapter.NodeMenuListener,
|
||||
ListNodesFragment.OnScrollListener {
|
||||
ListNodesFragment.OnScrollListener,
|
||||
AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
|
||||
NodeAdapter.NodeClickCallback,
|
||||
SortDialogFragment.SortSelectionListener {
|
||||
|
||||
private static final String TAG = GroupActivity.class.getName();
|
||||
|
||||
private Toolbar toolbar;
|
||||
private static final String GROUP_ID_KEY = "GROUP_ID_KEY";
|
||||
private static final String LIST_NODES_FRAGMENT_TAG = "LIST_NODES_FRAGMENT_TAG";
|
||||
private static final String SEARCH_FRAGMENT_TAG = "SEARCH_FRAGMENT_TAG";
|
||||
private static final String OLD_GROUP_TO_UPDATE_KEY = "OLD_GROUP_TO_UPDATE_KEY";
|
||||
private static final String NODE_TO_COPY_KEY = "NODE_TO_COPY_KEY";
|
||||
private static final String NODE_TO_MOVE_KEY = "NODE_TO_MOVE_KEY";
|
||||
|
||||
private Toolbar toolbar;
|
||||
private View searchTitleView;
|
||||
private ExpandableLayout toolbarPasteExpandableLayout;
|
||||
private Toolbar toolbarPaste;
|
||||
|
||||
private ImageView iconView;
|
||||
private AddNodeButtonView addNodeButtonView;
|
||||
private TextView groupNameView;
|
||||
|
||||
protected boolean addGroupEnabled = false;
|
||||
protected boolean addEntryEnabled = false;
|
||||
protected boolean isRoot = false;
|
||||
protected boolean readOnly = false;
|
||||
private Database database;
|
||||
|
||||
private static final String OLD_GROUP_TO_UPDATE_KEY = "OLD_GROUP_TO_UPDATE_KEY";
|
||||
private static final String NODE_TO_COPY_KEY = "NODE_TO_COPY_KEY";
|
||||
private static final String NODE_TO_MOVE_KEY = "NODE_TO_MOVE_KEY";
|
||||
private ListNodesFragment listNodesFragment;
|
||||
private boolean currentGroupIsASearch;
|
||||
|
||||
private PwGroup rootGroup;
|
||||
private PwGroup mCurrentGroup;
|
||||
private PwGroup oldGroupToUpdate;
|
||||
private PwNode nodeToCopy;
|
||||
private PwNode nodeToMove;
|
||||
|
||||
public static void launch(Activity act) {
|
||||
|
||||
private boolean entrySelectionMode;
|
||||
private AutofillHelper autofillHelper;
|
||||
|
||||
private SearchEntryCursorAdapter searchSuggestionAdapter;
|
||||
|
||||
private int iconColor;
|
||||
|
||||
// After a database creation
|
||||
public static void launch(Activity act) {
|
||||
launch(act, READ_ONLY_DEFAULT);
|
||||
}
|
||||
|
||||
public static void launch(Activity act, boolean readOnly) {
|
||||
startRecordTime(act);
|
||||
launch(act, null);
|
||||
launch(act, null, readOnly);
|
||||
}
|
||||
|
||||
public static void launch(Activity act, PwGroup group) {
|
||||
if (checkTimeIsAllowedOrFinish(act)) {
|
||||
Intent intent = new Intent(act, GroupActivity.class);
|
||||
private static void buildAndLaunchIntent(Activity activity, PwGroup group, boolean readOnly,
|
||||
IntentBuildLauncher intentBuildLauncher) {
|
||||
if (checkTimeIsAllowedOrFinish(activity)) {
|
||||
Intent intent = new Intent(activity, GroupActivity.class);
|
||||
if (group != null) {
|
||||
intent.putExtra(GROUP_ID_KEY, group.getId());
|
||||
}
|
||||
act.startActivityForResult(intent, 0);
|
||||
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
|
||||
intentBuildLauncher.startActivityForResult(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(Activity act) {
|
||||
public static void launch(Activity activity, PwGroup group, boolean readOnly) {
|
||||
buildAndLaunchIntent(activity, group, readOnly,
|
||||
(intent) -> activity.startActivityForResult(intent, 0));
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(Activity act, boolean readOnly) {
|
||||
startRecordTime(act);
|
||||
launchForKeyboardResult(act, null);
|
||||
launchForKeyboardResult(act, null, readOnly);
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(Activity act, PwGroup group) {
|
||||
// TODO remove
|
||||
if (checkTimeIsAllowedOrFinish(act)) {
|
||||
Intent intent = new Intent(act, GroupActivity.class);
|
||||
if (group != null) {
|
||||
intent.putExtra(GROUP_ID_KEY, group.getId());
|
||||
}
|
||||
public static void launchForKeyboardResult(Activity activity, PwGroup group, boolean readOnly) {
|
||||
// TODO implement pre search to directly open the direct group
|
||||
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
|
||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
||||
act.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
}
|
||||
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void launchForAutofillResult(Activity act, AssistStructure assistStructure) {
|
||||
public static void launchForAutofillResult(Activity act, AssistStructure assistStructure, boolean readOnly) {
|
||||
if ( assistStructure != null ) {
|
||||
startRecordTime(act);
|
||||
launchForAutofillResult(act, null, assistStructure);
|
||||
launchForAutofillResult(act, null, assistStructure, readOnly);
|
||||
} else {
|
||||
launch(act);
|
||||
launch(act, readOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void launchForAutofillResult(Activity act, PwGroup group, AssistStructure assistStructure) {
|
||||
// TODO remove
|
||||
public static void launchForAutofillResult(Activity activity, PwGroup group, AssistStructure assistStructure, boolean readOnly) {
|
||||
// TODO implement pre search to directly open the direct group
|
||||
if ( assistStructure != null ) {
|
||||
if (checkTimeIsAllowedOrFinish(act)) {
|
||||
Intent intent = new Intent(act, GroupActivity.class);
|
||||
if (group != null) {
|
||||
intent.putExtra(GROUP_ID_KEY, group.getId());
|
||||
}
|
||||
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
|
||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
||||
act.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
}
|
||||
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
});
|
||||
} else {
|
||||
launch(act, group);
|
||||
launch(activity, group, readOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Log.i(TAG, "Started creating tree");
|
||||
if ( mCurrentGroup == null ) {
|
||||
Log.w(TAG, "Group was null");
|
||||
return;
|
||||
}
|
||||
if ( isFinishing() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
database = App.getDB();
|
||||
// Likely the app has been killed exit the activity
|
||||
if ( ! database.getLoaded() ) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct main view
|
||||
setContentView(getLayoutInflater().inflate(R.layout.list_nodes_with_add_button, null));
|
||||
|
||||
attachFragmentToContentView();
|
||||
|
||||
// Initialize views
|
||||
iconView = findViewById(R.id.icon);
|
||||
addNodeButtonView = findViewById(R.id.add_node_button);
|
||||
addNodeButtonView.enableAddGroup(addGroupEnabled);
|
||||
addNodeButtonView.enableAddEntry(addEntryEnabled);
|
||||
|
||||
toolbar = findViewById(R.id.toolbar);
|
||||
toolbar.setTitle("");
|
||||
setSupportActionBar(toolbar);
|
||||
searchTitleView = findViewById(R.id.search_title);
|
||||
groupNameView = findViewById(R.id.group_name);
|
||||
|
||||
toolbarPasteExpandableLayout = findViewById(R.id.expandable_toolbar_paste_layout);
|
||||
toolbarPaste = findViewById(R.id.toolbar_paste);
|
||||
toolbarPaste.inflateMenu(R.menu.node_paste_menu);
|
||||
toolbarPaste.setNavigationIcon(R.drawable.ic_arrow_left_white_24dp);
|
||||
toolbarPaste.setNavigationOnClickListener(view -> {
|
||||
toolbarPasteExpandableLayout.collapse();
|
||||
nodeToCopy = null;
|
||||
nodeToMove = null;
|
||||
});
|
||||
|
||||
invalidateOptionsMenu();
|
||||
|
||||
// Get arg from intent or instance state
|
||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrIntent(savedInstanceState, getIntent());
|
||||
|
||||
// Retrieve elements after an orientation change
|
||||
if (savedInstanceState != null) {
|
||||
if (savedInstanceState.containsKey(OLD_GROUP_TO_UPDATE_KEY))
|
||||
oldGroupToUpdate = savedInstanceState.getParcelable(OLD_GROUP_TO_UPDATE_KEY);
|
||||
@@ -217,90 +248,237 @@ public class GroupActivity extends ListNodesActivity
|
||||
}
|
||||
}
|
||||
|
||||
addNodeButtonView.setAddGroupClickListener(v -> {
|
||||
GroupEditDialogFragment.build()
|
||||
.show(getSupportFragmentManager(),
|
||||
GroupEditDialogFragment.TAG_CREATE_GROUP);
|
||||
rootGroup = database.getPwDatabase().getRootGroup();
|
||||
mCurrentGroup = retrieveCurrentGroup(getIntent(), savedInstanceState);
|
||||
currentGroupIsASearch = Intent.ACTION_SEARCH.equals(getIntent().getAction());
|
||||
|
||||
Log.i(TAG, "Started creating tree");
|
||||
if ( mCurrentGroup == null ) {
|
||||
Log.w(TAG, "Group was null");
|
||||
return;
|
||||
}
|
||||
|
||||
toolbar.setTitle("");
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
toolbarPaste.inflateMenu(R.menu.node_paste_menu);
|
||||
toolbarPaste.setNavigationIcon(R.drawable.ic_arrow_left_white_24dp);
|
||||
toolbarPaste.setNavigationOnClickListener(view -> {
|
||||
toolbarPasteExpandableLayout.collapse();
|
||||
nodeToCopy = null;
|
||||
nodeToMove = null;
|
||||
});
|
||||
|
||||
// Retrieve the textColor to tint the icon
|
||||
int[] attrs = {R.attr.textColorInverse};
|
||||
TypedArray ta = getTheme().obtainStyledAttributes(attrs);
|
||||
iconColor = ta.getColor(0, Color.WHITE);
|
||||
|
||||
String fragmentTag = LIST_NODES_FRAGMENT_TAG;
|
||||
if (currentGroupIsASearch)
|
||||
fragmentTag = SEARCH_FRAGMENT_TAG;
|
||||
|
||||
// Initialize the fragment with the list
|
||||
listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
|
||||
.findFragmentByTag(fragmentTag);
|
||||
if (listNodesFragment == null)
|
||||
listNodesFragment = ListNodesFragment.newInstance(mCurrentGroup, readOnly, currentGroupIsASearch);
|
||||
|
||||
// Attach fragment to content view
|
||||
getSupportFragmentManager().beginTransaction().replace(
|
||||
R.id.nodes_list_fragment_container,
|
||||
listNodesFragment,
|
||||
fragmentTag)
|
||||
.commit();
|
||||
|
||||
// Add listeners to the add buttons
|
||||
addNodeButtonView.setAddGroupClickListener(v -> GroupEditDialogFragment.build()
|
||||
.show(getSupportFragmentManager(),
|
||||
GroupEditDialogFragment.TAG_CREATE_GROUP));
|
||||
addNodeButtonView.setAddEntryClickListener(v ->
|
||||
EntryEditActivity.launch(GroupActivity.this, mCurrentGroup));
|
||||
|
||||
Log.i(TAG, "Finished creating tree");
|
||||
|
||||
if (isRoot) {
|
||||
showWarnings();
|
||||
// To init autofill
|
||||
entrySelectionMode = EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
autofillHelper = new AutofillHelper();
|
||||
autofillHelper.retrieveAssistStructure(getIntent());
|
||||
}
|
||||
|
||||
// Search suggestion
|
||||
searchSuggestionAdapter = new SearchEntryCursorAdapter(this, database);
|
||||
|
||||
Log.i(TAG, "Finished creating tree");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
setIntent(intent);
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
// only one instance of search in backstack
|
||||
openSearchGroup(retrieveCurrentGroup(intent, null));
|
||||
currentGroupIsASearch = true;
|
||||
} else {
|
||||
currentGroupIsASearch = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void openSearchGroup(PwGroup group) {
|
||||
// Delete the previous search fragment
|
||||
Fragment searchFragment = getSupportFragmentManager().findFragmentByTag(SEARCH_FRAGMENT_TAG);
|
||||
if (searchFragment != null) {
|
||||
if ( getSupportFragmentManager()
|
||||
.popBackStackImmediate(SEARCH_FRAGMENT_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE) )
|
||||
getSupportFragmentManager().beginTransaction().remove(searchFragment).commit();
|
||||
}
|
||||
|
||||
openGroup(group, true);
|
||||
}
|
||||
|
||||
private void openChildGroup(PwGroup group) {
|
||||
openGroup(group, false);
|
||||
}
|
||||
|
||||
private void openGroup(PwGroup group, boolean isASearch) {
|
||||
// Check Timeout
|
||||
if (checkTimeIsAllowedOrFinish(this)) {
|
||||
startRecordTime(this);
|
||||
|
||||
// Open a group in a new fragment
|
||||
ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group, readOnly, isASearch);
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
// Different animation
|
||||
String fragmentTag;
|
||||
if (isASearch) {
|
||||
fragmentTransaction.setCustomAnimations(R.anim.slide_in_top, R.anim.slide_out_bottom,
|
||||
R.anim.slide_in_bottom, R.anim.slide_out_top);
|
||||
fragmentTag = SEARCH_FRAGMENT_TAG;
|
||||
} else {
|
||||
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
|
||||
R.anim.slide_in_left, R.anim.slide_out_right);
|
||||
fragmentTag = LIST_NODES_FRAGMENT_TAG;
|
||||
}
|
||||
|
||||
fragmentTransaction.replace(R.id.nodes_list_fragment_container,
|
||||
newListNodeFragment,
|
||||
fragmentTag);
|
||||
fragmentTransaction.addToBackStack(fragmentTag);
|
||||
fragmentTransaction.commit();
|
||||
|
||||
listNodesFragment = newListNodeFragment;
|
||||
mCurrentGroup = group;
|
||||
assignGroupViewElements();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
outState.putParcelable(GROUP_ID_KEY, mCurrentGroup.getId());
|
||||
if (mCurrentGroup != null)
|
||||
outState.putParcelable(GROUP_ID_KEY, mCurrentGroup.getId());
|
||||
outState.putParcelable(OLD_GROUP_TO_UPDATE_KEY, oldGroupToUpdate);
|
||||
if (nodeToCopy != null)
|
||||
outState.putParcelable(NODE_TO_COPY_KEY, nodeToCopy);
|
||||
if (nodeToMove != null)
|
||||
outState.putParcelable(NODE_TO_MOVE_KEY, nodeToMove);
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
protected PwGroup retrieveCurrentGroup(@Nullable Bundle savedInstanceState) {
|
||||
protected PwGroup retrieveCurrentGroup(Intent intent, @Nullable Bundle savedInstanceState) {
|
||||
|
||||
PwGroupId pwGroupId = null;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(GROUP_ID_KEY)) {
|
||||
pwGroupId = savedInstanceState.getParcelable(GROUP_ID_KEY);
|
||||
} else {
|
||||
if (getIntent() != null)
|
||||
pwGroupId = getIntent().getParcelableExtra(GROUP_ID_KEY);
|
||||
// If it's a search
|
||||
if ( Intent.ACTION_SEARCH.equals(intent.getAction()) ) {
|
||||
return database.search(intent.getStringExtra(SearchManager.QUERY).trim());
|
||||
}
|
||||
// else a real group
|
||||
else {
|
||||
PwGroupId pwGroupId = null;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(GROUP_ID_KEY)) {
|
||||
pwGroupId = savedInstanceState.getParcelable(GROUP_ID_KEY);
|
||||
} else {
|
||||
if (getIntent() != null)
|
||||
pwGroupId = intent.getParcelableExtra(GROUP_ID_KEY);
|
||||
}
|
||||
|
||||
Database db = App.getDB();
|
||||
readOnly = db.isReadOnly();
|
||||
PwGroup root = db.getPwDatabase().getRootGroup();
|
||||
readOnly = database.isReadOnly() || readOnly; // Force read only if the database is like that
|
||||
|
||||
Log.w(TAG, "Creating tree view");
|
||||
PwGroup currentGroup;
|
||||
if ( pwGroupId == null ) {
|
||||
currentGroup = root;
|
||||
} else {
|
||||
currentGroup = db.getPwDatabase().getGroupByGroupId(pwGroupId);
|
||||
Log.w(TAG, "Creating tree view");
|
||||
PwGroup currentGroup;
|
||||
if (pwGroupId == null) {
|
||||
currentGroup = rootGroup;
|
||||
} else {
|
||||
currentGroup = database.getPwDatabase().getGroupByGroupId(pwGroupId);
|
||||
}
|
||||
|
||||
return currentGroup;
|
||||
}
|
||||
|
||||
if (currentGroup != null) {
|
||||
addGroupEnabled = !readOnly;
|
||||
addEntryEnabled = !readOnly; // TODO consultation mode
|
||||
isRoot = (currentGroup == root);
|
||||
if (!currentGroup.allowAddEntryIfIsRoot())
|
||||
addEntryEnabled = !isRoot && addEntryEnabled;
|
||||
}
|
||||
|
||||
return currentGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assignToolbarElements() {
|
||||
super.assignToolbarElements();
|
||||
|
||||
// Assign the group icon depending of IconPack or custom icon
|
||||
if ( mCurrentGroup != null ) {
|
||||
if (IconPackChooser.getSelectedIconPack(this).tintable()) {
|
||||
// Retrieve the textColor to tint the icon
|
||||
int[] attrs = {R.attr.textColorInverse};
|
||||
TypedArray ta = getTheme().obtainStyledAttributes(attrs);
|
||||
int iconColor = ta.getColor(0, Color.WHITE);
|
||||
App.getDB().getDrawFactory().assignDatabaseIconTo(this, iconView, mCurrentGroup.getIcon(), true, iconColor);
|
||||
public void assignGroupViewElements() {
|
||||
// Assign title
|
||||
if (mCurrentGroup != null) {
|
||||
String title = mCurrentGroup.getName();
|
||||
if (title != null && title.length() > 0) {
|
||||
if (groupNameView != null) {
|
||||
groupNameView.setText(title);
|
||||
groupNameView.invalidate();
|
||||
}
|
||||
} else {
|
||||
App.getDB().getDrawFactory().assignDatabaseIconTo(this, iconView, mCurrentGroup.getIcon());
|
||||
}
|
||||
|
||||
if (toolbar != null) {
|
||||
if ( mCurrentGroup.containsParent() )
|
||||
toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp);
|
||||
else {
|
||||
toolbar.setNavigationIcon(null);
|
||||
if (groupNameView != null) {
|
||||
groupNameView.setText(getText(R.string.root));
|
||||
groupNameView.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentGroupIsASearch) {
|
||||
searchTitleView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
searchTitleView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// Assign icon
|
||||
if (currentGroupIsASearch) {
|
||||
if (toolbar != null) {
|
||||
toolbar.setNavigationIcon(null);
|
||||
}
|
||||
iconView.setVisibility(View.GONE);
|
||||
} else {
|
||||
// Assign the group icon depending of IconPack or custom icon
|
||||
iconView.setVisibility(View.VISIBLE);
|
||||
if (mCurrentGroup != null) {
|
||||
database.getDrawFactory().assignDatabaseIconTo(this, iconView, mCurrentGroup.getIcon(), iconColor);
|
||||
|
||||
if (toolbar != null) {
|
||||
if (mCurrentGroup.containsParent())
|
||||
toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp);
|
||||
else {
|
||||
toolbar.setNavigationIcon(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show button if allowed
|
||||
if (addNodeButtonView != null) {
|
||||
|
||||
// To enable add button
|
||||
boolean addGroupEnabled = !readOnly && !currentGroupIsASearch;
|
||||
boolean addEntryEnabled = !readOnly && !currentGroupIsASearch;
|
||||
if (mCurrentGroup != null) {
|
||||
boolean isRoot = (mCurrentGroup == rootGroup);
|
||||
if (!mCurrentGroup.allowAddEntryIfIsRoot())
|
||||
addEntryEnabled = !isRoot && addEntryEnabled;
|
||||
if (isRoot) {
|
||||
showWarnings();
|
||||
}
|
||||
}
|
||||
addNodeButtonView.enableAddGroup(addGroupEnabled);
|
||||
addNodeButtonView.enableAddEntry(addEntryEnabled);
|
||||
|
||||
if (addNodeButtonView.isEnable())
|
||||
addNodeButtonView.showButton();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -309,6 +487,50 @@ public class GroupActivity extends ListNodesActivity
|
||||
addNodeButtonView.hideButtonOnScrollListener(dy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNodeClick(PwNode node) {
|
||||
|
||||
// Add event when we have Autofill
|
||||
AssistStructure assistStructure = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
assistStructure = autofillHelper.getAssistStructure();
|
||||
if (assistStructure != null) {
|
||||
switch (node.getType()) {
|
||||
case GROUP:
|
||||
openChildGroup((PwGroup) node);
|
||||
break;
|
||||
case ENTRY:
|
||||
// Build response with the entry selected
|
||||
autofillHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( assistStructure == null ){
|
||||
if (entrySelectionMode) {
|
||||
switch (node.getType()) {
|
||||
case GROUP:
|
||||
openChildGroup((PwGroup) node);
|
||||
break;
|
||||
case ENTRY:
|
||||
EntrySelectionHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (node.getType()) {
|
||||
case GROUP:
|
||||
openChildGroup((PwGroup) node);
|
||||
break;
|
||||
case ENTRY:
|
||||
EntryActivity.launch(this, (PwEntry) node, readOnly);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOpenMenuClick(PwNode node) {
|
||||
onNodeClick(node);
|
||||
@@ -320,7 +542,7 @@ public class GroupActivity extends ListNodesActivity
|
||||
switch (node.getType()) {
|
||||
case GROUP:
|
||||
oldGroupToUpdate = (PwGroup) node;
|
||||
GroupEditDialogFragment.build(node)
|
||||
GroupEditDialogFragment.build(oldGroupToUpdate)
|
||||
.show(getSupportFragmentManager(),
|
||||
GroupEditDialogFragment.TAG_CREATE_GROUP);
|
||||
break;
|
||||
@@ -481,9 +703,11 @@ public class GroupActivity extends ListNodesActivity
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// Show button on resume
|
||||
if (addNodeButtonView != null)
|
||||
addNodeButtonView.showButton();
|
||||
// Refresh the elements
|
||||
assignGroupViewElements();
|
||||
// Refresh suggestions to change preferences
|
||||
if (searchSuggestionAdapter != null)
|
||||
searchSuggestionAdapter.reInit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,7 +720,8 @@ public class GroupActivity extends ListNodesActivity
|
||||
// If no node, show education to add new one
|
||||
if (listNodesFragment != null
|
||||
&& listNodesFragment.isEmpty()) {
|
||||
if (!PreferencesUtil.isEducationNewNodePerformed(this)) {
|
||||
if (!PreferencesUtil.isEducationNewNodePerformed(this)
|
||||
&& addNodeButtonView.isEnable()) {
|
||||
|
||||
TapTargetView.showFor(this,
|
||||
TapTarget.forView(findViewById(R.id.add_button),
|
||||
@@ -633,7 +858,8 @@ public class GroupActivity extends ListNodesActivity
|
||||
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.search, menu);
|
||||
inflater.inflate(R.menu.database_master_key, menu);
|
||||
if (!readOnly)
|
||||
inflater.inflate(R.menu.database_master_key, menu);
|
||||
inflater.inflate(R.menu.database_lock, menu);
|
||||
|
||||
// Get the SearchView and set the searchable configuration
|
||||
@@ -646,11 +872,26 @@ public class GroupActivity extends ListNodesActivity
|
||||
searchView = (SearchView) searchItem.getActionView();
|
||||
}
|
||||
if (searchView != null) {
|
||||
// TODO Flickering when locking, will be better with content provider
|
||||
searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(this, SearchResultsActivity.class)));
|
||||
searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(this, GroupActivity.class)));
|
||||
searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
|
||||
searchView.setSuggestionsAdapter(searchSuggestionAdapter);
|
||||
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
|
||||
@Override
|
||||
public boolean onSuggestionClick(int position) {
|
||||
onNodeClick(searchSuggestionAdapter.getEntryFromPosition(position));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSuggestionSelect(int position) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MenuUtil.contributionMenuInflater(inflater, menu);
|
||||
inflater.inflate(R.menu.default_menu, menu);
|
||||
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
// Launch education screen
|
||||
@@ -667,7 +908,7 @@ public class GroupActivity extends ListNodesActivity
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
String query = intent.getStringExtra(SearchManager.QUERY);
|
||||
// manually launch the real search activity
|
||||
final Intent searchIntent = new Intent(getApplicationContext(), SearchResultsActivity.class);
|
||||
final Intent searchIntent = new Intent(getApplicationContext(), GroupActivity.class);
|
||||
// add query to the Intent Extras
|
||||
searchIntent.setAction(Intent.ACTION_SEARCH);
|
||||
searchIntent.putExtra(SearchManager.QUERY, query);
|
||||
@@ -700,7 +941,7 @@ public class GroupActivity extends ListNodesActivity
|
||||
return true;
|
||||
|
||||
case R.id.menu_search:
|
||||
onSearchRequested();
|
||||
//onSearchRequested();
|
||||
return true;
|
||||
|
||||
case R.id.menu_lock:
|
||||
@@ -710,8 +951,11 @@ public class GroupActivity extends ListNodesActivity
|
||||
case R.id.menu_change_master_key:
|
||||
setPassword();
|
||||
return true;
|
||||
default:
|
||||
// Check the time lock before launching settings
|
||||
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, readOnly, true);
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void setPassword() {
|
||||
@@ -735,7 +979,7 @@ public class GroupActivity extends ListNodesActivity
|
||||
try {
|
||||
iconStandard = (PwIconStandard) icon;
|
||||
} catch (Exception ignored) {} // TODO custom icon
|
||||
newGroup.setIcon(iconStandard);
|
||||
newGroup.setIconStandard(iconStandard);
|
||||
|
||||
// If group created save it in the database
|
||||
AddGroupRunnable addGroupRunnable = new AddGroupRunnable(this,
|
||||
@@ -757,8 +1001,11 @@ public class GroupActivity extends ListNodesActivity
|
||||
updateGroup.setName(name);
|
||||
try {
|
||||
iconStandard = (PwIconStandard) icon;
|
||||
} catch (Exception ignored) {} // TODO custom icon
|
||||
updateGroup.setIcon(iconStandard);
|
||||
updateGroup = ((PwGroupV4) oldGroupToUpdate).clone(); // TODO generalize
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} // TODO custom icon
|
||||
updateGroup.setIconStandard(iconStandard);
|
||||
|
||||
if (listNodesFragment != null)
|
||||
listNodesFragment.removeNode(oldGroupToUpdate);
|
||||
@@ -783,6 +1030,7 @@ public class GroupActivity extends ListNodesActivity
|
||||
|
||||
class AfterAddNode extends AfterActionNodeOnFinish {
|
||||
|
||||
@Override
|
||||
public void run(PwNode oldNode, PwNode newNode) {
|
||||
super.run();
|
||||
|
||||
@@ -801,6 +1049,7 @@ public class GroupActivity extends ListNodesActivity
|
||||
|
||||
class AfterUpdateNode extends AfterActionNodeOnFinish {
|
||||
|
||||
@Override
|
||||
public void run(PwNode oldNode, PwNode newNode) {
|
||||
super.run();
|
||||
|
||||
@@ -886,16 +1135,79 @@ public class GroupActivity extends ListNodesActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openGroup(PwGroup group) {
|
||||
super.openGroup(group);
|
||||
if (addNodeButtonView != null)
|
||||
addNodeButtonView.showButton();
|
||||
public void onAssignKeyDialogPositiveClick(
|
||||
boolean masterPasswordChecked, String masterPassword,
|
||||
boolean keyFileChecked, Uri keyFile) {
|
||||
|
||||
AssignPasswordHelper assignPasswordHelper =
|
||||
new AssignPasswordHelper(this,
|
||||
masterPasswordChecked, masterPassword, keyFileChecked, keyFile);
|
||||
assignPasswordHelper.assignPasswordInDatabase(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssignKeyDialogNegativeClick(
|
||||
boolean masterPasswordChecked, String masterPassword,
|
||||
boolean keyFileChecked, Uri keyFile) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSortSelected(SortNodeEnum sortNodeEnum, boolean ascending, boolean groupsBefore, boolean recycleBinBottom) {
|
||||
if (listNodesFragment != null)
|
||||
listNodesFragment.onSortSelected(sortNodeEnum, ascending, groupsBefore, recycleBinBottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Override
|
||||
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
|
||||
/*
|
||||
* ACTION_SEARCH automatically forces a new task. This occurs when you open a kdb file in
|
||||
* another app such as Files or GoogleDrive and then Search for an entry. Here we remove the
|
||||
* FLAG_ACTIVITY_NEW_TASK flag bit allowing search to open it's activity in the current task.
|
||||
*/
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
int flags = intent.getFlags();
|
||||
flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
intent.setFlags(flags);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
super.startActivityForResult(intent, requestCode, options);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeSearchInIntent(Intent intent) {
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
currentGroupIsASearch = false;
|
||||
intent.setAction(Intent.ACTION_DEFAULT);
|
||||
intent.removeExtra(SearchManager.QUERY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
if (addNodeButtonView != null)
|
||||
addNodeButtonView.showButton();
|
||||
if (checkTimeIsAllowedOrFinish(this)) {
|
||||
startRecordTime(this);
|
||||
|
||||
super.onBackPressed();
|
||||
|
||||
listNodesFragment = (ListNodesFragment) getSupportFragmentManager().findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
|
||||
// to refresh fragment
|
||||
listNodesFragment.rebuildList();
|
||||
mCurrentGroup = listNodesFragment.getMainGroup();
|
||||
removeSearchInIntent(getIntent());
|
||||
assignGroupViewElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.kunzisoft.keepass.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
public interface IntentBuildLauncher {
|
||||
void startActivityForResult(Intent intent);
|
||||
}
|
||||
@@ -1,290 +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 3 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.kunzisoft.keepass.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.assist.AssistStructure;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.adapters.NodeAdapter;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.autofill.AutofillHelper;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.database.PwNode;
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
|
||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
import com.kunzisoft.keepass.password.AssignPasswordHelper;
|
||||
import com.kunzisoft.keepass.utils.MenuUtil;
|
||||
|
||||
public abstract class ListNodesActivity extends LockingActivity
|
||||
implements AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
|
||||
NodeAdapter.NodeClickCallback,
|
||||
SortDialogFragment.SortSelectionListener {
|
||||
|
||||
protected static final String GROUP_ID_KEY = "GROUP_ID_KEY";
|
||||
|
||||
protected static final String LIST_NODES_FRAGMENT_TAG = "LIST_NODES_FRAGMENT_TAG";
|
||||
protected ListNodesFragment listNodesFragment;
|
||||
|
||||
protected PwGroup mCurrentGroup;
|
||||
protected TextView groupNameView;
|
||||
|
||||
protected boolean entrySelectionMode;
|
||||
protected AutofillHelper autofillHelper;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if ( isFinishing() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Likely the app has been killed exit the activity
|
||||
if ( ! App.getDB().getLoaded() ) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
invalidateOptionsMenu();
|
||||
|
||||
mCurrentGroup = retrieveCurrentGroup(savedInstanceState);
|
||||
|
||||
initializeListNodesFragment(mCurrentGroup);
|
||||
|
||||
entrySelectionMode = EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
autofillHelper = new AutofillHelper();
|
||||
autofillHelper.retrieveAssistStructure(getIntent());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract PwGroup retrieveCurrentGroup(@Nullable Bundle savedInstanceState);
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// Refresh the title
|
||||
assignToolbarElements();
|
||||
}
|
||||
|
||||
protected void initializeListNodesFragment(PwGroup currentGroup) {
|
||||
listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
|
||||
.findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
|
||||
if (listNodesFragment == null)
|
||||
listNodesFragment = ListNodesFragment.newInstance(currentGroup.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach the fragment's list of node.
|
||||
* <br />
|
||||
* <strong>R.id.nodes_list_fragment_container</strong> must be the id of the container
|
||||
*/
|
||||
protected void attachFragmentToContentView() {
|
||||
getSupportFragmentManager().beginTransaction().replace(
|
||||
R.id.nodes_list_fragment_container,
|
||||
listNodesFragment,
|
||||
LIST_NODES_FRAGMENT_TAG)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public void assignToolbarElements() {
|
||||
if (mCurrentGroup != null) {
|
||||
String title = mCurrentGroup.getName();
|
||||
if (title != null && title.length() > 0) {
|
||||
if (groupNameView != null) {
|
||||
groupNameView.setText(title);
|
||||
groupNameView.invalidate();
|
||||
}
|
||||
} else {
|
||||
if (groupNameView != null) {
|
||||
groupNameView.setText(getText(R.string.root));
|
||||
groupNameView.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
MenuUtil.contributionMenuInflater(inflater, menu);
|
||||
inflater.inflate(R.menu.default_menu, menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch ( item.getItemId() ) {
|
||||
default:
|
||||
// Check the time lock before launching settings
|
||||
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, true);
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNodeClick(PwNode node) {
|
||||
|
||||
// Add event when we have Autofill
|
||||
AssistStructure assistStructure = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
assistStructure = autofillHelper.getAssistStructure();
|
||||
if (assistStructure != null) {
|
||||
switch (node.getType()) {
|
||||
case GROUP:
|
||||
openGroup((PwGroup) node);
|
||||
break;
|
||||
case ENTRY:
|
||||
// Build response with the entry selected
|
||||
autofillHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( assistStructure == null ){
|
||||
if (entrySelectionMode) {
|
||||
switch (node.getType()) {
|
||||
case GROUP:
|
||||
openGroup((PwGroup) node);
|
||||
break;
|
||||
case ENTRY:
|
||||
EntrySelectionHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (node.getType()) {
|
||||
case GROUP:
|
||||
openGroup((PwGroup) node);
|
||||
break;
|
||||
case ENTRY:
|
||||
EntryActivity.launch(this, (PwEntry) node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void openGroup(PwGroup group) {
|
||||
// Check Timeout
|
||||
if (checkTimeIsAllowedOrFinish(this)) {
|
||||
startRecordTime(this);
|
||||
|
||||
ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group.getId());
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
|
||||
R.anim.slide_in_left, R.anim.slide_out_right)
|
||||
.replace(R.id.nodes_list_fragment_container,
|
||||
newListNodeFragment,
|
||||
LIST_NODES_FRAGMENT_TAG)
|
||||
.addToBackStack(LIST_NODES_FRAGMENT_TAG)
|
||||
.commit();
|
||||
listNodesFragment = newListNodeFragment;
|
||||
mCurrentGroup = group;
|
||||
assignToolbarElements();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssignKeyDialogPositiveClick(
|
||||
boolean masterPasswordChecked, String masterPassword,
|
||||
boolean keyFileChecked, Uri keyFile) {
|
||||
|
||||
AssignPasswordHelper assignPasswordHelper =
|
||||
new AssignPasswordHelper(this,
|
||||
masterPasswordChecked, masterPassword, keyFileChecked, keyFile);
|
||||
assignPasswordHelper.assignPasswordInDatabase(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssignKeyDialogNegativeClick(
|
||||
boolean masterPasswordChecked, String masterPassword,
|
||||
boolean keyFileChecked, Uri keyFile) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSortSelected(SortNodeEnum sortNodeEnum, boolean ascending, boolean groupsBefore, boolean recycleBinBottom) {
|
||||
if (listNodesFragment != null)
|
||||
listNodesFragment.onSortSelected(sortNodeEnum, ascending, groupsBefore, recycleBinBottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Override
|
||||
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
|
||||
/*
|
||||
* ACTION_SEARCH automatically forces a new task. This occurs when you open a kdb file in
|
||||
* another app such as Files or GoogleDrive and then Search for an entry. Here we remove the
|
||||
* FLAG_ACTIVITY_NEW_TASK flag bit allowing search to open it's activity in the current task.
|
||||
*/
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
int flags = intent.getFlags();
|
||||
flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
intent.setFlags(flags);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
super.startActivityForResult(intent, requestCode, options);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (checkTimeIsAllowedOrFinish(this)) {
|
||||
startRecordTime(this);
|
||||
|
||||
super.onBackPressed();
|
||||
|
||||
listNodesFragment = (ListNodesFragment) getSupportFragmentManager().findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
|
||||
// to refresh fragment
|
||||
listNodesFragment.rebuildList();
|
||||
mCurrentGroup = listNodesFragment.getMainGroup();
|
||||
assignToolbarElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,8 @@ import android.view.ViewGroup;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.adapters.NodeAdapter;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.database.PwDatabase;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.database.PwGroupId;
|
||||
import com.kunzisoft.keepass.database.PwNode;
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
|
||||
@@ -36,34 +34,31 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
private static final String TAG = ListNodesFragment.class.getName();
|
||||
|
||||
private static final String GROUP_KEY = "GROUP_KEY";
|
||||
private static final String GROUP_ID_KEY = "GROUP_ID_KEY";
|
||||
private static final String IS_SEARCH = "IS_SEARCH";
|
||||
|
||||
private NodeAdapter.NodeClickCallback nodeClickCallback;
|
||||
private NodeAdapter.NodeMenuListener nodeMenuListener;
|
||||
private OnScrollListener onScrollListener;
|
||||
|
||||
private RecyclerView listView;
|
||||
protected PwGroup mCurrentGroup;
|
||||
protected NodeAdapter mAdapter;
|
||||
private PwGroup currentGroup;
|
||||
private NodeAdapter mAdapter;
|
||||
|
||||
private View notFoundView;
|
||||
private boolean isASearchResult;
|
||||
|
||||
// Preferences for sorting
|
||||
private SharedPreferences prefs;
|
||||
|
||||
public static ListNodesFragment newInstance(PwGroup group) {
|
||||
private boolean readOnly;
|
||||
|
||||
public static ListNodesFragment newInstance(PwGroup group, boolean readOnly, boolean isASearch) {
|
||||
Bundle bundle = new Bundle();
|
||||
if (group != null) {
|
||||
bundle.putParcelable(GROUP_KEY, group);
|
||||
}
|
||||
ListNodesFragment listNodesFragment = new ListNodesFragment();
|
||||
listNodesFragment.setArguments(bundle);
|
||||
return listNodesFragment;
|
||||
}
|
||||
|
||||
public static ListNodesFragment newInstance(PwGroupId groupId) {
|
||||
Bundle bundle=new Bundle();
|
||||
if (groupId != null) {
|
||||
bundle.putParcelable(GROUP_ID_KEY, groupId);
|
||||
}
|
||||
bundle.putBoolean(IS_SEARCH, isASearch);
|
||||
ReadOnlyHelper.putReadOnlyInBundle(bundle, readOnly);
|
||||
ListNodesFragment listNodesFragment = new ListNodesFragment();
|
||||
listNodesFragment.setArguments(bundle);
|
||||
return listNodesFragment;
|
||||
@@ -101,46 +96,39 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
if ( getActivity() != null ) {
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState, getArguments());
|
||||
|
||||
if (getArguments() != null) {
|
||||
// Contains all the group in element
|
||||
if (getArguments().containsKey(GROUP_KEY)) {
|
||||
currentGroup = getArguments().getParcelable(GROUP_KEY);
|
||||
}
|
||||
|
||||
if (getArguments().containsKey(IS_SEARCH)) {
|
||||
isASearchResult = getArguments().getBoolean(IS_SEARCH);
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentGroup = initCurrentGroup();
|
||||
if (getActivity() != null) {
|
||||
mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater());
|
||||
mAdapter.setReadOnly(readOnly);
|
||||
mAdapter.setIsASearchResult(isASearchResult);
|
||||
mAdapter.setOnNodeClickListener(nodeClickCallback);
|
||||
|
||||
if (nodeMenuListener != null) {
|
||||
mAdapter.setActivateContextMenu(true);
|
||||
mAdapter.setNodeMenuListener(nodeMenuListener);
|
||||
}
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
}
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
}
|
||||
|
||||
protected PwGroup initCurrentGroup() {
|
||||
|
||||
Database db = App.getDB();
|
||||
PwGroup root = db.getPwDatabase().getRootGroup();
|
||||
|
||||
PwGroup currentGroup = null;
|
||||
if (getArguments() != null) {
|
||||
// Contains all the group in element
|
||||
if (getArguments().containsKey(GROUP_KEY)) {
|
||||
currentGroup = getArguments().getParcelable(GROUP_KEY);
|
||||
}
|
||||
// Contains only the group id, so the group must be retrieve
|
||||
if (getArguments().containsKey(GROUP_ID_KEY)) {
|
||||
PwGroupId pwGroupId = getArguments().getParcelable(GROUP_ID_KEY);
|
||||
if ( pwGroupId != null )
|
||||
currentGroup = db.getPwDatabase().getGroupByGroupId(pwGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
if ( currentGroup == null ) {
|
||||
currentGroup = root;
|
||||
}
|
||||
|
||||
return currentGroup;
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -152,6 +140,7 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
View rootView = inflater.cloneInContext(getContextThemed())
|
||||
.inflate(R.layout.list_nodes_fragment, container, false);
|
||||
listView = rootView.findViewById(R.id.nodes_list);
|
||||
notFoundView = rootView.findViewById(R.id.not_found_container);
|
||||
|
||||
if (onScrollListener != null) {
|
||||
listView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@@ -171,11 +160,21 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
super.onResume();
|
||||
|
||||
rebuildList();
|
||||
|
||||
if (isASearchResult && mAdapter.isEmpty()) {
|
||||
// To show the " no search entry found "
|
||||
listView.setVisibility(View.GONE);
|
||||
notFoundView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
listView.setVisibility(View.VISIBLE);
|
||||
notFoundView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void rebuildList() {
|
||||
// Add elements to the list
|
||||
mAdapter.rebuildList(mCurrentGroup);
|
||||
if (currentGroup != null)
|
||||
mAdapter.rebuildList(currentGroup);
|
||||
assignListToNodeAdapter(listView);
|
||||
}
|
||||
|
||||
@@ -197,7 +196,7 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
|
||||
// Tell the adapter to refresh it's list
|
||||
mAdapter.notifyChangeSort(sortNodeEnum, ascending, groupsBefore);
|
||||
mAdapter.rebuildList(mCurrentGroup);
|
||||
mAdapter.rebuildList(currentGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -255,7 +254,7 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
mAdapter.addNode(newNode);
|
||||
if (resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE) {
|
||||
//mAdapter.updateLastNodeRegister(newNode);
|
||||
mAdapter.rebuildList(mCurrentGroup);
|
||||
mAdapter.rebuildList(currentGroup);
|
||||
}
|
||||
} else {
|
||||
Log.e(this.getClass().getName(), "New node can be retrieve in Activity Result");
|
||||
@@ -282,7 +281,7 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
}
|
||||
|
||||
public PwGroup getMainGroup() {
|
||||
return mCurrentGroup;
|
||||
return currentGroup;
|
||||
}
|
||||
|
||||
public interface OnScrollListener {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.kunzisoft.keepass.activities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
|
||||
public class ReadOnlyHelper {
|
||||
|
||||
public static final String READ_ONLY_KEY = "READ_ONLY_KEY";
|
||||
|
||||
public static final boolean READ_ONLY_DEFAULT = false;
|
||||
|
||||
public static boolean retrieveReadOnlyFromInstanceStateOrPreference(Context context, Bundle savedInstanceState) {
|
||||
boolean readOnly;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(READ_ONLY_KEY)) {
|
||||
readOnly = savedInstanceState.getBoolean(READ_ONLY_KEY);
|
||||
} else {
|
||||
readOnly = PreferencesUtil.enableReadOnlyDatabase(context);
|
||||
}
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public static boolean retrieveReadOnlyFromInstanceStateOrArguments(Bundle savedInstanceState, Bundle arguments) {
|
||||
boolean readOnly = READ_ONLY_DEFAULT;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(READ_ONLY_KEY)) {
|
||||
readOnly = savedInstanceState.getBoolean(READ_ONLY_KEY);
|
||||
} else if (arguments != null
|
||||
&& arguments.containsKey(READ_ONLY_KEY)) {
|
||||
readOnly = arguments.getBoolean(READ_ONLY_KEY);
|
||||
}
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public static boolean retrieveReadOnlyFromInstanceStateOrIntent(Bundle savedInstanceState, Intent intent) {
|
||||
boolean readOnly = READ_ONLY_DEFAULT;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(READ_ONLY_KEY)) {
|
||||
readOnly = savedInstanceState.getBoolean(READ_ONLY_KEY);
|
||||
} else {
|
||||
if (intent != null)
|
||||
readOnly = intent.getBooleanExtra(READ_ONLY_KEY, READ_ONLY_DEFAULT);
|
||||
}
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public static void putReadOnlyInIntent(Intent intent, boolean readOnly) {
|
||||
intent.putExtra(READ_ONLY_KEY, readOnly);
|
||||
}
|
||||
|
||||
public static void putReadOnlyInBundle(Bundle bundle, boolean readOnly) {
|
||||
bundle.putBoolean(READ_ONLY_KEY, readOnly);
|
||||
}
|
||||
|
||||
public static void onSaveInstanceState(Bundle outState, boolean readOnly) {
|
||||
outState.putBoolean(READ_ONLY_KEY, readOnly);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ abstract class BasicViewHolder extends RecyclerView.ViewHolder {
|
||||
View container;
|
||||
ImageView icon;
|
||||
TextView text;
|
||||
TextView subText;
|
||||
|
||||
BasicViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
@@ -30,5 +30,6 @@ class EntryViewHolder extends BasicViewHolder {
|
||||
container = itemView.findViewById(R.id.entry_container);
|
||||
icon = itemView.findViewById(R.id.entry_icon);
|
||||
text = itemView.findViewById(R.id.entry_text);
|
||||
subText = itemView.findViewById(R.id.entry_subtext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,5 +30,6 @@ class GroupViewHolder extends BasicViewHolder {
|
||||
container = itemView.findViewById(R.id.group_container);
|
||||
icon = itemView.findViewById(R.id.group_icon);
|
||||
text = itemView.findViewById(R.id.group_text);
|
||||
subText = itemView.findViewById(R.id.group_subtext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +38,13 @@ import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.database.PwNode;
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
import com.kunzisoft.keepass.utils.Util;
|
||||
|
||||
public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
private static final String TAG = NodeAdapter.class.getName();
|
||||
@@ -53,14 +55,20 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
private LayoutInflater inflater;
|
||||
private MenuInflater menuInflater;
|
||||
private float textSize;
|
||||
private float subtextSize;
|
||||
private float iconSize;
|
||||
private SortNodeEnum listSort;
|
||||
private boolean groupsBeforeSort;
|
||||
private boolean ascendingSort;
|
||||
private boolean showUsernames;
|
||||
|
||||
private NodeClickCallback nodeClickCallback;
|
||||
private NodeMenuListener nodeMenuListener;
|
||||
private boolean activateContextMenu;
|
||||
private boolean readOnly;
|
||||
private boolean isASearchResult;
|
||||
|
||||
private Database database;
|
||||
|
||||
private int iconGroupColor;
|
||||
private int iconEntryColor;
|
||||
@@ -75,6 +83,8 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
this.context = context;
|
||||
assignPreferences();
|
||||
this.activateContextMenu = false;
|
||||
this.readOnly = false;
|
||||
this.isASearchResult = false;
|
||||
|
||||
this.nodeSortedList = new SortedList<>(PwNode.class, new SortedListAdapterCallback<PwNode>(this) {
|
||||
@Override public int compare(PwNode item1, PwNode item2) {
|
||||
@@ -90,6 +100,9 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
}
|
||||
});
|
||||
|
||||
// Database
|
||||
this.database = App.getDB();
|
||||
|
||||
// Retrieve the color to tint the icon
|
||||
int[] attrTextColorPrimary = {android.R.attr.textColorPrimary};
|
||||
TypedArray taTextColorPrimary = context.getTheme().obtainStyledAttributes(attrTextColorPrimary);
|
||||
@@ -101,22 +114,30 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
taTextColor.recycle();
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
public void setIsASearchResult(boolean isASearchResult) {
|
||||
this.isASearchResult = isASearchResult;
|
||||
}
|
||||
|
||||
public void setActivateContextMenu(boolean activate) {
|
||||
this.activateContextMenu = activate;
|
||||
}
|
||||
|
||||
private void assignPreferences() {
|
||||
float textSizeDefault = Util.getListTextDefaultSize(context);
|
||||
this.textSize = PreferencesUtil.getListTextSize(context);
|
||||
this.subtextSize = context.getResources().getInteger(R.integer.list_small_size_default)
|
||||
* textSize / textSizeDefault;
|
||||
// Retrieve the icon size
|
||||
int iconDefaultSize = (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
context.getResources().getInteger(R.integer.list_icon_size_default),
|
||||
context.getResources().getDisplayMetrics()
|
||||
);
|
||||
this.iconSize = iconDefaultSize * textSize / Float.parseFloat(context.getString(R.string.list_size_default));
|
||||
float iconDefaultSize = context.getResources().getDimension(R.dimen.list_icon_size_default);
|
||||
this.iconSize = iconDefaultSize * textSize / textSizeDefault;
|
||||
this.listSort = PreferencesUtil.getListSort(context);
|
||||
this.groupsBeforeSort = PreferencesUtil.getGroupsBeforeSort(context);
|
||||
this.ascendingSort = PreferencesUtil.getAscendingSort(context);
|
||||
this.showUsernames = PreferencesUtil.showUsernamesListEntries(context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,6 +155,14 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the adapter contains or not any element
|
||||
* @return true if the list is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return nodeSortedList.size() <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a node to the list
|
||||
* @param node Node to add
|
||||
@@ -195,35 +224,51 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
public void onBindViewHolder(@NonNull BasicViewHolder holder, int position) {
|
||||
PwNode subNode = nodeSortedList.get(position);
|
||||
// Assign image
|
||||
if (IconPackChooser.getSelectedIconPack(context).tintable()) {
|
||||
int iconColor = Color.BLACK;
|
||||
switch (subNode.getType()) {
|
||||
case GROUP:
|
||||
iconColor = iconGroupColor;
|
||||
break;
|
||||
case ENTRY:
|
||||
iconColor = iconEntryColor;
|
||||
break;
|
||||
}
|
||||
App.getDB().getDrawFactory().assignDatabaseIconTo(context, holder.icon, subNode.getIcon(), true, iconColor);
|
||||
} else {
|
||||
App.getDB().getDrawFactory().assignDatabaseIconTo(context, holder.icon, subNode.getIcon());
|
||||
int iconColor = Color.BLACK;
|
||||
switch (subNode.getType()) {
|
||||
case GROUP:
|
||||
iconColor = iconGroupColor;
|
||||
break;
|
||||
case ENTRY:
|
||||
iconColor = iconEntryColor;
|
||||
break;
|
||||
}
|
||||
database.getDrawFactory().assignDatabaseIconTo(context, holder.icon, subNode.getIcon(), iconColor);
|
||||
// Assign text
|
||||
holder.text.setText(subNode.getDisplayTitle());
|
||||
holder.text.setText(subNode.getTitle());
|
||||
// Assign click
|
||||
holder.container.setOnClickListener(
|
||||
new OnNodeClickListener(subNode));
|
||||
// Context menu
|
||||
if (activateContextMenu) {
|
||||
holder.container.setOnCreateContextMenuListener(
|
||||
new ContextMenuBuilder(subNode, nodeMenuListener));
|
||||
new ContextMenuBuilder(subNode, nodeMenuListener, readOnly));
|
||||
}
|
||||
|
||||
// Add username
|
||||
holder.subText.setText("");
|
||||
holder.subText.setVisibility(View.GONE);
|
||||
if (subNode.getType().equals(PwNode.Type.ENTRY)) {
|
||||
PwEntry entry = (PwEntry) subNode;
|
||||
entry.startToManageFieldReferences(database.getPwDatabase());
|
||||
|
||||
holder.text.setText(entry.getVisualTitle());
|
||||
|
||||
String username = entry.getUsername();
|
||||
if (showUsernames && !username.isEmpty()) {
|
||||
holder.subText.setVisibility(View.VISIBLE);
|
||||
holder.subText.setText(username);
|
||||
}
|
||||
|
||||
entry.stopToManageFieldReferences();
|
||||
}
|
||||
|
||||
// Assign image and text size
|
||||
// Relative size of the icon
|
||||
holder.icon.getLayoutParams().height = ((int) iconSize);
|
||||
holder.icon.getLayoutParams().width = ((int) iconSize);
|
||||
holder.text.setTextSize(textSize);
|
||||
holder.subText.setTextSize(subtextSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -287,36 +332,56 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
|
||||
private PwNode node;
|
||||
private NodeMenuListener menuListener;
|
||||
private boolean readOnly;
|
||||
|
||||
ContextMenuBuilder(PwNode node, NodeMenuListener menuListener) {
|
||||
ContextMenuBuilder(PwNode node, NodeMenuListener menuListener, boolean readOnly) {
|
||||
this.menuListener = menuListener;
|
||||
this.node = node;
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
|
||||
menuInflater.inflate(R.menu.node_menu, contextMenu);
|
||||
|
||||
// TODO COPY For Group
|
||||
if (node.getType().equals(PwNode.Type.GROUP)) {
|
||||
contextMenu.removeItem(R.id.menu_copy);
|
||||
}
|
||||
|
||||
// Opening
|
||||
MenuItem menuItem = contextMenu.findItem(R.id.menu_open);
|
||||
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||
if (!App.getDB().isReadOnly() && !node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
|
||||
// Edition
|
||||
|
||||
// Edition
|
||||
if (readOnly || node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
|
||||
contextMenu.removeItem(R.id.menu_edit);
|
||||
} else {
|
||||
menuItem = contextMenu.findItem(R.id.menu_edit);
|
||||
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||
// Copy (not for group)
|
||||
if (node.getType().equals(PwNode.Type.ENTRY)) {
|
||||
menuItem = contextMenu.findItem(R.id.menu_copy);
|
||||
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||
}
|
||||
// Move
|
||||
}
|
||||
|
||||
// Copy (not for group)
|
||||
if (readOnly
|
||||
|| isASearchResult
|
||||
|| node.equals(App.getDB().getPwDatabase().getRecycleBin())
|
||||
|| node.getType().equals(PwNode.Type.GROUP)) {
|
||||
// TODO COPY For Group
|
||||
contextMenu.removeItem(R.id.menu_copy);
|
||||
} else {
|
||||
menuItem = contextMenu.findItem(R.id.menu_copy);
|
||||
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||
}
|
||||
|
||||
// Move
|
||||
if (readOnly
|
||||
|| isASearchResult
|
||||
|| node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
|
||||
contextMenu.removeItem(R.id.menu_move);
|
||||
} else {
|
||||
menuItem = contextMenu.findItem(R.id.menu_move);
|
||||
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||
// Deletion
|
||||
}
|
||||
|
||||
// Deletion
|
||||
if (readOnly || node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
|
||||
contextMenu.removeItem(R.id.menu_delete);
|
||||
} else {
|
||||
menuItem = contextMenu.findItem(R.id.menu_delete);
|
||||
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2018 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 3 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.kunzisoft.keepass.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwIcon;
|
||||
import com.kunzisoft.keepass.database.PwIconFactory;
|
||||
import com.kunzisoft.keepass.database.cursor.EntryCursor;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SearchEntryCursorAdapter extends CursorAdapter {
|
||||
|
||||
private LayoutInflater cursorInflater;
|
||||
private Database database;
|
||||
private boolean displayUsername;
|
||||
private int iconColor;
|
||||
|
||||
public SearchEntryCursorAdapter(Context context, Database database) {
|
||||
super(context, null, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
|
||||
cursorInflater = (LayoutInflater) context.getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE);
|
||||
this.database = database;
|
||||
|
||||
// Get the icon color
|
||||
int[] attrTextColor = {R.attr.textColorInverse};
|
||||
TypedArray taTextColor = context.getTheme().obtainStyledAttributes(attrTextColor);
|
||||
this.iconColor = taTextColor.getColor(0, Color.WHITE);
|
||||
taTextColor.recycle();
|
||||
|
||||
reInit(context);
|
||||
}
|
||||
|
||||
public void reInit(Context context) {
|
||||
this.displayUsername = PreferencesUtil.showUsernamesListEntries(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
|
||||
View view = cursorInflater.inflate(R.layout.search_entry, parent ,false);
|
||||
ViewHolder viewHolder = new ViewHolder();
|
||||
viewHolder.imageViewIcon = view.findViewById(R.id.entry_icon);
|
||||
viewHolder.textViewTitle = view.findViewById(R.id.entry_text);
|
||||
viewHolder.textViewSubTitle = view.findViewById(R.id.entry_subtext);
|
||||
view.setTag(viewHolder);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
|
||||
// Retrieve elements from cursor
|
||||
UUID uuid = new UUID(cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_UUID_MOST_SIGNIFICANT_BITS)),
|
||||
cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_UUID_LEAST_SIGNIFICANT_BITS)));
|
||||
PwIconFactory iconFactory = database.getPwDatabase().getIconFactory();
|
||||
PwIcon icon = iconFactory.getIcon(
|
||||
new UUID(cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS)),
|
||||
cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS))));
|
||||
if (icon.isUnknown()) {
|
||||
icon = iconFactory.getIcon(cursor.getInt(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_STANDARD)));
|
||||
if (icon.isUnknown())
|
||||
icon = iconFactory.getKeyIcon();
|
||||
}
|
||||
String title = cursor.getString( cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_TITLE) );
|
||||
String username = cursor.getString( cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_USERNAME) );
|
||||
String url = cursor.getString( cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_URL) );
|
||||
|
||||
ViewHolder viewHolder = (ViewHolder) view.getTag();
|
||||
|
||||
// Assign image
|
||||
database.getDrawFactory().assignDatabaseIconTo(context, viewHolder.imageViewIcon, icon, iconColor);
|
||||
|
||||
// Assign title
|
||||
String showTitle = PwEntry.getVisualTitle(false, title, username, url, uuid);
|
||||
viewHolder.textViewTitle.setText(showTitle);
|
||||
if (displayUsername && !username.isEmpty()) {
|
||||
viewHolder.textViewSubTitle.setText(String.format("(%s)", username));
|
||||
} else {
|
||||
viewHolder.textViewSubTitle.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
ImageView imageViewIcon;
|
||||
TextView textViewTitle;
|
||||
TextView textViewSubTitle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
|
||||
return database.searchEntry(constraint.toString());
|
||||
}
|
||||
|
||||
public PwEntry getEntryFromPosition(int position) {
|
||||
PwEntry pwEntry = null;
|
||||
|
||||
Cursor cursor = this.getCursor();
|
||||
if (cursor.moveToFirst()
|
||||
&&
|
||||
cursor.move(position)) {
|
||||
|
||||
pwEntry = database.createEntry();
|
||||
database.populateEntry(pwEntry, (EntryCursor) cursor);
|
||||
}
|
||||
return pwEntry;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,19 +21,21 @@ package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine;
|
||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory;
|
||||
import com.kunzisoft.keepass.database.cursor.EntryCursor;
|
||||
import com.kunzisoft.keepass.database.exception.ContentFileNotFoundException;
|
||||
import com.kunzisoft.keepass.database.exception.InvalidDBException;
|
||||
import com.kunzisoft.keepass.database.exception.PwDbOutputException;
|
||||
import com.kunzisoft.keepass.database.load.Importer;
|
||||
import com.kunzisoft.keepass.database.load.ImporterFactory;
|
||||
import com.kunzisoft.keepass.database.save.PwDbOutput;
|
||||
import com.kunzisoft.keepass.database.search.SearchDbHelper;
|
||||
import com.kunzisoft.keepass.icons.IconDrawableFactory;
|
||||
import com.kunzisoft.keepass.search.SearchDbHelper;
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater;
|
||||
import com.kunzisoft.keepass.utils.UriUtil;
|
||||
|
||||
@@ -179,13 +181,17 @@ public class Database {
|
||||
}
|
||||
|
||||
public PwGroup search(String str) {
|
||||
return search(str, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public PwGroup search(String str, int max) {
|
||||
if (searchHelper == null) { return null; }
|
||||
try {
|
||||
switch (pm.getVersion()) {
|
||||
case V3:
|
||||
return ((SearchDbHelper.SearchDbHelperV3) searchHelper).search(((PwDatabaseV3) pm), str);
|
||||
return ((SearchDbHelper.SearchDbHelperV3) searchHelper).search(((PwDatabaseV3) pm), str, max);
|
||||
case V4:
|
||||
return ((SearchDbHelper.SearchDbHelperV4) searchHelper).search(((PwDatabaseV4) pm), str);
|
||||
return ((SearchDbHelper.SearchDbHelperV4) searchHelper).search(((PwDatabaseV4) pm), str, max);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Search can't be performed with this SearchHelper", e);
|
||||
@@ -193,6 +199,54 @@ public class Database {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cursor searchEntry(String query) {
|
||||
final EntryCursor cursor = new EntryCursor();
|
||||
|
||||
// TODO real content provider
|
||||
if (!query.isEmpty()) {
|
||||
PwGroup searchResult = search(query, 6);
|
||||
PwVersion version = getPwDatabase().getVersion();
|
||||
if (searchResult != null) {
|
||||
for (int i = 0; i < searchResult.numbersOfChildEntries(); i++) {
|
||||
PwEntry entry = searchResult.getChildEntryAt(i);
|
||||
if (!entry.isMetaStream()) { // TODO metastream
|
||||
try {
|
||||
switch (version) {
|
||||
case V3:
|
||||
cursor.addEntry((PwEntryV3) entry);
|
||||
continue;
|
||||
case V4:
|
||||
cursor.addEntry((PwEntryV4) entry);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Can't add PwEntry to the cursor", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public void populateEntry(PwEntry pwEntry, EntryCursor cursor) {
|
||||
PwIconFactory iconFactory = getPwDatabase().getIconFactory();
|
||||
try {
|
||||
switch (getPwDatabase().getVersion()) {
|
||||
case V3:
|
||||
cursor.populateEntry((PwEntryV3) pwEntry, iconFactory);
|
||||
break;
|
||||
case V4:
|
||||
// TODO invert field reference manager
|
||||
pwEntry.startToManageFieldReferences(getPwDatabase());
|
||||
cursor.populateEntry((PwEntryV4) pwEntry, iconFactory);
|
||||
pwEntry.stopToManageFieldReferences();
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "This version of PwGroup can't be populated", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveData(Context ctx) throws IOException, PwDbOutputException {
|
||||
saveData(ctx, mUri);
|
||||
}
|
||||
@@ -464,19 +518,22 @@ public class Database {
|
||||
}
|
||||
}
|
||||
|
||||
public PwEntry createEntry(PwGroup parent) {
|
||||
PwEntry newPwEntry = null;
|
||||
public PwEntry createEntry() {
|
||||
return createEntry(null);
|
||||
}
|
||||
|
||||
public PwEntry createEntry(@Nullable PwGroup parent) {
|
||||
try {
|
||||
switch (getPwDatabase().getVersion()) {
|
||||
case V3:
|
||||
newPwEntry = new PwEntryV3((PwGroupV3) parent);
|
||||
return new PwEntryV3((PwGroupV3) parent);
|
||||
case V4:
|
||||
newPwEntry = new PwEntryV4((PwGroupV4) parent);
|
||||
return new PwEntryV4((PwGroupV4) parent);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "This version of PwEntry can't be created", e);
|
||||
}
|
||||
return newPwEntry;
|
||||
return null;
|
||||
}
|
||||
|
||||
public PwGroup createGroup(PwGroup parent) {
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class PwDatabase<PwGroupDB extends PwGroup<PwGroupDB, PwGroupDB, PwEntryDB>,
|
||||
public abstract class PwDatabase<PwGroupDB extends PwGroup<PwGroupDB, PwEntryDB>,
|
||||
PwEntryDB extends PwEntry<PwGroupDB>> {
|
||||
|
||||
public static final UUID UUID_ZERO = new UUID(0,0);
|
||||
|
||||
@@ -91,7 +91,7 @@ public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
|
||||
PwGroupV3 group = createGroup();
|
||||
group.setId(newGroupId());
|
||||
group.setName(name);
|
||||
group.setIcon(iconFactory.getIcon(iconId));
|
||||
group.setIconStandard(iconFactory.getIcon(iconId));
|
||||
addGroupTo(group, parent);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
|
||||
*/
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
PwEntryV3 ent = entries.get(i);
|
||||
if (ent.getGroupId() == parent.getGroupId())
|
||||
if (ent.getParent().getGroupId() == parent.getGroupId())
|
||||
kids.add(ent);
|
||||
}
|
||||
return kids;
|
||||
|
||||
@@ -37,12 +37,12 @@ import java.util.Date;
|
||||
*/
|
||||
public class PwDate implements Cloneable, Parcelable {
|
||||
|
||||
private static final int DATE_SIZE = 5;
|
||||
private static final int DATE_SIZE = 5;
|
||||
|
||||
private Date jDate;
|
||||
private boolean jDateBuilt = false;
|
||||
private byte[] cDate;
|
||||
private boolean cDateBuilt = false;
|
||||
transient private byte[] cDate;
|
||||
transient private boolean cDateBuilt = false;
|
||||
|
||||
public static final Date NEVER_EXPIRE = getNeverExpire();
|
||||
public static final Date DEFAULT_DATE = getDefaultDate();
|
||||
@@ -96,10 +96,9 @@ public class PwDate implements Cloneable, Parcelable {
|
||||
}
|
||||
|
||||
protected PwDate(Parcel in) {
|
||||
jDate = (Date) in.readSerializable();
|
||||
jDateBuilt = in.readByte() != 0;
|
||||
in.readByteArray(cDate);
|
||||
cDateBuilt = in.readByte() != 0;
|
||||
jDate = (Date) in.readSerializable();
|
||||
jDateBuilt = in.readByte() != 0;
|
||||
cDateBuilt = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,10 +108,8 @@ public class PwDate implements Cloneable, Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeSerializable(jDate);
|
||||
dest.writeSerializable(getDate());
|
||||
dest.writeByte((byte) (jDateBuilt ? 1 : 0));
|
||||
dest.writeByteArray(cDate);
|
||||
dest.writeByte((byte) (cDateBuilt ? 1 : 0));
|
||||
}
|
||||
|
||||
public static final Creator<PwDate> CREATOR = new Creator<PwDate>() {
|
||||
|
||||
@@ -76,7 +76,7 @@ public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> {
|
||||
}
|
||||
|
||||
public void startToManageFieldReferences(PwDatabase db) {}
|
||||
public void endToManageFieldReferences() {}
|
||||
public void stopToManageFieldReferences() {}
|
||||
|
||||
public abstract String getTitle();
|
||||
public abstract void setTitle(String title);
|
||||
@@ -97,15 +97,31 @@ public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> {
|
||||
return getTitle().equals(PMS_TAN_ENTRY) && (getUsername().length() > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayTitle() {
|
||||
if ( isTan() ) {
|
||||
return PMS_TAN_ENTRY + " " + getUsername();
|
||||
} else {
|
||||
return getTitle();
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Get the display title from an entry, <br />
|
||||
* {@link #startToManageFieldReferences(PwDatabase)} and {@link #stopToManageFieldReferences()} must be called
|
||||
* before and after {@link #getVisualTitle()}
|
||||
*/
|
||||
public String getVisualTitle() {
|
||||
// only used to compare, don't car if it's a reference
|
||||
return getVisualTitle(isTan(), getTitle(), getUsername(), getUrl(), getUUID());
|
||||
}
|
||||
|
||||
public static String getVisualTitle(boolean isTAN, String title, String username, String url, UUID uuid) {
|
||||
if ( isTAN ) {
|
||||
return PMS_TAN_ENTRY + " " + username;
|
||||
} else {
|
||||
if (title.isEmpty())
|
||||
if (url.isEmpty())
|
||||
return uuid.toString();
|
||||
else
|
||||
return url;
|
||||
else
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO encapsulate extra fields
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,8 +77,6 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
||||
private static final String PMS_ID_USER = "SYSTEM";
|
||||
private static final String PMS_ID_URL = "$";
|
||||
|
||||
// TODO Parent ID to remove
|
||||
private int groupId;
|
||||
private String title;
|
||||
private String username;
|
||||
private byte[] password;
|
||||
@@ -94,12 +92,10 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
||||
|
||||
public PwEntryV3(PwGroupV3 p) {
|
||||
construct(p);
|
||||
groupId = ((PwGroupIdV3) this.parent.getId()).getId(); // TODO remove
|
||||
}
|
||||
|
||||
public PwEntryV3(Parcel in) {
|
||||
super(in);
|
||||
groupId = in.readInt();
|
||||
title = in.readString();
|
||||
username = in.readString();
|
||||
in.readByteArray(password);
|
||||
@@ -112,7 +108,6 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(groupId);
|
||||
dest.writeString(title);
|
||||
dest.writeString(username);
|
||||
dest.writeByteArray(password);
|
||||
@@ -136,7 +131,6 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
||||
|
||||
protected void updateWith(PwEntryV3 source) {
|
||||
super.assign(source);
|
||||
groupId = source.groupId;
|
||||
|
||||
title = source.title;
|
||||
username = source.username;
|
||||
@@ -182,12 +176,9 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
||||
return newEntry;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
this.parent = new PwGroupV3();
|
||||
this.parent.setGroupId(groupId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -93,7 +93,8 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
parentGroupLastMod = in.readParcelable(PwDate.class.getClassLoader());
|
||||
customData = MemUtil.readStringParcelableMap(in);
|
||||
fields = in.readParcelable(ExtraFields.class.getClassLoader());
|
||||
binaries = MemUtil.readStringParcelableMap(in, ProtectedBinary.class);
|
||||
// TODO binaries takes too much memory for parcelable
|
||||
// binaries = MemUtil.readStringParcelableMap(in, ProtectedBinary.class);
|
||||
foregroundColor = in.readString();
|
||||
backgroupColor = in.readString();
|
||||
overrideURL = in.readString();
|
||||
@@ -112,7 +113,7 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
dest.writeParcelable(parentGroupLastMod, flags);
|
||||
MemUtil.writeStringParcelableMap(dest, customData);
|
||||
dest.writeParcelable(fields, flags);
|
||||
MemUtil.writeStringParcelableMap(dest, flags, binaries);
|
||||
// TODO MemUtil.writeStringParcelableMap(dest, flags, binaries);
|
||||
dest.writeString(foregroundColor);
|
||||
dest.writeString(backgroupColor);
|
||||
dest.writeString(overrideURL);
|
||||
@@ -169,7 +170,7 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endToManageFieldReferences() {
|
||||
public void stopToManageFieldReferences() {
|
||||
this.mDatabase = null;
|
||||
this.mDecodeRef = false;
|
||||
}
|
||||
@@ -205,41 +206,31 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
PwDatabaseV4 db = mDatabase;
|
||||
boolean protect = db.getMemoryProtection().protectTitle;
|
||||
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectTitle;
|
||||
setProtectedString(STR_TITLE, title, protect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(String user) {
|
||||
PwDatabaseV4 db = mDatabase;
|
||||
boolean protect = db.getMemoryProtection().protectUserName;
|
||||
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectUserName;
|
||||
setProtectedString(STR_USERNAME, user, protect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String pass) {
|
||||
PwDatabaseV4 db = mDatabase;
|
||||
boolean protect = db.getMemoryProtection().protectPassword;
|
||||
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectPassword;
|
||||
setProtectedString(STR_PASSWORD, pass, protect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUrl(String url) {
|
||||
PwDatabaseV4 db = mDatabase;
|
||||
boolean protect = db.getMemoryProtection().protectUrl;
|
||||
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectUrl;
|
||||
setProtectedString(STR_URL, url, protect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotes(String notes) {
|
||||
PwDatabaseV4 db = mDatabase;
|
||||
boolean protect = db.getMemoryProtection().protectNotes;
|
||||
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectNotes;
|
||||
setProtectedString(STR_NOTES, notes, protect);
|
||||
}
|
||||
|
||||
@@ -251,14 +242,6 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
fields.putProtectedString(key, value, protect);
|
||||
}
|
||||
|
||||
public PwIconCustom getCustomIcon() {
|
||||
return customIcon;
|
||||
}
|
||||
|
||||
public void setCustomIcon(PwIconCustom icon) {
|
||||
this.customIcon = icon;
|
||||
}
|
||||
|
||||
public PwDate getLocationChanged() {
|
||||
return parentGroupLastMod;
|
||||
}
|
||||
@@ -285,15 +268,28 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
return decodeRefKey(mDecodeRef, STR_URL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public PwIcon getIcon() {
|
||||
if (customIcon == null || customIcon.uuid.equals(PwDatabase.UUID_ZERO)) {
|
||||
if (customIcon == null || customIcon.isUnknown()) {
|
||||
return super.getIcon();
|
||||
} else {
|
||||
return customIcon;
|
||||
}
|
||||
}
|
||||
|
||||
public void setIconCustom(PwIconCustom icon) {
|
||||
this.customIcon = icon;
|
||||
}
|
||||
|
||||
public PwIconCustom getIconCustom() {
|
||||
return customIcon;
|
||||
}
|
||||
|
||||
public void setIconStandard(PwIconStandard icon) {
|
||||
this.icon = icon;
|
||||
this.customIcon = PwIconCustom.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowExtraFields() {
|
||||
return true;
|
||||
|
||||
@@ -24,14 +24,14 @@ import android.os.Parcel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class PwGroup<Parent extends PwGroup, ChildGroup extends PwGroup, ChildEntry extends PwEntry>
|
||||
extends PwNode<Parent> {
|
||||
public abstract class PwGroup<GroupG extends PwGroup, EntryE extends PwEntry>
|
||||
extends PwNode<GroupG> {
|
||||
|
||||
protected String name = "";
|
||||
|
||||
// TODO verify children not needed
|
||||
transient protected List<ChildGroup> childGroups = new ArrayList<>();
|
||||
transient protected List<ChildEntry> childEntries = new ArrayList<>();
|
||||
transient protected List<GroupG> childGroups = new ArrayList<>();
|
||||
transient protected List<EntryE> childEntries = new ArrayList<>();
|
||||
|
||||
protected PwGroup() {
|
||||
super();
|
||||
@@ -54,48 +54,48 @@ public abstract class PwGroup<Parent extends PwGroup, ChildGroup extends PwGroup
|
||||
return (PwGroup) super.clone();
|
||||
}
|
||||
|
||||
protected void assign(PwGroup<Parent, ChildGroup, ChildEntry> source) {
|
||||
protected void assign(PwGroup<GroupG, EntryE> source) {
|
||||
super.assign(source);
|
||||
name = source.name;
|
||||
}
|
||||
|
||||
public List<ChildGroup> getChildGroups() {
|
||||
public List<GroupG> getChildGroups() {
|
||||
return childGroups;
|
||||
}
|
||||
|
||||
public List<ChildEntry> getChildEntries() {
|
||||
public List<EntryE> getChildEntries() {
|
||||
return childEntries;
|
||||
}
|
||||
|
||||
public void setGroups(List<ChildGroup> groups) {
|
||||
public void setGroups(List<GroupG> groups) {
|
||||
childGroups = groups;
|
||||
}
|
||||
|
||||
public void setEntries(List<ChildEntry> entries) {
|
||||
public void setEntries(List<EntryE> entries) {
|
||||
childEntries = entries;
|
||||
}
|
||||
|
||||
public void addChildGroup(ChildGroup group) {
|
||||
public void addChildGroup(GroupG group) {
|
||||
this.childGroups.add(group);
|
||||
}
|
||||
|
||||
public void addChildEntry(ChildEntry entry) {
|
||||
public void addChildEntry(EntryE entry) {
|
||||
this.childEntries.add(entry);
|
||||
}
|
||||
|
||||
public ChildGroup getChildGroupAt(int number) {
|
||||
public GroupG getChildGroupAt(int number) {
|
||||
return this.childGroups.get(number);
|
||||
}
|
||||
|
||||
public ChildEntry getChildEntryAt(int number) {
|
||||
public EntryE getChildEntryAt(int number) {
|
||||
return this.childEntries.get(number);
|
||||
}
|
||||
|
||||
public void removeChildGroup(ChildGroup group) {
|
||||
public void removeChildGroup(GroupG group) {
|
||||
this.childGroups.remove(group);
|
||||
}
|
||||
|
||||
public void removeChildEntry(ChildEntry entry) {
|
||||
public void removeChildEntry(EntryE entry) {
|
||||
this.childEntries.remove(entry);
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public abstract class PwGroup<Parent extends PwGroup, ChildGroup extends PwGroup
|
||||
public List<PwNode> getDirectChildren() {
|
||||
List<PwNode> children = new ArrayList<>();
|
||||
children.addAll(childGroups);
|
||||
for(ChildEntry child : childEntries) {
|
||||
for(EntryE child : childEntries) {
|
||||
if (!child.isMetaStream())
|
||||
children.add(child);
|
||||
}
|
||||
@@ -130,10 +130,18 @@ public abstract class PwGroup<Parent extends PwGroup, ChildGroup extends PwGroup
|
||||
public abstract void setId(PwGroupId id);
|
||||
|
||||
@Override
|
||||
public String getDisplayTitle() {
|
||||
protected String getVisualTitle() {
|
||||
return getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The same thing as {@link #getTitle()}
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -146,15 +154,15 @@ public abstract class PwGroup<Parent extends PwGroup, ChildGroup extends PwGroup
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean preOrderTraverseTree(GroupHandler<ChildGroup> groupHandler,
|
||||
EntryHandler<ChildEntry> entryHandler) {
|
||||
public boolean preOrderTraverseTree(GroupHandler<GroupG> groupHandler,
|
||||
EntryHandler<EntryE> entryHandler) {
|
||||
if (entryHandler != null) {
|
||||
for (ChildEntry entry : childEntries) {
|
||||
for (EntryE entry : childEntries) {
|
||||
if (!entryHandler.operate(entry)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (ChildGroup group : childGroups) {
|
||||
for (GroupG group : childGroups) {
|
||||
if ((groupHandler != null) && !groupHandler.operate(group)) return false;
|
||||
group.preOrderTraverseTree(groupHandler, entryHandler);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
public class PwGroupV3 extends PwGroup<PwGroupV3, PwGroupV3, PwEntryV3> {
|
||||
public class PwGroupV3 extends PwGroup<PwGroupV3, PwEntryV3> {
|
||||
|
||||
// for tree traversing
|
||||
private int groupId;
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implements ITimeLogger {
|
||||
public class PwGroupV4 extends PwGroup<PwGroupV4, PwEntryV4> implements ITimeLogger {
|
||||
|
||||
public static final boolean DEFAULT_SEARCHING_ENABLED = true;
|
||||
|
||||
@@ -65,7 +65,7 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
|
||||
customIcon = in.readParcelable(PwIconCustom.class.getClassLoader());
|
||||
usageCount = in.readLong();
|
||||
parentGroupLastMod = in.readParcelable(PwDate.class.getClassLoader());
|
||||
customData = MemUtil.readStringParcelableMap(in);
|
||||
// TODO customData = MemUtil.readStringParcelableMap(in);
|
||||
expires = in.readByte() != 0;
|
||||
notes = in.readString();
|
||||
isExpanded = in.readByte() != 0;
|
||||
@@ -84,7 +84,7 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
|
||||
dest.writeParcelable(customIcon, flags);
|
||||
dest.writeLong(usageCount);
|
||||
dest.writeParcelable(parentGroupLastMod, flags);
|
||||
MemUtil.writeStringParcelableMap(dest, customData);
|
||||
// TODO MemUtil.writeStringParcelableMap(dest, customData);
|
||||
dest.writeByte((byte) (expires ? 1 : 0));
|
||||
dest.writeString(notes);
|
||||
dest.writeByte((byte) (isExpanded ? 1 : 0));
|
||||
@@ -169,14 +169,6 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public PwIconCustom getCustomIcon() {
|
||||
return customIcon;
|
||||
}
|
||||
|
||||
public void setCustomIcon(PwIconCustom icon) {
|
||||
this.customIcon = icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwGroupId getId() {
|
||||
return new PwGroupIdV4(uuid);
|
||||
@@ -225,13 +217,26 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
|
||||
|
||||
@Override
|
||||
public PwIcon getIcon() {
|
||||
if (customIcon == null || customIcon.uuid.equals(PwDatabase.UUID_ZERO)) {
|
||||
if (customIcon == null || customIcon.getUUID().equals(PwDatabase.UUID_ZERO)) {
|
||||
return super.getIcon();
|
||||
} else {
|
||||
return customIcon;
|
||||
}
|
||||
}
|
||||
|
||||
public PwIconCustom getIconCustom() {
|
||||
return customIcon;
|
||||
}
|
||||
|
||||
public void setIconCustom(PwIconCustom icon) {
|
||||
this.customIcon = icon;
|
||||
}
|
||||
|
||||
public void setIconStandard(PwIconStandard icon) { // TODO Encapsulate with PwEntryV4
|
||||
this.icon = icon;
|
||||
this.customIcon = PwIconCustom.ZERO;
|
||||
}
|
||||
|
||||
public void putCustomData(String key, String value) {
|
||||
customData.put(key, value);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ public abstract class PwIcon implements Parcelable {
|
||||
|
||||
protected PwIcon(Parcel in) {}
|
||||
|
||||
public abstract boolean isUnknown();
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
|
||||
@@ -26,8 +26,8 @@ import java.util.UUID;
|
||||
public class PwIconCustom extends PwIcon {
|
||||
public static final PwIconCustom ZERO = new PwIconCustom(PwDatabase.UUID_ZERO, new byte[0]);
|
||||
|
||||
public final UUID uuid;
|
||||
public byte[] imageData;
|
||||
private final UUID uuid;
|
||||
transient private byte[] imageData;
|
||||
|
||||
public PwIconCustom(UUID uuid, byte[] data) {
|
||||
super();
|
||||
@@ -44,13 +44,31 @@ public class PwIconCustom extends PwIcon {
|
||||
protected PwIconCustom(Parcel in) {
|
||||
super(in);
|
||||
uuid = (UUID) in.readSerializable();
|
||||
in.readByteArray(imageData);
|
||||
// TODO Take too much memories
|
||||
// in.readByteArray(imageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnknown() {
|
||||
return uuid == null || this.equals(ZERO);
|
||||
}
|
||||
|
||||
public UUID getUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public byte[] getImageData() {
|
||||
return imageData;
|
||||
}
|
||||
|
||||
public void setImageData(byte[] imageData) {
|
||||
this.imageData = imageData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeSerializable(uuid);
|
||||
dest.writeByteArray(imageData);
|
||||
// Too big for a parcelable dest.writeByteArray(imageData);
|
||||
}
|
||||
|
||||
public static final Creator<PwIconCustom> CREATOR = new Creator<PwIconCustom>() {
|
||||
@@ -65,7 +83,7 @@ public class PwIconCustom extends PwIcon {
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
|
||||
@@ -37,6 +37,10 @@ public class PwIconFactory {
|
||||
*/
|
||||
private ReferenceMap customCache = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
|
||||
|
||||
public PwIconStandard getUnknownIcon() {
|
||||
return getIcon(PwIconStandard.UNKNOWN);
|
||||
}
|
||||
|
||||
public PwIconStandard getKeyIcon() {
|
||||
return getIcon(PwIconStandard.KEY);
|
||||
}
|
||||
@@ -46,8 +50,8 @@ public class PwIconFactory {
|
||||
}
|
||||
|
||||
public PwIconStandard getFolderIcon() {
|
||||
return getIcon(PwIconStandard.FOLDER);
|
||||
}
|
||||
return getIcon(PwIconStandard.FOLDER);
|
||||
}
|
||||
|
||||
public PwIconStandard getIcon(int iconId) {
|
||||
PwIconStandard icon = (PwIconStandard) cache.get(iconId);
|
||||
@@ -71,25 +75,8 @@ public class PwIconFactory {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public PwIconCustom getIcon(UUID iconUuid, byte[] data) {
|
||||
PwIconCustom icon = (PwIconCustom) customCache.get(iconUuid);
|
||||
|
||||
if (icon == null) {
|
||||
icon = new PwIconCustom(iconUuid, data);
|
||||
customCache.put(iconUuid, icon);
|
||||
} else {
|
||||
icon.imageData = data;
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void setIconData(UUID iconUuid, byte[] data) {
|
||||
getIcon(iconUuid, data);
|
||||
}
|
||||
|
||||
public void put(PwIconCustom icon) {
|
||||
customCache.put(icon.uuid, icon);
|
||||
customCache.put(icon.getUUID(), icon);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,12 +22,17 @@ package com.kunzisoft.keepass.database;
|
||||
import android.os.Parcel;
|
||||
|
||||
public class PwIconStandard extends PwIcon {
|
||||
public final int iconId;
|
||||
private final int iconId;
|
||||
|
||||
public static final int UNKNOWN = -1;
|
||||
public static final int KEY = 0;
|
||||
public static final int TRASH = 43;
|
||||
public static final int FOLDER = 48;
|
||||
|
||||
public PwIconStandard() {
|
||||
this.iconId = KEY;
|
||||
}
|
||||
|
||||
public PwIconStandard(int iconId) {
|
||||
this.iconId = iconId;
|
||||
}
|
||||
@@ -42,6 +47,15 @@ public class PwIconStandard extends PwIcon {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnknown() {
|
||||
return iconId == UNKNOWN;
|
||||
}
|
||||
|
||||
public int getIconId() {
|
||||
return iconId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(iconId);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.joda.time.LocalDate;
|
||||
public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger, Parcelable, Cloneable {
|
||||
|
||||
protected Parent parent = null;
|
||||
protected PwIconStandard icon = new PwIconStandard(0);
|
||||
protected PwIconStandard icon = new PwIconStandard();
|
||||
protected PwDate creation = new PwDate();
|
||||
protected PwDate lastMod = new PwDate();
|
||||
protected PwDate lastAccess = new PwDate();
|
||||
@@ -119,22 +119,27 @@ public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger
|
||||
public abstract Type getType();
|
||||
|
||||
/**
|
||||
* @return Title to display as view
|
||||
* @return Title
|
||||
*/
|
||||
public abstract String getDisplayTitle();
|
||||
public abstract String getTitle();
|
||||
|
||||
/**
|
||||
* @return Title to display, typically return alternative title if {@link #getTitle()} is empty
|
||||
*/
|
||||
protected abstract String getVisualTitle();
|
||||
|
||||
/**
|
||||
* @return Visual icon
|
||||
*/
|
||||
public PwIcon getIcon() {
|
||||
return icon;
|
||||
return getIconStandard();
|
||||
}
|
||||
|
||||
public PwIconStandard getIconStandard() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void setIcon(PwIconStandard icon) {
|
||||
public void setIconStandard(PwIconStandard icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
@@ -210,7 +215,7 @@ public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger
|
||||
*/
|
||||
public boolean isContentVisuallyTheSame(PwNode o) {
|
||||
return getType().equals(o.getType())
|
||||
&& getDisplayTitle().equals(o.getDisplayTitle())
|
||||
&& getVisualTitle().equals(o.getVisualTitle())
|
||||
&& getIcon().equals(o.getIcon());
|
||||
}
|
||||
|
||||
|
||||
@@ -109,8 +109,8 @@ public enum SortNodeEnum {
|
||||
new EntryNameComparator(ascending),
|
||||
object1,
|
||||
object2,
|
||||
object1.getDisplayTitle()
|
||||
.compareToIgnoreCase(object2.getDisplayTitle()));
|
||||
object1.getTitle()
|
||||
.compareToIgnoreCase(object2.getTitle()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,9 +69,7 @@ public class LoadDatabaseRunnable extends RunnableOnFinish {
|
||||
public void run() {
|
||||
try {
|
||||
mDatabase.loadData(mContext, mUri, mPass, mKey, mStatus);
|
||||
|
||||
saveFileData(mUri, mKey);
|
||||
|
||||
} catch (ArcFourException e) {
|
||||
catchError(e, R.string.error_arc4);
|
||||
return;
|
||||
@@ -85,8 +83,10 @@ public class LoadDatabaseRunnable extends RunnableOnFinish {
|
||||
catchError(e, R.string.file_not_found);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Database can't be read", e);
|
||||
finish(false, e.getMessage());
|
||||
if (e.getMessage().contains("Hash failed with code"))
|
||||
catchError(e, R.string.error_load_database_KDF_memory, true);
|
||||
else
|
||||
catchError(e, R.string.error_load_database, true);
|
||||
return;
|
||||
} catch (KeyFileEmptyException e) {
|
||||
catchError(e, R.string.keyfile_is_empty);
|
||||
@@ -107,22 +107,24 @@ public class LoadDatabaseRunnable extends RunnableOnFinish {
|
||||
catchError(e, R.string.error_invalid_db);
|
||||
return;
|
||||
} catch (OutOfMemoryError e) {
|
||||
String errorMessage = mContext.getString(R.string.error_out_of_memory);
|
||||
Log.e(TAG, errorMessage, e);
|
||||
finish(false, errorMessage);
|
||||
catchError(e, R.string.error_out_of_memory);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Database can't be load", e);
|
||||
finish(false, e.getMessage());
|
||||
catchError(e, R.string.error_load_database, true);
|
||||
return;
|
||||
}
|
||||
|
||||
finish(true);
|
||||
}
|
||||
|
||||
private void catchError(Exception e, @StringRes int messageId) {
|
||||
private void catchError(Throwable e, @StringRes int messageId) {
|
||||
catchError(e, messageId, false);
|
||||
}
|
||||
|
||||
private void catchError(Throwable e, @StringRes int messageId, boolean addThrowableMessage) {
|
||||
String errorMessage = mContext.getString(messageId);
|
||||
Log.e(TAG, errorMessage, e);
|
||||
if (addThrowableMessage)
|
||||
errorMessage = errorMessage + " " + e.getLocalizedMessage();
|
||||
finish(false, errorMessage);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,15 +31,15 @@ import java.util.List;
|
||||
|
||||
public class DeleteGroupRunnable extends ActionNodeDatabaseRunnable {
|
||||
|
||||
private PwGroup<PwGroup, PwGroup, PwEntry> mGroupToDelete;
|
||||
private PwGroup<PwGroup, PwEntry> mGroupToDelete;
|
||||
private PwGroup mParent;
|
||||
private boolean mRecycle;
|
||||
|
||||
public DeleteGroupRunnable(Context ctx, Database db, PwGroup<PwGroup, PwGroup, PwEntry> group, AfterActionNodeOnFinish finish) {
|
||||
public DeleteGroupRunnable(Context ctx, Database db, PwGroup<PwGroup, PwEntry> group, AfterActionNodeOnFinish finish) {
|
||||
this(ctx, db, group, finish, false);
|
||||
}
|
||||
|
||||
public DeleteGroupRunnable(Context ctx, Database db, PwGroup<PwGroup, PwGroup, PwEntry> group, AfterActionNodeOnFinish finish, boolean dontSave) {
|
||||
public DeleteGroupRunnable(Context ctx, Database db, PwGroup<PwGroup, PwEntry> group, AfterActionNodeOnFinish finish, boolean dontSave) {
|
||||
super(ctx, db, finish, dontSave);
|
||||
mGroupToDelete = group;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.kunzisoft.keepass.database.cursor;
|
||||
|
||||
import android.database.MatrixCursor;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import com.kunzisoft.keepass.database.PwDatabase;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwEntryV3;
|
||||
import com.kunzisoft.keepass.database.PwEntryV4;
|
||||
import com.kunzisoft.keepass.database.PwIconCustom;
|
||||
import com.kunzisoft.keepass.database.PwIconFactory;
|
||||
import com.kunzisoft.keepass.database.PwIconStandard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class EntryCursor extends MatrixCursor {
|
||||
|
||||
private long entryId;
|
||||
public static final String _ID = BaseColumns._ID;
|
||||
public static final String COLUMN_INDEX_UUID_MOST_SIGNIFICANT_BITS = "UUID_most_significant_bits";
|
||||
public static final String COLUMN_INDEX_UUID_LEAST_SIGNIFICANT_BITS = "UUID_least_significant_bits";
|
||||
public static final String COLUMN_INDEX_TITLE = "title";
|
||||
public static final String COLUMN_INDEX_ICON_STANDARD = "icon_standard";
|
||||
public static final String COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS = "icon_custom_UUID_most_significant_bits";
|
||||
public static final String COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS = "icon_custom_UUID_least_significant_bits";
|
||||
public static final String COLUMN_INDEX_USERNAME = "username";
|
||||
public static final String COLUMN_INDEX_PASSWORD = "password";
|
||||
public static final String COLUMN_INDEX_URL = "URL";
|
||||
public static final String COLUMN_INDEX_NOTES = "notes";
|
||||
|
||||
private ExtraFieldCursor extraFieldCursor;
|
||||
|
||||
public EntryCursor() {
|
||||
super(new String[]{ _ID,
|
||||
COLUMN_INDEX_UUID_MOST_SIGNIFICANT_BITS,
|
||||
COLUMN_INDEX_UUID_LEAST_SIGNIFICANT_BITS,
|
||||
COLUMN_INDEX_TITLE,
|
||||
COLUMN_INDEX_ICON_STANDARD,
|
||||
COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS,
|
||||
COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS,
|
||||
COLUMN_INDEX_USERNAME,
|
||||
COLUMN_INDEX_PASSWORD,
|
||||
COLUMN_INDEX_URL,
|
||||
COLUMN_INDEX_NOTES});
|
||||
entryId = 0;
|
||||
extraFieldCursor = new ExtraFieldCursor();
|
||||
}
|
||||
|
||||
public void addEntry(PwEntryV3 entry) {
|
||||
addRow(new Object[] {entryId,
|
||||
entry.getUUID().getMostSignificantBits(),
|
||||
entry.getUUID().getLeastSignificantBits(),
|
||||
entry.getTitle(),
|
||||
entry.getIconStandard().getIconId(),
|
||||
PwDatabase.UUID_ZERO.getMostSignificantBits(),
|
||||
PwDatabase.UUID_ZERO.getLeastSignificantBits(),
|
||||
entry.getUsername(),
|
||||
entry.getPassword(),
|
||||
entry.getUrl(),
|
||||
entry.getNotes()});
|
||||
entryId++;
|
||||
}
|
||||
|
||||
public void addEntry(PwEntryV4 entry) {
|
||||
addRow(new Object[] {entryId,
|
||||
entry.getUUID().getMostSignificantBits(),
|
||||
entry.getUUID().getLeastSignificantBits(),
|
||||
entry.getTitle(),
|
||||
entry.getIconStandard().getIconId(),
|
||||
entry.getIconCustom().getUUID().getMostSignificantBits(),
|
||||
entry.getIconCustom().getUUID().getLeastSignificantBits(),
|
||||
entry.getUsername(),
|
||||
entry.getPassword(),
|
||||
entry.getUrl(),
|
||||
entry.getNotes()});
|
||||
|
||||
entry.getFields().doActionToAllCustomProtectedField((key, value) -> {
|
||||
extraFieldCursor.addExtraField(entryId, key, value);
|
||||
});
|
||||
|
||||
entryId++;
|
||||
}
|
||||
|
||||
private void populateEntryBaseVersion(PwEntry pwEntry, PwIconFactory iconFactory) {
|
||||
pwEntry.setUUID(
|
||||
new UUID(getLong(getColumnIndex(EntryCursor.COLUMN_INDEX_UUID_MOST_SIGNIFICANT_BITS)),
|
||||
getLong(getColumnIndex(EntryCursor.COLUMN_INDEX_UUID_LEAST_SIGNIFICANT_BITS))));
|
||||
pwEntry.setTitle(getString(getColumnIndex(EntryCursor.COLUMN_INDEX_TITLE)));
|
||||
|
||||
PwIconStandard iconStandard = iconFactory.getIcon(getInt(getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_STANDARD)));
|
||||
pwEntry.setIconStandard(iconStandard);
|
||||
|
||||
pwEntry.setUsername(getString(getColumnIndex(EntryCursor.COLUMN_INDEX_USERNAME)));
|
||||
pwEntry.setPassword(getString(getColumnIndex(EntryCursor.COLUMN_INDEX_PASSWORD)));
|
||||
pwEntry.setUrl(getString(getColumnIndex(EntryCursor.COLUMN_INDEX_URL)));
|
||||
pwEntry.setNotes(getString(getColumnIndex(EntryCursor.COLUMN_INDEX_NOTES)));
|
||||
}
|
||||
|
||||
public void populateEntry(PwEntryV3 pwEntry, PwIconFactory iconFactory) {
|
||||
populateEntryBaseVersion(pwEntry, iconFactory);
|
||||
}
|
||||
|
||||
public void populateEntry(PwEntryV4 pwEntry, PwIconFactory iconFactory) {
|
||||
populateEntryBaseVersion(pwEntry, iconFactory);
|
||||
|
||||
// Retrieve custom icon
|
||||
PwIconCustom iconCustom = iconFactory.getIcon(
|
||||
new UUID(getLong(getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS)),
|
||||
getLong(getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS))));
|
||||
pwEntry.setIconCustom(iconCustom);
|
||||
|
||||
// Retrieve extra fields
|
||||
if (extraFieldCursor.moveToFirst()) {
|
||||
while (!extraFieldCursor.isAfterLast()) {
|
||||
// Add a new extra field only if entryId is the one we want
|
||||
if (extraFieldCursor.getLong(extraFieldCursor.getColumnIndex(ExtraFieldCursor.FOREIGN_KEY_ENTRY_ID))
|
||||
== getLong(getColumnIndex(EntryCursor._ID))) {
|
||||
extraFieldCursor.populateExtraFieldInEntry(pwEntry);
|
||||
}
|
||||
extraFieldCursor.moveToNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.kunzisoft.keepass.database.cursor;
|
||||
|
||||
import android.database.MatrixCursor;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import com.kunzisoft.keepass.database.PwEntryV4;
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
|
||||
public class ExtraFieldCursor extends MatrixCursor {
|
||||
|
||||
private long fieldId;
|
||||
public static final String _ID = BaseColumns._ID;
|
||||
public static final String FOREIGN_KEY_ENTRY_ID = "entry_id";
|
||||
public static final String COLUMN_LABEL = "label";
|
||||
public static final String COLUMN_PROTECTION = "protection";
|
||||
public static final String COLUMN_VALUE = "value";
|
||||
|
||||
public ExtraFieldCursor() {
|
||||
super(new String[]{ _ID,
|
||||
FOREIGN_KEY_ENTRY_ID,
|
||||
COLUMN_LABEL,
|
||||
COLUMN_PROTECTION,
|
||||
COLUMN_VALUE});
|
||||
fieldId = 0;
|
||||
}
|
||||
|
||||
public synchronized void addExtraField(long entryId, String label, ProtectedString value) {
|
||||
addRow(new Object[] {fieldId,
|
||||
entryId,
|
||||
label,
|
||||
(value.isProtected()) ? 1 : 0,
|
||||
value.toString()});
|
||||
fieldId++;
|
||||
}
|
||||
|
||||
public void populateExtraFieldInEntry(PwEntryV4 pwEntry) {
|
||||
|
||||
pwEntry.addExtraField(getString(getColumnIndex(ExtraFieldCursor.COLUMN_LABEL)),
|
||||
new ProtectedString((getInt(getColumnIndex(ExtraFieldCursor.COLUMN_PROTECTION)) > 0),
|
||||
getString(getColumnIndex(ExtraFieldCursor.COLUMN_VALUE))));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,8 @@ package com.kunzisoft.keepass.database.iterator;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwEntryV3;
|
||||
import com.kunzisoft.keepass.database.PwEntryV4;
|
||||
import com.kunzisoft.keepass.database.SearchParameters;
|
||||
import com.kunzisoft.keepass.database.SearchParametersV4;
|
||||
import com.kunzisoft.keepass.database.search.SearchParameters;
|
||||
import com.kunzisoft.keepass.database.search.SearchParametersV4;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.kunzisoft.keepass.database.iterator;
|
||||
|
||||
import com.kunzisoft.keepass.database.PwEntryV3;
|
||||
import com.kunzisoft.keepass.database.SearchParameters;
|
||||
import com.kunzisoft.keepass.database.search.SearchParameters;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.kunzisoft.keepass.database.iterator;
|
||||
|
||||
import com.kunzisoft.keepass.database.PwEntryV4;
|
||||
import com.kunzisoft.keepass.database.SearchParametersV4;
|
||||
import com.kunzisoft.keepass.database.search.SearchParametersV4;
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
|
||||
import java.util.Iterator;
|
||||
@@ -78,18 +78,19 @@ public class EntrySearchStringIteratorV4 extends EntrySearchStringIterator {
|
||||
}
|
||||
|
||||
private boolean searchInField(String key) {
|
||||
if (key.equals(PwEntryV4.STR_TITLE)) {
|
||||
return sp.searchInTitles;
|
||||
} else if (key.equals(PwEntryV4.STR_USERNAME)) {
|
||||
return sp.searchInUserNames;
|
||||
} else if (key.equals(PwEntryV4.STR_PASSWORD)) {
|
||||
return sp.searchInPasswords;
|
||||
} else if (key.equals(PwEntryV4.STR_URL)) {
|
||||
return sp.searchInUrls;
|
||||
} else if (key.equals(PwEntryV4.STR_NOTES)) {
|
||||
return sp.searchInNotes;
|
||||
} else {
|
||||
return sp.searchInOther;
|
||||
switch (key) {
|
||||
case PwEntryV4.STR_TITLE:
|
||||
return sp.searchInTitles;
|
||||
case PwEntryV4.STR_USERNAME:
|
||||
return sp.searchInUserNames;
|
||||
case PwEntryV4.STR_PASSWORD:
|
||||
return sp.searchInPasswords;
|
||||
case PwEntryV4.STR_URL:
|
||||
return sp.searchInUrls;
|
||||
case PwEntryV4.STR_NOTES:
|
||||
return sp.searchInNotes;
|
||||
default:
|
||||
return sp.searchInOther;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -316,7 +316,7 @@ public class ImporterV3 extends Importer {
|
||||
grp.setExpiryTime(new PwDate(buf, offset));
|
||||
break;
|
||||
case 0x0007 :
|
||||
grp.setIcon(db.getIconFactory().getIcon(LEDataInputStream.readInt(buf, offset)));
|
||||
grp.setIconStandard(db.getIconFactory().getIcon(LEDataInputStream.readInt(buf, offset)));
|
||||
break;
|
||||
case 0x0008 :
|
||||
grp.setLevel(LEDataInputStream.readUShort(buf, offset));
|
||||
@@ -353,7 +353,7 @@ public class ImporterV3 extends Importer {
|
||||
iconId = 0;
|
||||
}
|
||||
|
||||
ent.setIcon(db.getIconFactory().getIcon(iconId));
|
||||
ent.setIconStandard(db.getIconFactory().getIcon(iconId));
|
||||
break;
|
||||
case 0x0004 :
|
||||
ent.setTitle(Types.readCString(buf, offset));
|
||||
|
||||
@@ -556,9 +556,9 @@ public class ImporterV4 extends Importer {
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemNotes) ) {
|
||||
ctxGroup.setNotes(ReadString(xpp));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemIcon) ) {
|
||||
ctxGroup.setIcon(db.getIconFactory().getIcon((int)ReadUInt(xpp, 0)));
|
||||
ctxGroup.setIconStandard(db.getIconFactory().getIcon((int)ReadUInt(xpp, 0)));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemCustomIconID) ) {
|
||||
ctxGroup.setCustomIcon(db.getIconFactory().getIcon(ReadUuid(xpp)));
|
||||
ctxGroup.setIconCustom(db.getIconFactory().getIcon(ReadUuid(xpp)));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemTimes) ) {
|
||||
return SwitchContext(ctx, KdbContext.GroupTimes, xpp);
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemIsExpanded) ) {
|
||||
@@ -611,9 +611,9 @@ public class ImporterV4 extends Importer {
|
||||
if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemUuid) ) {
|
||||
ctxEntry.setUUID(ReadUuid(xpp));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemIcon) ) {
|
||||
ctxEntry.setIcon(db.getIconFactory().getIcon((int)ReadUInt(xpp, 0)));
|
||||
ctxEntry.setIconStandard(db.getIconFactory().getIcon((int)ReadUInt(xpp, 0)));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemCustomIconID) ) {
|
||||
ctxEntry.setCustomIcon(db.getIconFactory().getIcon(ReadUuid(xpp)));
|
||||
ctxEntry.setIconCustom(db.getIconFactory().getIcon(ReadUuid(xpp)));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemFgColor) ) {
|
||||
ctxEntry.setForegroundColor(ReadString(xpp));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemBgColor) ) {
|
||||
|
||||
@@ -350,10 +350,10 @@ public class PwDbV4Output extends PwDbOutput<PwDbHeaderV4> {
|
||||
writeObject(PwDatabaseV4XML.ElemUuid, group.getUUID());
|
||||
writeObject(PwDatabaseV4XML.ElemName, group.getName());
|
||||
writeObject(PwDatabaseV4XML.ElemNotes, group.getNotes());
|
||||
writeObject(PwDatabaseV4XML.ElemIcon, group.getIconStandard().iconId);
|
||||
writeObject(PwDatabaseV4XML.ElemIcon, group.getIconStandard().getIconId());
|
||||
|
||||
if (!group.getCustomIcon().equals(PwIconCustom.ZERO)) {
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconID, group.getCustomIcon().uuid);
|
||||
if (!group.getIconCustom().equals(PwIconCustom.ZERO)) {
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconID, group.getIconCustom().getUUID());
|
||||
}
|
||||
|
||||
writeList(PwDatabaseV4XML.ElemTimes, group);
|
||||
@@ -375,10 +375,10 @@ public class PwDbV4Output extends PwDbOutput<PwDbHeaderV4> {
|
||||
xml.startTag(null, PwDatabaseV4XML.ElemEntry);
|
||||
|
||||
writeObject(PwDatabaseV4XML.ElemUuid, entry.getUUID());
|
||||
writeObject(PwDatabaseV4XML.ElemIcon, entry.getIconStandard().iconId);
|
||||
writeObject(PwDatabaseV4XML.ElemIcon, entry.getIconStandard().getIconId());
|
||||
|
||||
if (!entry.getCustomIcon().equals(PwIconCustom.ZERO)) {
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconID, entry.getCustomIcon().uuid);
|
||||
if (!entry.getIconCustom().equals(PwIconCustom.ZERO)) {
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconID, entry.getIconCustom().getUUID());
|
||||
}
|
||||
|
||||
writeObject(PwDatabaseV4XML.ElemFgColor, entry.getForegroundColor());
|
||||
@@ -701,8 +701,8 @@ public class PwDbV4Output extends PwDbOutput<PwDbHeaderV4> {
|
||||
for (PwIconCustom icon : customIcons) {
|
||||
xml.startTag(null, PwDatabaseV4XML.ElemCustomIconItem);
|
||||
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconItemID, icon.uuid);
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconItemData, String.valueOf(Base64Coder.encode(icon.imageData)));
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconItemID, icon.getUUID());
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconItemData, String.valueOf(Base64Coder.encode(icon.getImageData())));
|
||||
|
||||
xml.endTag(null, PwDatabaseV4XML.ElemCustomIconItem);
|
||||
}
|
||||
|
||||
@@ -79,12 +79,12 @@ public class PwEntryOutputV3 {
|
||||
// Group ID
|
||||
mOS.write(GROUPID_FIELD_TYPE);
|
||||
mOS.write(LONG_FOUR);
|
||||
mOS.write(LEDataOutputStream.writeIntBuf(mPE.getGroupId()));
|
||||
mOS.write(LEDataOutputStream.writeIntBuf(mPE.getParent().getGroupId()));
|
||||
|
||||
// Image ID
|
||||
mOS.write(IMAGEID_FIELD_TYPE);
|
||||
mOS.write(LONG_FOUR);
|
||||
mOS.write(LEDataOutputStream.writeIntBuf(mPE.getIconStandard().iconId));
|
||||
mOS.write(LEDataOutputStream.writeIntBuf(mPE.getIconStandard().getIconId()));
|
||||
|
||||
// Title
|
||||
//byte[] title = mPE.title.getBytes("UTF-8");
|
||||
|
||||
@@ -93,7 +93,7 @@ public class PwGroupOutputV3 {
|
||||
// Image ID
|
||||
mOS.write(IMAGEID_FIELD_TYPE);
|
||||
mOS.write(IMAGEID_FIELD_SIZE);
|
||||
mOS.write(LEDataOutputStream.writeIntBuf(mPG.getIconStandard().iconId));
|
||||
mOS.write(LEDataOutputStream.writeIntBuf(mPG.getIconStandard().getIconId()));
|
||||
|
||||
// Level
|
||||
mOS.write(LEVEL_FIELD_TYPE);
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
package com.kunzisoft.keepass.database.search;
|
||||
|
||||
import com.kunzisoft.keepass.database.EntryHandler;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator;
|
||||
|
||||
import java.util.Date;
|
||||
@@ -17,7 +17,10 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
package com.kunzisoft.keepass.database.search;
|
||||
|
||||
import com.kunzisoft.keepass.database.EntryHandler;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -17,8 +17,11 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
package com.kunzisoft.keepass.database.search;
|
||||
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwEntryV4;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.utils.StrUtil;
|
||||
import com.kunzisoft.keepass.utils.UuidUtil;
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
package com.kunzisoft.keepass.database.search;
|
||||
|
||||
import com.kunzisoft.keepass.database.EntryHandler;
|
||||
import com.kunzisoft.keepass.database.PwEntryV4;
|
||||
import com.kunzisoft.keepass.database.PwGroupV4;
|
||||
import com.kunzisoft.keepass.utils.StrUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.search;
|
||||
package com.kunzisoft.keepass.database.search;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -42,7 +42,7 @@ import java.util.Locale;
|
||||
import java.util.Queue;
|
||||
|
||||
public class SearchDbHelper<PwDatabaseVersion extends PwDatabase<PwGroupSearch, PwEntrySearch>,
|
||||
PwGroupSearch extends PwGroup<PwGroupSearch, PwGroupSearch, PwEntrySearch>,
|
||||
PwGroupSearch extends PwGroup<PwGroupSearch, PwEntrySearch>,
|
||||
PwEntrySearch extends PwEntry<PwGroupSearch>> {
|
||||
|
||||
private final Context mCtx;
|
||||
@@ -54,31 +54,33 @@ public class SearchDbHelper<PwDatabaseVersion extends PwDatabase<PwGroupSearch,
|
||||
private boolean omitBackup() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mCtx);
|
||||
return prefs.getBoolean(mCtx.getString(R.string.omitbackup_key), mCtx.getResources().getBoolean(R.bool.omitbackup_default));
|
||||
|
||||
}
|
||||
|
||||
public PwGroupSearch search(PwDatabaseVersion pm, String qStr) {
|
||||
|
||||
public PwGroupSearch search(PwDatabaseVersion pm, String qStr, int max) {
|
||||
|
||||
PwGroupSearch group = pm.createGroup();
|
||||
group.setName(mCtx.getString(R.string.search_results));
|
||||
group.setName("\"" + qStr + "\"");
|
||||
group.setEntries(new ArrayList<>());
|
||||
|
||||
// Search all entries
|
||||
Locale loc = Locale.getDefault();
|
||||
qStr = qStr.toLowerCase(loc);
|
||||
boolean isOmitBackup = omitBackup();
|
||||
|
||||
|
||||
// TODO Search from the current group
|
||||
Queue<PwGroupSearch> worklist = new LinkedList<>();
|
||||
if (pm.getRootGroup() != null) {
|
||||
worklist.add(pm.getRootGroup());
|
||||
}
|
||||
|
||||
|
||||
while (worklist.size() != 0) {
|
||||
PwGroupSearch top = worklist.remove();
|
||||
|
||||
if (pm.isGroupSearchable(top, isOmitBackup)) {
|
||||
for (PwEntrySearch entry : top.getChildEntries()) {
|
||||
processEntries(entry, group.getChildEntries(), qStr, loc);
|
||||
if (group.numbersOfChildEntries() >= max)
|
||||
return group;
|
||||
}
|
||||
|
||||
for (PwGroupSearch childGroup : top.getChildGroups()) {
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
package com.kunzisoft.keepass.database.search;
|
||||
|
||||
/**
|
||||
* @author bpellin
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
package com.kunzisoft.keepass.database.search;
|
||||
|
||||
public class SearchParametersV4 extends SearchParameters implements Cloneable {
|
||||
public static SearchParametersV4 DEFAULT = new SearchParametersV4();
|
||||
@@ -35,9 +35,9 @@ import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.database.PwIcon;
|
||||
import com.kunzisoft.keepass.database.PwNode;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
|
||||
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION;
|
||||
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE;
|
||||
@@ -49,9 +49,11 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
public static final String TAG_CREATE_GROUP = "TAG_CREATE_GROUP";
|
||||
|
||||
public static final String KEY_NAME = "KEY_NAME";
|
||||
public static final String KEY_ICON_ID = "KEY_ICON_ID";
|
||||
public static final String KEY_ICON = "KEY_ICON";
|
||||
public static final String KEY_ACTION_ID = "KEY_ACTION_ID";
|
||||
|
||||
private Database database;
|
||||
|
||||
private EditGroupListener editGroupListener;
|
||||
|
||||
private EditGroupDialogAction editGroupDialogAction;
|
||||
@@ -59,6 +61,7 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
private PwIcon iconGroup;
|
||||
|
||||
private ImageView iconButton;
|
||||
private int iconColor;
|
||||
|
||||
public enum EditGroupDialogAction {
|
||||
CREATION, UPDATE, NONE;
|
||||
@@ -76,10 +79,10 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public static GroupEditDialogFragment build(PwNode group) {
|
||||
public static GroupEditDialogFragment build(PwGroup group) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_NAME, group.getDisplayTitle());
|
||||
bundle.putParcelable(KEY_ICON_ID, group.getIcon());
|
||||
bundle.putString(KEY_NAME, group.getName());
|
||||
bundle.putParcelable(KEY_ICON, group.getIcon());
|
||||
bundle.putInt(KEY_ACTION_ID, UPDATE.ordinal());
|
||||
GroupEditDialogFragment fragment = new GroupEditDialogFragment();
|
||||
fragment.setArguments(bundle);
|
||||
@@ -112,20 +115,21 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
// Retrieve the textColor to tint the icon
|
||||
int[] attrs = {android.R.attr.textColorPrimary};
|
||||
TypedArray ta = getActivity().getTheme().obtainStyledAttributes(attrs);
|
||||
int iconColor = ta.getColor(0, Color.WHITE);
|
||||
iconColor = ta.getColor(0, Color.WHITE);
|
||||
|
||||
// Init elements
|
||||
database = App.getDB();
|
||||
editGroupDialogAction = EditGroupDialogAction.NONE;
|
||||
nameGroup = "";
|
||||
iconGroup = App.getDB().getPwDatabase().getIconFactory().getFolderIcon();
|
||||
iconGroup = database.getPwDatabase().getIconFactory().getFolderIcon();
|
||||
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(KEY_ACTION_ID)
|
||||
&& savedInstanceState.containsKey(KEY_NAME)
|
||||
&& savedInstanceState.containsKey(KEY_ICON_ID)) {
|
||||
&& savedInstanceState.containsKey(KEY_ICON)) {
|
||||
editGroupDialogAction = getActionFromOrdinal(savedInstanceState.getInt(KEY_ACTION_ID));
|
||||
nameGroup = savedInstanceState.getString(KEY_NAME);
|
||||
iconGroup = savedInstanceState.getParcelable(KEY_ICON_ID);
|
||||
iconGroup = savedInstanceState.getParcelable(KEY_ICON);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -135,30 +139,16 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
|
||||
if (getArguments() != null
|
||||
&& getArguments().containsKey(KEY_NAME)
|
||||
&& getArguments().containsKey(KEY_ICON_ID)) {
|
||||
&& getArguments().containsKey(KEY_ICON)) {
|
||||
nameGroup = getArguments().getString(KEY_NAME);
|
||||
iconGroup = getArguments().getParcelable(KEY_ICON_ID);
|
||||
iconGroup = getArguments().getParcelable(KEY_ICON);
|
||||
}
|
||||
}
|
||||
|
||||
// populate the name
|
||||
nameField.setText(nameGroup);
|
||||
// populate the icon
|
||||
if (IconPackChooser.getSelectedIconPack(getContext()).tintable()) {
|
||||
App.getDB().getDrawFactory()
|
||||
.assignDatabaseIconTo(
|
||||
getContext(),
|
||||
iconButton,
|
||||
iconGroup,
|
||||
true,
|
||||
iconColor);
|
||||
} else {
|
||||
App.getDB().getDrawFactory()
|
||||
.assignDatabaseIconTo(
|
||||
getContext(),
|
||||
iconButton,
|
||||
iconGroup);
|
||||
}
|
||||
assignIconView();
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setView(root)
|
||||
@@ -195,18 +185,26 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void assignIconView() {
|
||||
database.getDrawFactory()
|
||||
.assignDatabaseIconTo(
|
||||
getContext(),
|
||||
iconButton,
|
||||
iconGroup,
|
||||
iconColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void iconPicked(Bundle bundle) {
|
||||
int selectedIconID = bundle.getInt(IconPickerDialogFragment.KEY_ICON_ID);
|
||||
iconButton.setImageResource(IconPackChooser.getSelectedIconPack(getContext()).iconToResId(selectedIconID));
|
||||
iconGroup = App.getDB().getPwDatabase().getIconFactory().getIcon(selectedIconID);
|
||||
iconGroup = bundle.getParcelable(IconPickerDialogFragment.KEY_ICON_STANDARD);
|
||||
assignIconView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putInt(KEY_ACTION_ID, editGroupDialogAction.ordinal());
|
||||
outState.putString(KEY_NAME, nameGroup);
|
||||
outState.putParcelable(KEY_ICON_ID, iconGroup);
|
||||
outState.putParcelable(KEY_ICON, iconGroup);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,14 +37,16 @@ import android.widget.GridView;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.database.PwIconStandard;
|
||||
import com.kunzisoft.keepass.icons.IconPack;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.stylish.StylishActivity;
|
||||
|
||||
|
||||
public class IconPickerDialogFragment extends DialogFragment {
|
||||
public static final String KEY_ICON_ID = "icon_id";
|
||||
public static final int UNDEFINED_ICON_ID = -1;
|
||||
|
||||
public static final String KEY_ICON_STANDARD = "KEY_ICON_STANDARD";
|
||||
|
||||
private IconPickerListener iconPickerListener;
|
||||
private IconPack iconPack;
|
||||
|
||||
@@ -85,7 +87,7 @@ public class IconPickerDialogFragment extends DialogFragment {
|
||||
|
||||
currIconGridView.setOnItemClickListener((parent, v, position, id) -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(KEY_ICON_ID, position);
|
||||
bundle.putParcelable(KEY_ICON_STANDARD, new PwIconStandard(position));
|
||||
iconPickerListener.iconPicked(bundle);
|
||||
dismiss();
|
||||
});
|
||||
|
||||
@@ -65,52 +65,50 @@ public class IconDrawableFactory {
|
||||
private ReferenceMap standardIconMap = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
|
||||
|
||||
/**
|
||||
* Assign a default database icon to an ImageView
|
||||
* Assign a default database icon to an ImageView and tint it if needed
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param iv ImageView that will host the drawable
|
||||
* @param iconView ImageView that will host the drawable
|
||||
* @param tintColor Use this color to tint tintable icon
|
||||
*/
|
||||
public void assignDefaultDatabaseIconTo(Context context, ImageView iv) {
|
||||
assignDefaultDatabaseIconTo(context, iv, false, Color.WHITE);
|
||||
public void assignDefaultDatabaseIconTo(Context context, ImageView iconView, int tintColor) {
|
||||
if (IconPackChooser.getSelectedIconPack(context).tintable()) {
|
||||
assignDrawableTo(context,
|
||||
iconView,
|
||||
IconPackChooser.getSelectedIconPack(context).getDefaultIconId(),
|
||||
true,
|
||||
tintColor);
|
||||
} else {
|
||||
assignDrawableTo(context,
|
||||
iconView,
|
||||
IconPackChooser.getSelectedIconPack(context).getDefaultIconId(),
|
||||
false,
|
||||
Color.WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a default database icon to an ImageView and tint it
|
||||
* Assign a database icon to an ImageView and tint it if needed
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param iv ImageView that will host the drawable
|
||||
*/
|
||||
public void assignDefaultDatabaseIconTo(Context context, ImageView iv, boolean tint, int tintColor) {
|
||||
assignDrawableTo(context, iv, IconPackChooser.getSelectedIconPack(context).getDefaultIconId(), tint, tintColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a database icon to an ImageView
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param iv ImageView that will host the drawable
|
||||
* @param iconView ImageView that will host the drawable
|
||||
* @param icon The icon from the database
|
||||
* @param tintColor Use this color to tint tintable icon
|
||||
*/
|
||||
public void assignDatabaseIconTo(Context context, ImageView iv, PwIcon icon) {
|
||||
assignDatabaseIconTo(context, iv, icon, false, Color.WHITE);
|
||||
public void assignDatabaseIconTo(Context context, ImageView iconView, PwIcon icon, int tintColor) {
|
||||
if (IconPackChooser.getSelectedIconPack(context).tintable()) {
|
||||
assignDrawableToImageView(getIconDrawable(context, icon, true, tintColor),
|
||||
iconView,
|
||||
true,
|
||||
tintColor);
|
||||
} else {
|
||||
assignDrawableToImageView(getIconDrawable(context, icon, true, tintColor),
|
||||
iconView,
|
||||
false,
|
||||
Color.WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a database icon to an ImageView and tint it
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param imageView ImageView that will host the drawable
|
||||
* @param icon The icon from the database
|
||||
* @param tint true will tint the drawable with tintColor
|
||||
* @param tintColor Use this color if tint is true
|
||||
*/
|
||||
public void assignDatabaseIconTo(Context context, ImageView imageView, PwIcon icon, boolean tint, int tintColor) {
|
||||
assignDrawableToImageView(getIconDrawable(context, icon, tint, tintColor),
|
||||
imageView,
|
||||
tint,
|
||||
tintColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an image by its resourceId to an ImageView and tint it
|
||||
*
|
||||
@@ -221,7 +219,7 @@ public class IconDrawableFactory {
|
||||
* @return The drawable
|
||||
*/
|
||||
private Drawable getIconDrawable(Context context, PwIconStandard icon, boolean isTint, int tintColor) {
|
||||
int resId = IconPackChooser.getSelectedIconPack(context).iconToResId(icon.iconId);
|
||||
int resId = IconPackChooser.getSelectedIconPack(context).iconToResId(icon.getIconId());
|
||||
|
||||
return getIconDrawable(context, resId, isTint, tintColor);
|
||||
}
|
||||
@@ -289,14 +287,14 @@ public class IconDrawableFactory {
|
||||
return blank;
|
||||
}
|
||||
|
||||
Drawable draw = (Drawable) customIconMap.get(icon.uuid);
|
||||
Drawable draw = (Drawable) customIconMap.get(icon.getUUID());
|
||||
|
||||
if (draw == null) {
|
||||
if (icon.imageData == null) {
|
||||
if (icon.getImageData() == null) {
|
||||
return blank;
|
||||
}
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(icon.imageData, 0, icon.imageData.length);
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(icon.getImageData(), 0, icon.getImageData().length);
|
||||
|
||||
// Could not understand custom icon
|
||||
if (bitmap == null) {
|
||||
@@ -306,7 +304,7 @@ public class IconDrawableFactory {
|
||||
bitmap = resize(bitmap);
|
||||
|
||||
draw = new BitmapDrawable(context.getResources(), bitmap);
|
||||
customIconMap.put(icon.uuid, draw);
|
||||
customIconMap.put(icon.getUUID(), draw);
|
||||
}
|
||||
|
||||
return draw;
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
import com.kunzisoft.keepass.stylish.StylishActivity;
|
||||
@@ -45,6 +46,7 @@ public abstract class LockingActivity extends StylishActivity {
|
||||
private LockReceiver lockReceiver;
|
||||
private boolean exitLock;
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
/**
|
||||
* Called to start a record time,
|
||||
@@ -72,6 +74,9 @@ public abstract class LockingActivity extends StylishActivity {
|
||||
lockReceiver = null;
|
||||
|
||||
exitLock = false;
|
||||
|
||||
readOnly = false;
|
||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrIntent(savedInstanceState, getIntent());
|
||||
}
|
||||
|
||||
public static void checkShutdown(Activity activity) {
|
||||
@@ -116,6 +121,12 @@ public abstract class LockingActivity extends StylishActivity {
|
||||
TimeoutHelper.recordTime(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
@@ -239,11 +239,13 @@ public class NotificationCopyingService extends Service {
|
||||
}
|
||||
countingDownTask = null;
|
||||
notificationManager.cancel(myNotificationId);
|
||||
try {
|
||||
clipboardHelper.cleanClipboard();
|
||||
} catch (SamsungClipboardException e) {
|
||||
Log.e(TAG, "Clipboard can't be cleaned", e);
|
||||
}
|
||||
// Clean password only if no next field
|
||||
if (nextFields.size() <= 0)
|
||||
try {
|
||||
clipboardHelper.cleanClipboard();
|
||||
} catch (SamsungClipboardException e) {
|
||||
Log.e(TAG, "Clipboard can't be cleaned", e);
|
||||
}
|
||||
});
|
||||
countingDownTask.start();
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.GroupActivity;
|
||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
import com.kunzisoft.keepass.activities.IntentBuildLauncher;
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.autofill.AutofillHelper;
|
||||
import com.kunzisoft.keepass.compat.ClipDataCompat;
|
||||
@@ -69,6 +69,8 @@ import com.kunzisoft.keepass.fileselect.KeyFileHelper;
|
||||
import com.kunzisoft.keepass.fingerprint.FingerPrintAnimatedVector;
|
||||
import com.kunzisoft.keepass.fingerprint.FingerPrintExplanationDialog;
|
||||
import com.kunzisoft.keepass.fingerprint.FingerPrintHelper;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
import com.kunzisoft.keepass.stylish.StylishActivity;
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment;
|
||||
@@ -124,6 +126,8 @@ public class PasswordActivity extends StylishActivity
|
||||
private CompoundButton checkboxDefaultDatabaseView;
|
||||
private CompoundButton.OnCheckedChangeListener enableButtonOncheckedChangeListener;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
private DefaultCheckChange defaultCheckChange;
|
||||
private ValidateButtonViewClickListener validateButtonViewClickListener;
|
||||
|
||||
@@ -139,16 +143,23 @@ public class PasswordActivity extends StylishActivity
|
||||
}
|
||||
|
||||
public static void launch(
|
||||
Activity act,
|
||||
Activity activity,
|
||||
String fileName,
|
||||
String keyFile) throws FileNotFoundException {
|
||||
verifyFileNameUriFromLaunch(fileName);
|
||||
|
||||
Intent intent = new Intent(act, PasswordActivity.class);
|
||||
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
||||
// only to avoid visible flickering when redirecting
|
||||
activity.startActivityForResult(intent, RESULT_CANCELED);
|
||||
});
|
||||
}
|
||||
|
||||
private static void buildAndLaunchIntent(Activity activity, String fileName, String keyFile,
|
||||
IntentBuildLauncher intentBuildLauncher) {
|
||||
Intent intent = new Intent(activity, PasswordActivity.class);
|
||||
intent.putExtra(UriIntentInitTask.KEY_FILENAME, fileName);
|
||||
intent.putExtra(UriIntentInitTask.KEY_KEYFILE, keyFile);
|
||||
// only to avoid visible flickering when redirecting
|
||||
act.startActivityForResult(intent, RESULT_CANCELED);
|
||||
intentBuildLauncher.startActivityForResult(intent);
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(
|
||||
@@ -158,17 +169,16 @@ public class PasswordActivity extends StylishActivity
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(
|
||||
Activity act,
|
||||
Activity activity,
|
||||
String fileName,
|
||||
String keyFile) throws FileNotFoundException {
|
||||
verifyFileNameUriFromLaunch(fileName);
|
||||
|
||||
Intent intent = new Intent(act, PasswordActivity.class);
|
||||
intent.putExtra(UriIntentInitTask.KEY_FILENAME, fileName);
|
||||
intent.putExtra(UriIntentInitTask.KEY_KEYFILE, keyFile);
|
||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
||||
// only to avoid visible flickering when redirecting
|
||||
act.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
||||
// only to avoid visible flickering when redirecting
|
||||
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
});
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@@ -181,20 +191,19 @@ public class PasswordActivity extends StylishActivity
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void launchForAutofillResult(
|
||||
Activity act,
|
||||
Activity activity,
|
||||
String fileName,
|
||||
String keyFile,
|
||||
AssistStructure assistStructure) throws FileNotFoundException {
|
||||
verifyFileNameUriFromLaunch(fileName);
|
||||
|
||||
if ( assistStructure != null ) {
|
||||
Intent intent = new Intent(act, PasswordActivity.class);
|
||||
intent.putExtra(UriIntentInitTask.KEY_FILENAME, fileName);
|
||||
intent.putExtra(UriIntentInitTask.KEY_KEYFILE, keyFile);
|
||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
||||
act.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
||||
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
});
|
||||
} else {
|
||||
launch(act, fileName, keyFile);
|
||||
launch(activity, fileName, keyFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +285,8 @@ public class PasswordActivity extends StylishActivity
|
||||
checkboxKeyfileView = findViewById(R.id.keyfile_checkox);
|
||||
checkboxDefaultDatabaseView = findViewById(R.id.default_database);
|
||||
|
||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrPreference(this, savedInstanceState);
|
||||
|
||||
View browseView = findViewById(R.id.browse_button);
|
||||
keyFileHelper = new KeyFileHelper(PasswordActivity.this);
|
||||
browseView.setOnClickListener(keyFileHelper.getOpenFileOnClickViewListener());
|
||||
@@ -326,8 +337,6 @@ public class PasswordActivity extends StylishActivity
|
||||
autofillHelper = new AutofillHelper();
|
||||
autofillHelper.retrieveAssistStructure(getIntent());
|
||||
}
|
||||
|
||||
checkAndPerformedEducation();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -380,11 +389,17 @@ public class PasswordActivity extends StylishActivity
|
||||
.execute(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and display learning views
|
||||
* Displays the explanation for a database opening with fingerprints if available
|
||||
*/
|
||||
private void checkAndPerformedEducation() {
|
||||
private void checkAndPerformedEducation(Menu menu) {
|
||||
if (PreferencesUtil.isEducationScreensEnabled(this)) {
|
||||
|
||||
if (!PreferencesUtil.isEducationUnlockPerformed(this)) {
|
||||
@@ -394,7 +409,7 @@ public class PasswordActivity extends StylishActivity
|
||||
getString(R.string.education_unlock_title),
|
||||
getString(R.string.education_unlock_summary))
|
||||
.dimColor(R.color.green)
|
||||
.icon(ContextCompat.getDrawable(this, R.mipmap.ic_launcher_round))
|
||||
.icon(ContextCompat.getDrawable(getApplicationContext(), R.mipmap.ic_launcher_round))
|
||||
.textColorInt(Color.WHITE)
|
||||
.tintTarget(false)
|
||||
.cancelable(true),
|
||||
@@ -402,6 +417,44 @@ public class PasswordActivity extends StylishActivity
|
||||
@Override
|
||||
public void onTargetClick(TapTargetView view) {
|
||||
super.onTargetClick(view);
|
||||
performedReadOnlyEducation(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOuterCircleClick(TapTargetView view) {
|
||||
super.onOuterCircleClick(view);
|
||||
view.dismiss(false);
|
||||
performedReadOnlyEducation(menu);
|
||||
|
||||
}
|
||||
});
|
||||
// TODO make a period for donation
|
||||
PreferencesUtil.saveEducationPreference(PasswordActivity.this,
|
||||
R.string.education_unlock_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and display learning views
|
||||
* Displays read-only if available
|
||||
*/
|
||||
private void performedReadOnlyEducation(Menu menu) {
|
||||
if (!PreferencesUtil.isEducationReadOnlyPerformed(this)) {
|
||||
try {
|
||||
TapTargetView.showFor(this,
|
||||
TapTarget.forToolbarMenuItem(toolbar, R.id.menu_open_file_read_mode_key,
|
||||
getString(R.string.education_read_only_title),
|
||||
getString(R.string.education_read_only_summary))
|
||||
.textColorInt(Color.WHITE)
|
||||
.tintTarget(true)
|
||||
.cancelable(true),
|
||||
new TapTargetView.Listener() {
|
||||
@Override
|
||||
public void onTargetClick(TapTargetView view) {
|
||||
super.onTargetClick(view);
|
||||
MenuItem editItem = menu.findItem(R.id.menu_open_file_read_mode_key);
|
||||
onOptionsItemSelected(editItem);
|
||||
checkAndPerformedEducationForFingerprint();
|
||||
}
|
||||
|
||||
@@ -410,11 +463,13 @@ public class PasswordActivity extends StylishActivity
|
||||
super.onOuterCircleClick(view);
|
||||
view.dismiss(false);
|
||||
checkAndPerformedEducationForFingerprint();
|
||||
|
||||
}
|
||||
});
|
||||
// TODO make a period for donation
|
||||
PreferencesUtil.saveEducationPreference(PasswordActivity.this, R.string.education_unlock_key);
|
||||
PreferencesUtil.saveEducationPreference(this,
|
||||
R.string.education_read_only_key);
|
||||
} catch (Exception e) {
|
||||
// If icon not visible
|
||||
Log.w(TAG, "Can't performed education for entry's edition");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -953,14 +1008,14 @@ public class PasswordActivity extends StylishActivity
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
assistStructure = autofillHelper.getAssistStructure();
|
||||
if (assistStructure != null) {
|
||||
GroupActivity.launchForAutofillResult(PasswordActivity.this, assistStructure);
|
||||
GroupActivity.launchForAutofillResult(PasswordActivity.this, assistStructure, readOnly);
|
||||
}
|
||||
}
|
||||
if (assistStructure == null) {
|
||||
if (entrySelectionMode) {
|
||||
GroupActivity.launchForKeyboardResult(PasswordActivity.this);
|
||||
GroupActivity.launchForKeyboardResult(PasswordActivity.this, readOnly);
|
||||
} else {
|
||||
GroupActivity.launch(PasswordActivity.this);
|
||||
GroupActivity.launch(PasswordActivity.this, readOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -968,16 +1023,35 @@ public class PasswordActivity extends StylishActivity
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
// Read menu
|
||||
inflater.inflate(R.menu.open_file, menu);
|
||||
changeOpenFileReadIcon(menu.findItem(R.id.menu_open_file_read_mode_key));
|
||||
|
||||
MenuUtil.defaultMenuInflater(inflater, menu);
|
||||
|
||||
// Fingerprint menu
|
||||
if (!fingerprintMustBeConfigured
|
||||
&& prefsNoBackup.contains(getPreferenceKeyValue()) )
|
||||
inflater.inflate(R.menu.fingerprint, menu);
|
||||
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
// Show education views
|
||||
new Handler().post(() -> checkAndPerformedEducation(menu));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void changeOpenFileReadIcon(MenuItem togglePassword) {
|
||||
if ( readOnly ) {
|
||||
togglePassword.setTitle(R.string.menu_file_selection_read_only);
|
||||
togglePassword.setIcon(R.drawable.ic_read_only_white_24dp);
|
||||
} else {
|
||||
togglePassword.setTitle(R.string.menu_open_file_read_and_write);
|
||||
togglePassword.setIcon(R.drawable.ic_read_write_white_24dp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
||||
@@ -985,6 +1059,10 @@ public class PasswordActivity extends StylishActivity
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
break;
|
||||
case R.id.menu_open_file_read_mode_key:
|
||||
readOnly = !readOnly;
|
||||
changeOpenFileReadIcon(item);
|
||||
break;
|
||||
case R.id.menu_fingerprint_remove_key:
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
deleteEntryKey();
|
||||
|
||||
@@ -1,117 +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 3 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.kunzisoft.keepass.search;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.ListNodesActivity;
|
||||
import com.kunzisoft.keepass.activities.ListNodesFragment;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.utils.MenuUtil;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SearchResultsActivity extends ListNodesActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(getLayoutInflater().inflate(R.layout.search_results, null));
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(getString(R.string.search_label));
|
||||
setSupportActionBar(toolbar);
|
||||
assert getSupportActionBar() != null;
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
groupNameView = findViewById(R.id.group_name);
|
||||
|
||||
attachFragmentToContentView();
|
||||
|
||||
View notFoundView = findViewById(R.id.not_found_container);
|
||||
View listContainer = findViewById(R.id.nodes_list_fragment_container);
|
||||
|
||||
if ( mCurrentGroup == null || mCurrentGroup.numbersOfChildEntries() < 1 ) {
|
||||
listContainer.setVisibility(View.GONE);
|
||||
notFoundView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
listContainer.setVisibility(View.VISIBLE);
|
||||
notFoundView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeListNodesFragment(PwGroup currentGroup) {
|
||||
listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
|
||||
.findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
|
||||
// Directly get group and not id
|
||||
if (listNodesFragment == null)
|
||||
listNodesFragment = ListNodesFragment.newInstance(currentGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PwGroup retrieveCurrentGroup(@Nullable Bundle savedInstanceState) {
|
||||
Database mDb = App.getDB();
|
||||
// Likely the app has been killed exit the activity
|
||||
if ( ! mDb.getLoaded() ) {
|
||||
finish();
|
||||
}
|
||||
return mDb.search(getSearchStr(getIntent()).trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
MenuUtil.contributionMenuInflater(inflater, menu);
|
||||
inflater.inflate(R.menu.default_menu, menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch ( item.getItemId() ) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private String getSearchStr(Intent queryIntent) {
|
||||
// get and process search query here
|
||||
final String queryAction = queryIntent.getAction();
|
||||
if ( Intent.ACTION_SEARCH.equals(queryAction) ) {
|
||||
return queryIntent.getStringExtra(SearchManager.QUERY);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.dialogs.ProFeatureDialogFragment;
|
||||
@@ -72,6 +73,9 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
private static final int REQUEST_CODE_AUTOFILL = 5201;
|
||||
|
||||
private Database database;
|
||||
private boolean databaseReadOnly;
|
||||
|
||||
private int count = 0;
|
||||
|
||||
private Preference roundPref;
|
||||
@@ -79,14 +83,24 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
private Preference parallelismPref;
|
||||
|
||||
public static NestedSettingsFragment newInstance(Screen key) {
|
||||
return newInstance(key, ReadOnlyHelper.READ_ONLY_DEFAULT);
|
||||
}
|
||||
|
||||
public static NestedSettingsFragment newInstance(Screen key, boolean databaseReadOnly) {
|
||||
NestedSettingsFragment fragment = new NestedSettingsFragment();
|
||||
// supply arguments to bundle.
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(TAG_KEY, key.ordinal());
|
||||
ReadOnlyHelper.putReadOnlyInBundle(args, databaseReadOnly);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@@ -110,6 +124,10 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
if (getArguments() != null)
|
||||
key = getArguments().getInt(TAG_KEY);
|
||||
|
||||
database = App.getDB();
|
||||
databaseReadOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState, getArguments());
|
||||
databaseReadOnly = database.isReadOnly() || databaseReadOnly;
|
||||
|
||||
// Load the preferences from an XML resource
|
||||
switch (Screen.values()[key]) {
|
||||
case APPLICATION:
|
||||
@@ -306,23 +324,22 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
case DATABASE:
|
||||
setPreferencesFromResource(R.xml.database_preferences, rootKey);
|
||||
|
||||
Database db = App.getDB();
|
||||
if (db.getLoaded()) {
|
||||
if (database.getLoaded()) {
|
||||
|
||||
PreferenceCategory dbGeneralPrefCategory = (PreferenceCategory) findPreference(getString(R.string.database_general_key));
|
||||
|
||||
// Db name
|
||||
Preference dbNamePref = findPreference(getString(R.string.database_name_key));
|
||||
if ( db.containsName() ) {
|
||||
dbNamePref.setSummary(db.getName());
|
||||
if ( database.containsName() ) {
|
||||
dbNamePref.setSummary(database.getName());
|
||||
} else {
|
||||
dbGeneralPrefCategory.removePreference(dbNamePref);
|
||||
}
|
||||
|
||||
// Db description
|
||||
Preference dbDescriptionPref = findPreference(getString(R.string.database_description_key));
|
||||
if ( db.containsDescription() ) {
|
||||
dbDescriptionPref.setSummary(db.getDescription());
|
||||
if ( database.containsDescription() ) {
|
||||
dbDescriptionPref.setSummary(database.getDescription());
|
||||
} else {
|
||||
dbGeneralPrefCategory.removePreference(dbDescriptionPref);
|
||||
}
|
||||
@@ -331,9 +348,9 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
SwitchPreference recycleBinPref = (SwitchPreference) findPreference(getString(R.string.recycle_bin_key));
|
||||
// TODO Recycle
|
||||
dbGeneralPrefCategory.removePreference(recycleBinPref); // To delete
|
||||
if (db.isRecycleBinAvailable()) {
|
||||
if (database.isRecycleBinAvailable()) {
|
||||
|
||||
recycleBinPref.setChecked(db.isRecycleBinEnabled());
|
||||
recycleBinPref.setChecked(database.isRecycleBinEnabled());
|
||||
recycleBinPref.setEnabled(false);
|
||||
} else {
|
||||
dbGeneralPrefCategory.removePreference(recycleBinPref);
|
||||
@@ -341,27 +358,27 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
// Version
|
||||
Preference dbVersionPref = findPreference(getString(R.string.database_version_key));
|
||||
dbVersionPref.setSummary(db.getVersion());
|
||||
dbVersionPref.setSummary(database.getVersion());
|
||||
|
||||
// Encryption Algorithm
|
||||
Preference algorithmPref = findPreference(getString(R.string.encryption_algorithm_key));
|
||||
algorithmPref.setSummary(db.getEncryptionAlgorithmName(getResources()));
|
||||
algorithmPref.setSummary(database.getEncryptionAlgorithmName(getResources()));
|
||||
|
||||
// Key derivation function
|
||||
Preference kdfPref = findPreference(getString(R.string.key_derivation_function_key));
|
||||
kdfPref.setSummary(db.getKeyDerivationName(getResources()));
|
||||
kdfPref.setSummary(database.getKeyDerivationName(getResources()));
|
||||
|
||||
// Round encryption
|
||||
roundPref = findPreference(getString(R.string.transform_rounds_key));
|
||||
roundPref.setSummary(db.getNumberKeyEncryptionRoundsAsString());
|
||||
roundPref.setSummary(database.getNumberKeyEncryptionRoundsAsString());
|
||||
|
||||
// Memory Usage
|
||||
memoryPref = findPreference(getString(R.string.memory_usage_key));
|
||||
memoryPref.setSummary(db.getMemoryUsageAsString());
|
||||
memoryPref.setSummary(database.getMemoryUsageAsString());
|
||||
|
||||
// Parallelism
|
||||
parallelismPref = findPreference(getString(R.string.parallelism_key));
|
||||
parallelismPref.setSummary(db.getParallelismAsString());
|
||||
parallelismPref.setSummary(database.getParallelismAsString());
|
||||
|
||||
} else {
|
||||
Log.e(getClass().getName(), "Database isn't ready");
|
||||
@@ -480,18 +497,16 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
assert getFragmentManager() != null;
|
||||
|
||||
DialogFragment dialogFragment = null;
|
||||
boolean otherDialogFragment = false;
|
||||
|
||||
DialogFragment dialogFragment = null;
|
||||
if (preference.getKey().equals(getString(R.string.database_name_key))) {
|
||||
dialogFragment = DatabaseNamePreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.database_description_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.database_description_key))) {
|
||||
dialogFragment = DatabaseDescriptionPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.encryption_algorithm_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.encryption_algorithm_key))) {
|
||||
dialogFragment = DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.key_derivation_function_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.key_derivation_function_key))) {
|
||||
DatabaseKeyDerivationPreferenceDialogFragmentCompat keyDerivationDialogFragment = DatabaseKeyDerivationPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
// Add other prefs to manage
|
||||
if (roundPref != null)
|
||||
@@ -501,24 +516,23 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
if (parallelismPref != null)
|
||||
keyDerivationDialogFragment.setParallelismPreference(parallelismPref);
|
||||
dialogFragment = keyDerivationDialogFragment;
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.transform_rounds_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.transform_rounds_key))) {
|
||||
dialogFragment = RoundsPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.memory_usage_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.memory_usage_key))) {
|
||||
dialogFragment = MemoryUsagePreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.parallelism_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.parallelism_key))) {
|
||||
dialogFragment = ParallelismPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
} else {
|
||||
otherDialogFragment = true;
|
||||
}
|
||||
|
||||
if (dialogFragment != null) {
|
||||
if (dialogFragment != null && !databaseReadOnly) {
|
||||
dialogFragment.setTargetFragment(this, 0);
|
||||
dialogFragment.show(getFragmentManager(), null);
|
||||
}
|
||||
|
||||
// Could not be handled here. Try with the super method.
|
||||
else {
|
||||
else if (otherDialogFragment) {
|
||||
super.onDisplayPreferenceDialog(preference);
|
||||
}
|
||||
}
|
||||
@@ -538,6 +552,12 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, databaseReadOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
// TODO encapsulate
|
||||
|
||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.settings;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||
@@ -54,9 +55,22 @@ public class PreferencesUtil {
|
||||
sharedPreferencesEditor.apply();
|
||||
}
|
||||
|
||||
public static boolean showUsernamesListEntries(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
return prefs.getBoolean(context.getString(R.string.list_entries_show_username_key),
|
||||
context.getResources().getBoolean(R.bool.list_entries_show_username_default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the text size in SP, verify the integrity of the size stored in preference
|
||||
*/
|
||||
public static float getListTextSize(Context ctx) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
return Float.parseFloat(prefs.getString(ctx.getString(R.string.list_size_key), ctx.getString(R.string.list_size_default)));
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
String defaultSizeString = ctx.getString(R.string.list_size_default);
|
||||
String listSize = prefs.getString(ctx.getString(R.string.list_size_key), defaultSizeString);
|
||||
if (!Arrays.asList(ctx.getResources().getStringArray(R.array.list_size_values)).contains(listSize))
|
||||
listSize = defaultSizeString;
|
||||
return Float.parseFloat(listSize);
|
||||
}
|
||||
|
||||
public static int getDefaultPasswordLength(Context ctx) {
|
||||
@@ -139,12 +153,26 @@ public class PreferencesUtil {
|
||||
ctx.getResources().getBoolean(R.bool.auto_open_file_uri_default));
|
||||
}
|
||||
|
||||
public static boolean isFirstTimeAskAllowCopyPasswordAndProtectedFields(Context ctx) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
return prefs.getBoolean(ctx.getString(R.string.allow_copy_password_first_time_key),
|
||||
ctx.getResources().getBoolean(R.bool.allow_copy_password_first_time_default));
|
||||
}
|
||||
|
||||
public static boolean allowCopyPasswordAndProtectedFields(Context ctx) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
return prefs.getBoolean(ctx.getString(R.string.allow_copy_password_key),
|
||||
ctx.getResources().getBoolean(R.bool.allow_copy_password_default));
|
||||
}
|
||||
|
||||
public static void setAllowCopyPasswordAndProtectedFields(Context ctx, boolean allowCopy) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
prefs.edit()
|
||||
.putBoolean(ctx.getString(R.string.allow_copy_password_first_time_key), false)
|
||||
.putBoolean(ctx.getString(R.string.allow_copy_password_key), allowCopy)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static String getIconPackSelectedId(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
return prefs.getString(
|
||||
@@ -158,6 +186,12 @@ public class PreferencesUtil {
|
||||
context.getResources().getBoolean(R.bool.allow_no_password_default));
|
||||
}
|
||||
|
||||
public static boolean enableReadOnlyDatabase(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
return prefs.getBoolean(context.getString(R.string.enable_read_only_key),
|
||||
context.getResources().getBoolean(R.bool.enable_read_only_default));
|
||||
}
|
||||
|
||||
/**
|
||||
* All preference keys associated with education
|
||||
*/
|
||||
@@ -166,6 +200,7 @@ public class PreferencesUtil {
|
||||
R.string.education_select_db_key,
|
||||
R.string.education_open_link_db_key,
|
||||
R.string.education_unlock_key,
|
||||
R.string.education_read_only_key,
|
||||
R.string.education_search_key,
|
||||
R.string.education_new_node_key,
|
||||
R.string.education_sort_key,
|
||||
@@ -245,6 +280,18 @@ public class PreferencesUtil {
|
||||
context.getResources().getBoolean(R.bool.education_unlock_default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the explanatory view of the database read-only has already been displayed.
|
||||
*
|
||||
* @param context The context to open the SharedPreferences
|
||||
* @return boolean value of education_read_only_key key
|
||||
*/
|
||||
public static boolean isEducationReadOnlyPerformed(Context context) {
|
||||
SharedPreferences prefs = getEducationSharedPreferences(context);
|
||||
return prefs.getBoolean(context.getString(R.string.education_read_only_key),
|
||||
context.getResources().getBoolean(R.bool.education_read_only_default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the explanatory view of search has already been displayed.
|
||||
*
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.support.v7.widget.Toolbar;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
|
||||
|
||||
@@ -39,17 +40,18 @@ public class SettingsActivity extends LockingActivity implements MainPreferenceF
|
||||
|
||||
private Toolbar toolbar;
|
||||
|
||||
public static void launch(Activity activity) {
|
||||
Intent i = new Intent(activity, SettingsActivity.class);
|
||||
activity.startActivity(i);
|
||||
public static void launch(Activity activity, boolean readOnly) {
|
||||
Intent intent = new Intent(activity, SettingsActivity.class);
|
||||
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void launch(Activity activity, boolean checkLock) {
|
||||
public static void launch(Activity activity, boolean readOnly, boolean checkLock) {
|
||||
// To avoid flickering when launch settings in a LockingActivity
|
||||
if (!checkLock)
|
||||
launch(activity);
|
||||
launch(activity, readOnly);
|
||||
else if (LockingActivity.checkTimeIsAllowedOrFinish(activity)) {
|
||||
launch(activity);
|
||||
launch(activity, readOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +116,7 @@ public class SettingsActivity extends LockingActivity implements MainPreferenceF
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
|
||||
R.anim.slide_in_left, R.anim.slide_out_right)
|
||||
.replace(R.id.fragment_container, NestedSettingsFragment.newInstance(key), TAG_NESTED)
|
||||
.replace(R.id.fragment_container, NestedSettingsFragment.newInstance(key, readOnly), TAG_NESTED)
|
||||
.addToBackStack(TAG_NESTED)
|
||||
.commit();
|
||||
|
||||
|
||||
@@ -88,8 +88,8 @@ public class ProgressTaskDialogFragment extends DialogFragment implements Progre
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
Util.unlockScreenOrientation(getActivity());
|
||||
super.onDismiss(dialog);
|
||||
}
|
||||
|
||||
public static void stop(AppCompatActivity activity) {
|
||||
|
||||
@@ -32,6 +32,8 @@ import com.kunzisoft.keepass.activities.AboutActivity;
|
||||
import com.kunzisoft.keepass.settings.SettingsActivity;
|
||||
import com.kunzisoft.keepass.stylish.StylishActivity;
|
||||
|
||||
import static com.kunzisoft.keepass.activities.ReadOnlyHelper.READ_ONLY_DEFAULT;
|
||||
|
||||
|
||||
public class MenuUtil {
|
||||
|
||||
@@ -56,20 +58,20 @@ public class MenuUtil {
|
||||
}
|
||||
|
||||
public static boolean onDefaultMenuOptionsItemSelected(StylishActivity activity, MenuItem item) {
|
||||
return onDefaultMenuOptionsItemSelected(activity, item, false);
|
||||
return onDefaultMenuOptionsItemSelected(activity, item, READ_ONLY_DEFAULT, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* @param checkLock Check the time lock before launch settings in LockingActivity
|
||||
*/
|
||||
public static boolean onDefaultMenuOptionsItemSelected(StylishActivity activity, MenuItem item, boolean checkLock) {
|
||||
public static boolean onDefaultMenuOptionsItemSelected(StylishActivity activity, MenuItem item, boolean readOnly, boolean checkLock) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_contribute:
|
||||
return onContributionItemSelected(activity);
|
||||
|
||||
case R.id.menu_app_settings:
|
||||
// To avoid flickering when launch settings in a LockingActivity
|
||||
SettingsActivity.launch(activity, checkLock);
|
||||
SettingsActivity.launch(activity, readOnly, checkLock);
|
||||
return true;
|
||||
|
||||
case R.id.menu_about:
|
||||
|
||||
@@ -19,13 +19,12 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.utils;
|
||||
|
||||
import com.kunzisoft.keepass.database.EntrySearchV4;
|
||||
import com.kunzisoft.keepass.database.PwDatabase;
|
||||
import com.kunzisoft.keepass.database.PwDatabaseV4;
|
||||
import com.kunzisoft.keepass.database.PwEntry;
|
||||
import com.kunzisoft.keepass.database.PwEntryV4;
|
||||
import com.kunzisoft.keepass.database.PwGroupV4;
|
||||
import com.kunzisoft.keepass.database.SearchParametersV4;
|
||||
import com.kunzisoft.keepass.database.search.EntrySearchV4;
|
||||
import com.kunzisoft.keepass.database.search.SearchParametersV4;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -158,7 +157,7 @@ public class SprEngineV4 {
|
||||
|
||||
List<PwEntryV4> list = new ArrayList<>();
|
||||
// TODO type parameter
|
||||
EntrySearchV4 entrySearchV4 = new EntrySearchV4((PwGroupV4) ctx.db.getRootGroup());
|
||||
EntrySearchV4 entrySearchV4 = new EntrySearchV4(ctx.db.getRootGroup());
|
||||
entrySearchV4.searchEntries(sp, list);
|
||||
|
||||
if (list.size() > 0) {
|
||||
|
||||
@@ -27,9 +27,12 @@ import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -74,6 +77,10 @@ public class Util {
|
||||
applyFontVisibilityTo(context, (TextView) editText);
|
||||
}
|
||||
|
||||
public static float getListTextDefaultSize(Context context) {
|
||||
return Float.parseFloat(context.getString(R.string.list_size_default));
|
||||
}
|
||||
|
||||
public static void lockScreenOrientation(Activity activity) {
|
||||
if (activity != null) {
|
||||
int currentOrientation = activity.getResources().getConfiguration().orientation;
|
||||
@@ -86,7 +93,8 @@ public class Util {
|
||||
}
|
||||
|
||||
public static void unlockScreenOrientation(Activity activity) {
|
||||
if (activity != null)
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
|
||||
if (activity != null) {
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@ public class AddNodeButtonView extends RelativeLayout {
|
||||
this.addEntryEnable = enable;
|
||||
if (enable && addEntryView != null && addEntryView.getVisibility() != VISIBLE)
|
||||
addEntryView.setVisibility(INVISIBLE);
|
||||
disableViewIfNoAddAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,6 +178,19 @@ public class AddNodeButtonView extends RelativeLayout {
|
||||
this.addGroupEnable = enable;
|
||||
if (enable && addGroupView != null && addGroupView.getVisibility() != VISIBLE)
|
||||
addGroupView.setVisibility(INVISIBLE);
|
||||
disableViewIfNoAddAvailable();
|
||||
}
|
||||
|
||||
private void disableViewIfNoAddAvailable() {
|
||||
if (!addEntryEnable || !addGroupEnable) {
|
||||
setVisibility(GONE);
|
||||
} else {
|
||||
setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return getVisibility() == VISIBLE;
|
||||
}
|
||||
|
||||
public void setAddGroupClickListener(OnClickListener onClickListener) {
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
package com.kunzisoft.keepass.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -39,6 +42,7 @@ import java.util.Date;
|
||||
public class EntryContentsView extends LinearLayout {
|
||||
|
||||
private boolean fontInVisibility;
|
||||
private int colorAccent;
|
||||
|
||||
private View userNameContainerView;
|
||||
private TextView userNameView;
|
||||
@@ -77,6 +81,11 @@ public class EntryContentsView extends LinearLayout {
|
||||
timeFormat = android.text.format.DateFormat.getTimeFormat(context);
|
||||
|
||||
inflate(context);
|
||||
|
||||
int[] attrColorAccent = {R.attr.colorAccentCompat};
|
||||
TypedArray taColorAccent = context.getTheme().obtainStyledAttributes(attrColorAccent);
|
||||
this.colorAccent = taColorAccent.getColor(0, Color.BLACK);
|
||||
taColorAccent.recycle();
|
||||
}
|
||||
|
||||
private void inflate(Context context) {
|
||||
@@ -129,21 +138,26 @@ public class EntryContentsView extends LinearLayout {
|
||||
return userNameContainerView.getVisibility() == VISIBLE;
|
||||
}
|
||||
|
||||
public void assignPassword(String password) {
|
||||
public void assignPassword(String password, boolean allowCopyPassword) {
|
||||
if (password != null && !password.isEmpty()) {
|
||||
passwordContainerView.setVisibility(VISIBLE);
|
||||
passwordView.setText(password);
|
||||
if (fontInVisibility)
|
||||
Util.applyFontVisibilityTo(getContext(), passwordView);
|
||||
passwordActionView.setVisibility(GONE);
|
||||
if (!allowCopyPassword) {
|
||||
passwordActionView.setColorFilter(ContextCompat.getColor(getContext(), R.color.grey_dark));
|
||||
} else {
|
||||
passwordActionView.setColorFilter(colorAccent);
|
||||
}
|
||||
} else {
|
||||
passwordContainerView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void assignPasswordCopyListener(OnClickListener onClickListener) {
|
||||
if (onClickListener == null)
|
||||
setClickable(false);
|
||||
passwordActionView.setOnClickListener(onClickListener);
|
||||
passwordActionView.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
public boolean isPasswordPresent() {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package com.kunzisoft.keepass.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
@@ -62,10 +63,12 @@ public class EntryCustomField extends LinearLayout {
|
||||
setLabel(label);
|
||||
setValue(value);
|
||||
|
||||
if (!showAction) {
|
||||
actionImageView.setVisibility(INVISIBLE);
|
||||
} else {
|
||||
if (showAction) {
|
||||
actionImageView.setEnabled(true);
|
||||
setAction(onClickActionListener);
|
||||
} else {
|
||||
actionImageView.setEnabled(false);
|
||||
actionImageView.setColorFilter(ContextCompat.getColor(getContext(), R.color.grey_dark));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,55 +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 3 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.kunzisoft.keepass.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
|
||||
public class GroupHeaderView extends RelativeLayout {
|
||||
|
||||
public GroupHeaderView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public GroupHeaderView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
inflate(context);
|
||||
}
|
||||
|
||||
private void inflate(Context context) {
|
||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
assert inflater != null;
|
||||
inflater.inflate(R.layout.group_header, this);
|
||||
|
||||
if (App.getDB().isReadOnly()) {
|
||||
View readOnlyIndicator = findViewById(R.id.read_only);
|
||||
readOnlyIndicator.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
24
app/src/main/res/anim/slide_in_bottom.xml
Normal file
24
app/src/main/res/anim/slide_in_bottom.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/* //device/apps/common/res/anim/slide_in_right.xml
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromYDelta="100%p" android:toYDelta="0"
|
||||
android:duration="@integer/animation_duration"/>
|
||||
</set>
|
||||
24
app/src/main/res/anim/slide_in_top.xml
Normal file
24
app/src/main/res/anim/slide_in_top.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/* //device/apps/common/res/anim/slide_in_left.xml
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromYDelta="-100%p" android:toYDelta="0"
|
||||
android:duration="@integer/animation_duration"/>
|
||||
</set>
|
||||
24
app/src/main/res/anim/slide_out_bottom.xml
Normal file
24
app/src/main/res/anim/slide_out_bottom.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/* //device/apps/common/res/anim/slide_out_right.xml
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromYDelta="0" android:toYDelta="100%p"
|
||||
android:duration="@integer/animation_duration"/>
|
||||
</set>
|
||||
24
app/src/main/res/anim/slide_out_top.xml
Normal file
24
app/src/main/res/anim/slide_out_top.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/* //device/apps/common/res/anim/slide_out_left.xml
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromYDelta="0" android:toYDelta="-100%p"
|
||||
android:duration="@integer/animation_duration"/>
|
||||
</set>
|
||||
19
app/src/main/res/drawable/ic_read_only_white_24dp.xml
Normal file
19
app/src/main/res/drawable/ic_read_only_white_24dp.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:width="24dp"
|
||||
android:height="24dp">
|
||||
<group
|
||||
android:translateY="-8">
|
||||
<group
|
||||
android:scaleX="1.777778"
|
||||
android:scaleY="1.777778"
|
||||
android:translateX="-205.4844"
|
||||
android:translateY="-31.99788">
|
||||
<path
|
||||
android:pathData="M125.00684 31.305444l0 -6.644528c0 -0.263013 -0.21159 -0.47461 -0.4746 -0.47461l-6.48633 0c-1.04808 0 -1.89843 0.850344 -1.89843 1.898435l0 6.328127c0 1.048093 0.85035 1.898437 1.89843 1.898437l6.48633 0c0.26301 0 0.4746 -0.2116 0.4746 -0.474611l0 -0.316409c0 -0.148311 -0.0692 -0.282785 -0.176 -0.369792 -0.083 -0.304543 -0.083 -1.172685 0 -1.477229 0.10684 -0.08504 0.176 -0.219501 0.176 -0.36782zm-6.32812 -4.469236c0 -0.06529 0.0534 -0.118652 0.11866 -0.118652l4.19238 0c0.0653 0 0.11866 0.05343 0.11866 0.118652l0 0.39551c0 0.06529 -0.0534 0.118653 -0.11866 0.118653l-4.19238 0c-0.0653 0 -0.11866 -0.05343 -0.11866 -0.118653l0 -0.39551zm0 1.265621c0 -0.06529 0.0534 -0.118653 0.11866 -0.118653l4.19238 0c0.0653 0 0.11866 0.05343 0.11866 0.118653l0 0.395509c0 0.06529 -0.0534 0.118653 -0.11866 0.118653l-4.19238 0c-0.0653 0 -0.11866 -0.05342 -0.11866 -0.118653l0 -0.395509zm5.0111 4.943847l-5.64391 0c-0.35003 0 -0.63282 -0.282781 -0.63282 -0.632808 0 -0.348045 0.28476 -0.632813 0.63282 -0.632813l5.64391 0c-0.0375 0.338162 -0.0375 0.927466 0 1.265621z"
|
||||
android:fillColor="#ffffff" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
25
app/src/main/res/drawable/ic_read_write_white_24dp.xml
Normal file
25
app/src/main/res/drawable/ic_read_write_white_24dp.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:width="24dp"
|
||||
android:height="24dp">
|
||||
<group
|
||||
android:translateY="-8">
|
||||
<group
|
||||
android:scaleX="1.777778"
|
||||
android:scaleY="1.777778"
|
||||
android:translateX="-205.4844"
|
||||
android:translateY="-31.99788">
|
||||
<group
|
||||
android:scaleX="0.5625"
|
||||
android:scaleY="0.5625"
|
||||
android:translateX="115.585"
|
||||
android:translateY="22.49881">
|
||||
<path
|
||||
android:pathData="M4.375 3C2.5117466 3 1 4.5117271 1 6.375l0 11.25C1 19.488276 2.5117466 21 4.375 21l11.53125 0C16.373823 21 16.75 20.623825 16.75 20.15625l0 -0.5625c0 -0.263664 -0.122669 -0.503524 -0.3125 -0.658203 -0.147556 -0.54141 -0.147556 -2.08359 0 -2.625 0.189938 -0.151182 0.3125 -0.390619 0.3125 -0.654297l0 -0.669922 -2.378906 2.378906c-0.0089 0.500068 -0.0036 1.014773 0.03711 1.384766l-1.525391 0 -3.0507808 0.667969C9.333649 19.527124 8.7483479 19.391267 8.3632812 19.005859 8.2870146 18.929486 8.2287106 18.840044 8.171875 18.75L4.375 18.75C3.7527244 18.75 3.25 18.24727 3.25 17.625 3.25 17.006253 3.7562267 16.5 4.375 16.5l3.8027344 0L8.6503906 14.349609 12.125 10.875l-6.4140625 0C5.5948486 10.875 5.5 10.780031 5.5 10.664062l0 -0.7031245C5.5 9.8448664 5.5949375 9.75 5.7109375 9.75l7.4531245 0c0.02365 0 0.03921 0.018137 0.06055 0.025391L16.550781 6.4492188 16.75 6.25l0 -2.40625C16.75 3.3761713 16.373823 3 15.90625 3L4.375 3Zm16.015625 1.5898438c-0.30546 0.033979 -0.623906 0.1844704 -0.882813 0.4433593l-1.183593 1.1835938 2.828125 2.828125 1.183594 -1.1835938c0.517848 -0.5180889 0.601704 -1.2752558 0.1875 -1.6894531L21.195312 4.8457031C20.988219 4.6386018 20.696085 4.5558644 20.390625 4.5898438ZM17.320312 7.21875L9.6464844 14.894531 9.015625 17.767578c-0.08448 0.384462 0.1995577 0.670133 0.5839844 0.585938L12.472656 17.724609 20.148438 10.046875 17.320312 7.21875ZM5.7109375 7.5L13.164062 7.5C13.280151 7.5 13.375 7.594987 13.375 7.7109375l0 0.703125C13.375 8.5301336 13.28008 8.625 13.164062 8.625l-7.4531245 0C5.5948486 8.625 5.5 8.5300127 5.5 8.4140625l0 -0.703125C5.5 7.5948664 5.5949375 7.5 5.7109375 7.5Z"
|
||||
android:fillColor="#ffffff" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -32,6 +32,6 @@
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="18dp"
|
||||
android:layout_toStartOf="@+id/fingerprint_image"
|
||||
style="@style/KeepassDXStyle.TextAppearance.DefaultTextOnPrimary"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Default.TextOnPrimary"
|
||||
android:gravity="center_vertical|start" />
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
style="@style/KeepassDXStyle.TextAppearance.TitleTextOnPrimary" />
|
||||
style="@style/KeepassDXStyle.TextAppearance.Title.TextOnPrimary" />
|
||||
</LinearLayout>
|
||||
</android.support.v7.widget.Toolbar>
|
||||
|
||||
|
||||
@@ -1,52 +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 3 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/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView android:id="@+id/read_only"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/read_only"
|
||||
android:visibility="gone"
|
||||
style="@style/KeepassDXStyle.TextAppearance.WarningTextStyle" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/list_margin"
|
||||
android:layout_marginEnd="@dimen/list_margin">
|
||||
<android.support.v7.widget.AppCompatImageView android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:scaleType="fitXY" />
|
||||
<android.support.v7.widget.AppCompatTextView android:id="@+id/group_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/root"
|
||||
android:maxLines="1"
|
||||
style="@style/KeepassDXStyle.TextAppearance.TitleTextOnPrimary" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -36,14 +36,32 @@
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true" />
|
||||
<TextView
|
||||
android:id="@+id/entry_text"
|
||||
android:layout_height="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Default"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_toRightOf="@+id/entry_icon"
|
||||
android:layout_toEndOf="@+id/entry_icon" />
|
||||
android:layout_toEndOf="@+id/entry_icon">
|
||||
<TextView
|
||||
android:id="@+id/entry_text"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Default" /> <!-- style override -->
|
||||
<TextView
|
||||
android:id="@+id/entry_subtext"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Secondary" /> <!-- style override -->
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -1,6 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/nodes_list"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/windowBackground" />
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:id="@+id/not_found_container"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/not_found_img"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/img_not_found"/>
|
||||
<TextView
|
||||
android:id="@+id/not_found_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_results"/>
|
||||
</LinearLayout>
|
||||
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/nodes_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/windowBackground" />
|
||||
</FrameLayout>
|
||||
|
||||
@@ -50,14 +50,29 @@
|
||||
android:layout_toRightOf="@+id/group_arrow"
|
||||
android:layout_toEndOf="@+id/group_arrow" />
|
||||
|
||||
<TextView android:id="@+id/group_text"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="2dp"
|
||||
style="@style/KeepassDXStyle.TextAppearance.FolderTitle"
|
||||
android:orientation="vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:layout_toRightOf="@+id/group_icon"
|
||||
android:layout_toEndOf="@+id/group_icon" />
|
||||
android:layout_toEndOf="@+id/group_icon">
|
||||
<TextView android:id="@+id/group_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Title" /> <!-- style override -->
|
||||
<TextView android:id="@+id/group_subtext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Secondary" /> <!-- style override -->
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
@@ -56,13 +56,43 @@
|
||||
app:popupTheme="?attr/toolbarPopupAppearance"
|
||||
android:elevation="4dp"
|
||||
tools:targetApi="lollipop">
|
||||
<com.kunzisoft.keepass.view.GroupHeaderView
|
||||
<LinearLayout
|
||||
android:id="@+id/group_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/toolbar" />
|
||||
android:layout_below="@+id/toolbar"
|
||||
android:orientation="vertical">
|
||||
<TextView android:id="@+id/search_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/search_results"
|
||||
android:visibility="gone"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Default.TextOnPrimary" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/list_margin"
|
||||
android:layout_marginEnd="@dimen/list_margin">
|
||||
<android.support.v7.widget.AppCompatImageView android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:scaleType="fitXY" />
|
||||
<android.support.v7.widget.AppCompatTextView android:id="@+id/group_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/root"
|
||||
android:maxLines="1"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Title.TextOnPrimary" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</android.support.v7.widget.Toolbar>
|
||||
|
||||
</android.support.design.widget.CollapsingToolbarLayout>
|
||||
@@ -70,10 +100,11 @@
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/nodes_list_fragment_container"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/toolbar" />
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:layout_below="@+id/toolbar"
|
||||
android:background="?android:attr/windowBackground" />
|
||||
|
||||
<com.kunzisoft.keepass.view.AddNodeButtonView
|
||||
android:id="@+id/add_node_button"
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
tools:targetApi="lollipop" >
|
||||
<TextView
|
||||
android:id="@+id/filename"
|
||||
style="@style/KeepassDXStyle.TextAppearance.TitleTextOnPrimary"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Title.TextOnPrimary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
|
||||
65
app/src/main/res/layout/search_entry.xml
Normal file
65
app/src/main/res/layout/search_entry.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2018 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 3 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:id="@+id/entry_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:minHeight="32dp"
|
||||
android:background="?attr/colorPrimary" >
|
||||
<android.support.v7.widget.AppCompatImageView android:id="@+id/entry_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
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:scaleType="fitXY"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true" />
|
||||
<TextView
|
||||
android:id="@+id/entry_text"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Default.TextOnPrimary"
|
||||
android:textStyle="bold"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/entry_icon"
|
||||
android:layout_toEndOf="@+id/entry_icon" />
|
||||
<TextView
|
||||
android:id="@+id/entry_subtext"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Secondary.TextOnPrimary"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_toRightOf="@+id/entry_text"
|
||||
android:layout_toEndOf="@+id/entry_text" />
|
||||
</RelativeLayout>
|
||||
27
app/src/main/res/menu/open_file.xml
Normal file
27
app/src/main/res/menu/open_file.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2018 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 3 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/>.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/menu_open_file_read_mode_key"
|
||||
android:icon="@drawable/ic_read_write_white_24dp"
|
||||
android:title="@string/menu_open_file_read_and_write"
|
||||
android:orderInCategory="85"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
||||
@@ -88,7 +88,7 @@
|
||||
<string name="field_name">Feldname</string>
|
||||
<string name="field_value">Feldwert</string>
|
||||
<string name="file_not_found">Datei nicht gefunden.</string>
|
||||
<string name="file_not_found_content">Datei nicht gefunden. Versuche es von ihrem Dienstanbieter erneut zu öffnen.</string>
|
||||
<string name="file_not_found_content">Datei nicht gefunden. Versuchen Sie, es von Ihrem Dienstanbieter erneut zu öffnen.</string>
|
||||
<string name="file_browser">Dateimanager</string>
|
||||
<string name="generate_password">Passwort generieren</string>
|
||||
<string name="hint_conf_pass">Passwort wiederholen</string>
|
||||
@@ -129,7 +129,7 @@
|
||||
<string name="never">Nie</string>
|
||||
<string name="no_results">Keine Suchergebnisse</string>
|
||||
<string name="no_url_handler">Kein Handler zum Öffnen der URL vorhanden.</string>
|
||||
<string name="open_recent">Zuletzt geöffnete Datenbank :</string>
|
||||
<string name="open_recent">Zuletzt geöffnete Datenbanken :</string>
|
||||
<string name="omitbackup_title">Papierkorb/Sicherungen nicht durchsuchen</string>
|
||||
<string name="omitbackup_summary">Papierkorb und Sicherungseinträge werden bei der Suche nicht berücksichtigt (nur bei .kdb Dateien)</string>
|
||||
<string name="progress_create">Neue Datenbank anlegen\u2026</string>
|
||||
@@ -162,7 +162,7 @@
|
||||
<string name="use_saf_summary">Storage Access Framework als Dateimanager verwenden (Android KitKat und später)</string>
|
||||
<string name="use_saf_title">Speicherzugriff-Framework</string>
|
||||
<string name="warning">Warnung</string>
|
||||
<string name="warning_password_encoding">Das .kdb Format unterstützt nur den Latin1 Zeichensatz. Ihr Passwort enthält andere Zeichen. Diese Zeichen werden umgewandelt. Dies reduziert die Sicherheit des Passwortes. Es wird empfohlen ihr Passwort zu ändern.</string>
|
||||
<string name="warning_password_encoding">Das .kdb Format unterstützt nur den Latin1-Zeichensatz. Enthält Ihr Passwort Zeichen, die in diesem Zeichensatz nicht vorkommen, werden diese alle in in ein und dasselbe Zeichen umgewandelt. Dies reduziert die Sicherheit des Passwortes. Es wird empfohlen, dass Sie Ihr Passwort ändern.</string>
|
||||
<string name="warning_read_only">Die SD-Karte ist schreibgeschützt. Etwaige Änderungen in den Datensätzen können daher nicht in der Datenbank gespeichert werden.</string>
|
||||
<string name="warning_unmounted">Keine SD-Karte vorhanden oder derzeit nicht im Gerät eingebunden. Daher kann weder eine Datenbank geöffnet, noch erstellt werden.</string>
|
||||
<string name="version_label">Version:</string>
|
||||
@@ -186,13 +186,13 @@
|
||||
<item>Groß</item>
|
||||
</string-array>
|
||||
|
||||
<string name="warning_empty_password">Sind Sie sicher, dass sie ein leeres Passwort verwenden wollen ?</string>
|
||||
<string name="warning_no_encryption_key">Sind Sie sicher, dass sie keinen Verschlüsselungsschlüssel verwenden wollen ?</string>
|
||||
<string name="warning_empty_password">Sind Sie sicher, dass Sie ein leeres Passwort verwenden wollen ?</string>
|
||||
<string name="warning_no_encryption_key">Sind Sie sicher, dass Sie keinen Verschlüsselungsschlüssel verwenden wollen ?</string>
|
||||
<string name="appearance">Aussehen</string>
|
||||
<string name="password_size_title">Passwortlänge</string>
|
||||
<string name="password_size_summary">Standardlänge des generierten Passworts ändern</string>
|
||||
<string name="clipboard_notifications_title">Zwischenablagenbenachrichtigungen</string>
|
||||
<string name="clipboard_notifications_summary">Zwischenablagenbenachrichtigungen zum Kopieren von Benutzername und Passwort einschalten</string>
|
||||
<string name="clipboard_notifications_summary">Zwischenablagenbenachrichtigungen einschalten um Eingabefelder zu aktivieren</string>
|
||||
<string name="lock_database_screen_off_title">Bildschirmsperre</string>
|
||||
<string name="lock_database_screen_off_summary">Datenbank sperren, wenn der Bildschirm ausgeschaltet wird</string>
|
||||
<string name="create_keepass_file">Keepass Datei erstellen</string>
|
||||
@@ -204,9 +204,9 @@
|
||||
<string name="fingerprint_enable_summary">Datenbanköffnung mit Fingerabdruck einschalten</string>
|
||||
<string name="fingerprint">Fingerabdruck</string>
|
||||
<string name="fingerprint_enable_title">Fingerabdruckscanner</string>
|
||||
<string name="fingerprint_scan_to_open">Fingerabdruck scannen während Passwortfeld leer ist, um Datenbank zu öffnen</string>
|
||||
<string name="fingerprint_scan_to_open">Fingerabdruck scannen während das Passwortfeld leer ist, um Datenbank zu öffnen</string>
|
||||
<string name="fingerprint_scan_to_store">Fingerabdruck scannen, um Masterpasswort zu speichern</string>
|
||||
<string name="fingerprint_type_password_text">Geben Sie ihr Passwort in Keepass DX ein</string>
|
||||
<string name="fingerprint_type_password_text">Geben Sie Ihr Passwort in Keepass DX ein</string>
|
||||
<string name="lock">Sperre</string>
|
||||
<string name="list_password_generator_options_summary">Standardzeichen für Passwortgenerator setzen</string>
|
||||
<string name="list_password_generator_options_title">Passwortzeichen</string>
|
||||
@@ -217,7 +217,7 @@
|
||||
<string name="fingerprint_error">Probleme mit dem Fingerabdruck : %1$s</string>
|
||||
<string name="history">Verlauf</string>
|
||||
<string name="fingerprint_quick_unlock_title">Wie richte ich den Fingerabdruckscanner für schnelles Entsperren ein ?</string>
|
||||
<string name="fingerprint_setting_text">Speichern sie ihren persönlichen Fingerabdruck in</string>
|
||||
<string name="fingerprint_setting_text">Speichern Sie Ihren persönlichen Fingerabdruck in</string>
|
||||
<string name="fingerprint_setting_way_text">Einstellungen -> Sicherheit -> Fingerabdruck</string>
|
||||
<string name="usage">Verwendung</string>
|
||||
<string name="general">Allgemein</string>
|
||||
@@ -238,7 +238,7 @@
|
||||
<string name="memory_usage">Speichernutzung</string>
|
||||
<string name="memory_usage_explanation">Größe des Speichers (in binären Bytes) der für die Schlüsselableitung genutzt wird.</string>
|
||||
<string name="parallelism">Parallelismus</string>
|
||||
<string name="parallelism_explanation">Grad des Parallelismus (i.d.F. Anzahl der Threads) der für die Schlüsselableitung genutzt wird.</string>
|
||||
<string name="parallelism_explanation">Grad des Parallelismus (d.h. Anzahl der Threads) der für die Schlüsselableitung genutzt wird.</string>
|
||||
<string name="sort_menu">Sortieren</string>
|
||||
<string name="sort_ascending">Aufsteigend</string>
|
||||
<string name="sort_groups_before">Gruppen davor</string>
|
||||
@@ -254,7 +254,7 @@
|
||||
<string name="autofill_sign_in_prompt">Mit KeePass DX anmelden</string>
|
||||
<string name="set_autofill_service_title">Standard Autofill-Dienst auswählen</string>
|
||||
<string name="set_autofill_service_summary">Dienst aktivieren, um automatisch Eingabefelder anderer Anwendungen auszufüllen</string>
|
||||
<string name="notifications">Benachrichtigungen</string>
|
||||
<string name="clipboard">Zwischenablage</string>
|
||||
<string name="fingerprint_delete_all_title">Verschlüsselungskeys löschen</string>
|
||||
<string name="fingerprint_delete_all_summary">Alle Verschlüsselungsschlüssel für Fingerabdruckerkennung löschen</string>
|
||||
<string name="fingerprint_delete_all_warning">Sind Sie sicher, dass Sie alle Schlüssel für die Fingerabdruckerkennung löschen möchten?</string>
|
||||
@@ -266,7 +266,7 @@
|
||||
<string name="recycle_bin_title">Papierkorb verwenden</string>
|
||||
<string name="recycle_bin_summary">Gruppe oder Eintrag in den Papierkorb verschieben bevor er gelöscht wird</string>
|
||||
<string name="permission_external_storage_rationale_write_database">KeePass DX benötigt Berechtigungen für Speicherzugriff um Datenbanken zu schreiben</string>
|
||||
<string name="permission_external_storage_rationale_read_database">KeePass DX benötigt externe Speicherzugriffsberechtigung um eine URI zu lesen, die nicht vom Content-Provider zur Verfügung gestellt wird</string>
|
||||
<string name="permission_external_storage_rationale_read_database">KeePass DX benötigt externe Speicherzugriffsberechtigung um eine URI zu lesen, die nicht von einem Content-Provider zur Verfügung gestellt wird</string>
|
||||
<string name="permission_external_storage_denied">Speicherzugriff verweigert</string>
|
||||
<string name="permission_external_storage_never_ask">Aktion kann ohne Speicherzugriff nicht ausgeführt werden</string>
|
||||
<string name="monospace_font_fields_enable_title">Felder Schriftart</string>
|
||||
@@ -274,7 +274,7 @@
|
||||
<string name="auto_open_file_uri_title">Ausgewählte Datei automatisch öffnen</string>
|
||||
<string name="auto_open_file_uri_summary">Automatisch eine Datei vom Auswahlbildschirm öffnen nach Auswahl im Dateibrowser</string>
|
||||
<string name="allow_copy_password_title">Kopie des Passworts</string>
|
||||
<string name="allow_copy_password_summary">Koperen des Passworts in die Zwischenablage erlauben.</string>
|
||||
<string name="allow_copy_password_summary">Kopieren des Passworts und der geschützten Felder in die Zwischenablage erlauben.</string>
|
||||
<string name="warning_disabling_storage_access_framework">WARNUNG: Deaktivierung dieses Features könnte das Öffnen und Speichern von Datenbanken unmöglich machen</string>
|
||||
<string name="open_link_database">Link der zu öffnenden Kdbx-Datei</string>
|
||||
<string name="database_name_title">Datenbankname</string>
|
||||
@@ -287,9 +287,9 @@
|
||||
<string name="magic_keyboard_title">Magikeyboard</string>
|
||||
<string name="magic_keyboard_summary">Aktiviert eine eigene Tastatur, die Passwort- und Identitätsfelder ganz einfach ausfüllt.</string>
|
||||
|
||||
<string name="reset_education_screens_title">Hilfe-Anzeige zurücksetzen</string>
|
||||
<string name="reset_education_screens_summary">Elemente hervorheben, um zu lernen wie die Anwendung funktioniert</string>
|
||||
<string name="reset_education_screens_text">Hilfe-Anzeige zurückgesetzt</string>
|
||||
<string name="reset_education_screens_title">Hilfe-Anzeige abschalten</string>
|
||||
<string name="reset_education_screens_summary">Anzeige von Hilfe-Themen abschalten</string>
|
||||
<string name="reset_education_screens_text">Hilfe-Anzeige beendet</string>
|
||||
<string name="education_create_database_title">Ihre Datenbankdatei erstellen</string>
|
||||
<string name="education_create_database_summary">Sie kennen KeePass DX noch nicht, erstellen Sie Ihre erste Passwortmanager-Datei.</string>
|
||||
<string name="education_select_database_title">Existierende Datenbank öffnen</string>
|
||||
@@ -299,7 +299,7 @@
|
||||
<string name="education_new_node_title">Neue Einträge zu Ihrer Datenbank hinzufügen</string>
|
||||
<string name="education_new_node_summary">Elemente hinzufügen um Ihre digitalen Identitäten zu verwalten.\n\nGruppen hinzufügen (wie Ordner) um Ihre Einträge und Datenbank zu ordnen.</string>
|
||||
<string name="education_search_title">Ihre Einträge ganz einfach durchsuchen</string>
|
||||
<string name="education_search_summary">Einträge via Titel, Benutzernamen oder anderen Feldern finden um ganz einfach Ihre Passwörter zu bekommen.</string>
|
||||
<string name="education_search_summary">Einträge nach Titel, Benutzernamen oder anderen Feldern durchsuchen, um ganz einfach Ihre Passwörter wiederzufinden.</string>
|
||||
<string name="education_fingerprint_title">Ihre Datenbank mit Ihrem Fingerabdruck entsperren</string>
|
||||
<string name="education_fingerprint_summary">Verknüpfen Sie Ihr Passwort und Ihren Fingerabdruck um Ihre Datenbank im Handumdrehen zu entsperren.</string>
|
||||
<string name="education_entry_edit_title">Eintrag bearbeiten</string>
|
||||
@@ -341,4 +341,39 @@
|
||||
|
||||
<string name="icon_pack_choose_title">Icon-Paket auswählen</string>
|
||||
<string name="icon_pack_choose_summary">Das Symbolpaket der Anwendung ändern</string>
|
||||
</resources>
|
||||
<string name="error_move_folder_in_itself">Eine Gruppe kann nicht in sich selbst verschoben werden.</string>
|
||||
<string name="menu_copy">Kopieren</string>
|
||||
<string name="menu_move">Verschieben</string>
|
||||
<string name="menu_paste">Einfügen</string>
|
||||
<string name="menu_cancel">Abbrechen</string>
|
||||
<string name="clipboard_warning">Einige Geräte sind nicht in der Lage, die Zwischenablage automatisch zu leeren. Ist die Löschung durch den Gerätemanager nicht möglich, müssen die kopierten Elemente manuell aus der Zwischenablage gelöscht werden.</string>
|
||||
<string name="allow_copy_password_warning">WARNUNG : Alle Anwendungen teilen sich die Zwischenablage. Wenn sensible Daten kopiert werden, kann andere Software darauf zugreifen.</string>
|
||||
<string name="magic_keyboard_preference_title">Magikeyboard-Einstellungen</string>
|
||||
<string name="magic_keyboard_configure_title">Wie funktioniert die Tastaturkonfiguration zum sicheren Ausfüllen von Formularen?</string>
|
||||
<string name="magic_keyboard_activate_setting_text">Aktivieren Sie das Magikeyboard in den Geräteeinstellungen.</string>
|
||||
<string name="magic_keyboard_activate_setting_path_1_text">Einstellungen -> Sprachen & Eingabe -> Aktuelle Tastatur -> TASTATUR ÄNDERN</string>
|
||||
<string name="magic_keyboard_activate_setting_path_2_text">oder (Einstellungen -> System -> Sprachen & Eingabe -> Bildschirmtastatur -> Tastaturen verwalten)</string>
|
||||
<string name="keyboards_choose_magikeyboard_text">Wählen Sie das Magikeyboard aus, wenn Sie ein Formular ausfüllen müssen.</string>
|
||||
<string name="keyboards_swicth_magikeyboard_text">Sie können leicht von Ihrer Haupttastatur auf Magikeyboard umschalten, entweder mit der Sprachentaste Ihrer Tastatur, durch einen langen Druck auf die Leertaste oder, wenn das nicht zur Verfügung steht, mit :</string>
|
||||
<string name="keyboard_select_entry_text">Wählen Sie den Eintrag mit dem Schlüssel aus.</string>
|
||||
<string name="keyboard_fill_field_text">Füllen Sie die Felder mit den Elementen des Eintrags aus.</string>
|
||||
<string name="keyboard_lock_database_text">Sperren Sie die Datenbank.</string>
|
||||
<string name="keyboard_back_main_keyboard_text">Kehren Sie zur Haupttastatur zurück.</string>
|
||||
|
||||
<string name="allow_no_password_title">Kein Passwort zulassen</string>
|
||||
<string name="allow_no_password_summary">Öffnen-Taste aktivieren, wenn keine Passwort-Identifikation festgelegt ist.</string>
|
||||
|
||||
<string name="enable_education_screens_title">Hilfe-Anzeige</string>
|
||||
<string name="enable_education_screens_summary">Bedienelemente hervorheben, um die Funktionsweise der Anwendung zu lernen</string>
|
||||
<string name="menu_open_file_read_and_write">Lesen und Schreiben</string>
|
||||
<string name="menu_file_selection_read_only">schreibgeschützt</string>
|
||||
<string name="enable_read_only_title">Schreibgeschützt</string>
|
||||
<string name="education_read_only_title">Schreibschutz aktivieren</string>
|
||||
<string name="enable_read_only_summary">Standardmäßig wird die Datenbank im schreibgeschützten Modus geöffnet.</string>
|
||||
|
||||
<string name="education_read_only_summary">Ändern Sie den Modus bei Eröffnung einer Sitzung.
|
||||
\n
|
||||
\nIm schreibgeschützten Modus verhindern Sie unbeabsichtigte Änderungen an der Datenbank.
|
||||
\n
|
||||
\nIm Modus ‘Lesen und Schreiben‘ können Sie alle Elemente hinzufügen, löschen oder verändern, wie Sie möchten.</string>
|
||||
</resources>
|
||||
|
||||
@@ -229,7 +229,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
|
||||
<string name="password_size_summary">Establecer el tamaño predeterminado de la contraseña generada</string>
|
||||
<string name="list_password_generator_options_title">Caracteres de contraseña</string>
|
||||
<string name="list_password_generator_options_summary">Establecer los caracteres predeterminados del generador de contraseñas</string>
|
||||
<string name="notifications">Notificaciones</string>
|
||||
<string name="clipboard">Portapapeles</string>
|
||||
<string name="clipboard_notifications_title">Notificaciones del Portapapeles</string>
|
||||
<string name="clipboard_notifications_summary">Habilitar las notificaciones del portapapeles para copiar el nombre de usuario y la contraseña</string>
|
||||
<string name="lock">Bloquear</string>
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
<string name="password_size_summary">Définir la taille par défaut du mot de passe généré</string>
|
||||
<string name="list_password_generator_options_title">Caractères de mot de passe</string>
|
||||
<string name="list_password_generator_options_summary">Définir les caractères par défaut du générateur de mot de passe</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
<string name="clipboard">Presse-papiers</string>
|
||||
<string name="clipboard_notifications_title">Notifications du presse-papiers</string>
|
||||
<string name="clipboard_notifications_summary">Activer les notifications du presse-papiers pour copier les champs d\'entrées</string>
|
||||
<string name="clipboard_warning">Certains appareils ne sont pas en mesure de supprimer automatiquement les éléments du presse-papiers. Si votre gestionnaire n\'autorise pas cette suppression, vous devrez supprimer manuellement l\'élément copié de l\'historique de votre presse-papiers.</string>
|
||||
@@ -350,4 +350,35 @@
|
||||
<string name="icon_pack_choose_title">Choisir un pack d\'icones</string>
|
||||
<string name="icon_pack_choose_summary">Changer le pack d\'icones de l\'application</string>
|
||||
|
||||
</resources>
|
||||
<string name="error_move_folder_in_itself">Impossible de déplacer un groupe en lui-même.</string>
|
||||
<string name="menu_copy">Copier</string>
|
||||
<string name="menu_move">Déplacer</string>
|
||||
<string name="menu_paste">Coller</string>
|
||||
<string name="menu_cancel">Annuler</string>
|
||||
<string name="magic_keyboard_preference_title">Paramètres du Magikeyboard</string>
|
||||
<string name="magic_keyboard_configure_title">Comment configurer le clavier pour le remplissage sécurisé de formulaire ?</string>
|
||||
<string name="magic_keyboard_activate_setting_text">Activer le Magikeyboard dans les paramètres de l\'appareil.</string>
|
||||
<string name="magic_keyboard_activate_setting_path_1_text">Paramètres -> Langue et saisie -> Clavier actuel -> CHOISIR LES CLAVIERS</string>
|
||||
<string name="magic_keyboard_activate_setting_path_2_text">ou (Paramètres -> Système -> Langues et saisie -> Clavier virtuel -> Gérer les claviers)</string>
|
||||
<string name="keyboards_choose_magikeyboard_text">Choisir le Magikeyboard lorsque vous avez besoin de remplir un formulaire.</string>
|
||||
<string name="keyboards_swicth_magikeyboard_text">Vous pouvez facilement passer de votre clavier principal à Magikeyboard avec le bouton langage de votre clavier, un appui long sur la barre d\'espace de votre clavier, ou, si ce n\'est pas disponible, avec :</string>
|
||||
<string name="keyboard_select_entry_text">Sélectionnez votre entrée avec la clé.</string>
|
||||
<string name="keyboard_fill_field_text">Remplissez vos champs avec les éléments de l\'entrée.</string>
|
||||
<string name="keyboard_lock_database_text">Verrouiller la base de données.</string>
|
||||
<string name="keyboard_back_main_keyboard_text">Retourner sur votre clavier principal.</string>
|
||||
|
||||
<string name="allow_no_password_title">Autoriser aucun mot de passe</string>
|
||||
<string name="allow_no_password_summary">Activer le bouton d\'ouverture si aucune identification de mot de passe n\'est sélectionnée.</string>
|
||||
|
||||
<string name="menu_file_selection_read_only">Lecture seule</string>
|
||||
<string name="menu_open_file_read_and_write">Lecture et écriture</string>
|
||||
<string name="enable_read_only_title">Lecture seule</string>
|
||||
<string name="enable_read_only_summary">Par défaut, ouvrir une base de données en mode lecture seule.</string>
|
||||
|
||||
<string name="education_read_only_title">Activer la lecture seule</string>
|
||||
<string name="education_read_only_summary">Changez le mode d\'ouverture de la session.
|
||||
\n
|
||||
\nEn mode lecture seule, vous empêchez les modifications involontaires de la base de données.
|
||||
\n
|
||||
\nEn mode écriture, vous pouvez ajouter, supprimer ou modifier tous les éléments comme vous le souhaitez.</string>
|
||||
</resources>
|
||||
|
||||
26
app/src/main/res/values-gl/strings.xml
Normal file
26
app/src/main/res/values-gl/strings.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources><string name="about_feedback">Comentarios:</string>
|
||||
<string name="about_homepage">Páxina inicial:</string>
|
||||
<string name="about_description">KeePass DX é unha implementación para Android do xestor de contrasinais KeePass.</string>
|
||||
<string name="accept">Aceptar</string>
|
||||
<string name="add_entry">Engadir entrada</string>
|
||||
<string name="add_group">Engadir grupo</string>
|
||||
<string name="add_string">Engadir texto</string>
|
||||
<string name="encryption">Cifrado</string>
|
||||
<string name="encryption_algorithm">Algoritmo de cifrado</string>
|
||||
<string name="key_derivation_function">Función de derivación de chave</string>
|
||||
<string name="app_timeout">Tempo de espera da aplicación</string>
|
||||
<string name="app_timeout_summary">Tempo antes de bloquear a base de datos cando a aplicación está inactiva.</string>
|
||||
<string name="application">Aplicación</string>
|
||||
<string name="beta_dontask">Non amosar de novo</string>
|
||||
<string name="brackets">Parénteses</string>
|
||||
<string name="extended_ASCII">ASCII extendido</string>
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="allow">Permitir</string>
|
||||
<string name="clipboard_cleared">Portapapeis limpo</string>
|
||||
<string name="clipboard_error_title">Erro do portapapeis</string>
|
||||
<string name="clipboard_error_clear">Fallou a limpeza do portapapeis</string>
|
||||
<string name="clipboard_timeout">Tempo límite para o portapapeis</string>
|
||||
<string name="clipboard_timeout_summary">Tempo antes de limpar o portapapeis após copiar usuario ou contrasinal</string>
|
||||
<string name="clipboard_swipe_clean">Deslice para limpar agora o portapapeis</string>
|
||||
</resources>
|
||||
@@ -164,7 +164,7 @@
|
||||
<string name="configure_fingerprint">Impronte supportate ma non configurate nel dispositivo</string>
|
||||
<string name="scanning_fingerprint">In attesa di impronte</string>
|
||||
<string name="encrypted_value_stored">Password criptata salvata</string>
|
||||
<string name="fingerprint_invalid_key">Problema chiave non valida</string>
|
||||
<string name="fingerprint_invalid_key">Problema impronta non valida. Ripristina la tua password.</string>
|
||||
<string name="fingerprint_error">Problema impronta : %1$s</string>
|
||||
<string name="store_with_fingerprint">Usa l\'impronta per salvare questa password</string>
|
||||
<string name="no_password_stored">Nessuna password salvata per questo database</string>
|
||||
@@ -190,4 +190,191 @@
|
||||
<string name="beta_dontask">Non mostrare di nuovo</string>
|
||||
<string name="allow">Consenti</string>
|
||||
<string name="copy_field">Copia di %1$s</string>
|
||||
<string name="encryption">Crittografia</string>
|
||||
<string name="key_derivation_function">Funzione di derivazione chiave</string>
|
||||
<string name="extended_ASCII">ASCII esteso</string>
|
||||
<string name="clipboard_swipe_clean">Scorri ora per pulire gli appunti</string>
|
||||
<string name="error_nokeyfile">È richiesto un file chiave.</string>
|
||||
<string name="error_autofill_enable_service">Il servizio di auto-riempimento non può essere attivato.</string>
|
||||
<string name="error_move_folder_in_itself">Impossibile spostare un gruppo in se stesso.</string>
|
||||
<string name="menu_form_filling_settings">Riempimento campi</string>
|
||||
<string name="menu_copy">Copia</string>
|
||||
<string name="menu_move">Sposta</string>
|
||||
<string name="menu_paste">Incolla</string>
|
||||
<string name="menu_cancel">Annulla</string>
|
||||
<string name="menu_fingerprint_remove_key">Rimuovi l\'impronta digitale</string>
|
||||
<string name="menu_file_selection_read_only">Solo lettura</string>
|
||||
<string name="menu_open_file_read_and_write">Lettura e scrittura</string>
|
||||
<string name="encryption_explanation">Algoritmo per cifrare l\'intero database. (Password, nome utente, note e tutti i dati del database sono criptati con l\'algoritmo selezionato)</string>
|
||||
<string name="kdf_explanation">Per generare la chiave per l\'algoritmo di cifratura, la chiave master compressa (SHA-256) viene trasformata usando una funzione di derivazione della chiave (con un sale casuale).</string>
|
||||
<string name="memory_usage">Utilizzo di memoria</string>
|
||||
<string name="memory_usage_explanation">Quantità di memoria (in byte binari) da usare dalla funzione di derivazione della chiave.</string>
|
||||
<string name="parallelism">Parallelismo</string>
|
||||
<string name="parallelism_explanation">Grado di parallelismo (cioè numero di thread) usato dalla funzione di derivazione della chiave.</string>
|
||||
<string name="sort_menu">Ordina</string>
|
||||
<string name="sort_ascending">Ascendente</string>
|
||||
<string name="sort_groups_before">Prima i gruppi</string>
|
||||
<string name="sort_recycle_bin_bottom">Cestino in fondo</string>
|
||||
<string name="sort_title">Ordina per titolo</string>
|
||||
<string name="sort_username">Ordina per nome utente</string>
|
||||
<string name="sort_creation_time">Ordina per data di creazione</string>
|
||||
<string name="sort_last_modify_time">Ordina per ultima modifica</string>
|
||||
<string name="sort_last_access_time">Ordina per ultimo accesso</string>
|
||||
<string name="warning_empty_password">Vuoi veramente usare una stringa vuota come password?</string>
|
||||
<string name="warning_no_encryption_key">Sei sicuro di non volere usare una chiave di cifratura?</string>
|
||||
<string name="fingerprint_not_recognized">Impronta non riconosciuta</string>
|
||||
<string name="history">Cronologia</string>
|
||||
<string name="appearance">Aspetto</string>
|
||||
<string name="general">Generale</string>
|
||||
<string name="autofill">Autocompletamento</string>
|
||||
<string name="autofill_service_name">Servizio autocompletamento di KeePass DX</string>
|
||||
<string name="autofill_sign_in_prompt">Accedi con KeePass DX</string>
|
||||
<string name="set_autofill_service_title">Imposta servizio predefinito di autocompletamento</string>
|
||||
<string name="set_autofill_service_summary">Attiva il servizio per completare facilmente i moduli da altre applicazioni</string>
|
||||
<string name="password_size_title">Dimensione password</string>
|
||||
<string name="password_size_summary">Imposta la dimensione predefinita della password generata</string>
|
||||
<string name="list_password_generator_options_title">Caratteri password</string>
|
||||
<string name="list_password_generator_options_summary">Imposta i caratteri predefiniti di generazione password</string>
|
||||
<string name="clipboard_notifications_title">Notifiche appunti</string>
|
||||
<string name="clipboard_notifications_summary">Attiva le notifiche appunti per copiare gli elementi</string>
|
||||
<string name="clipboard_warning">Alcuni dispositivi non riescono ad eliminare automaticamente gli appunti. Se il tuo gestore non permette questa eliminazione, dovrai cancellare manualmente dagli appunti l\'elemento copiato.</string>
|
||||
<string name="lock">Blocca</string>
|
||||
<string name="lock_database_screen_off_title">Blocco schermo</string>
|
||||
<string name="lock_database_screen_off_summary">Blocca il database quando lo schermo è spento</string>
|
||||
<string name="fingerprint_quick_unlock_title">Come configurare l\'impronta per sbloccare velocemente?</string>
|
||||
<string name="fingerprint_setting_text">Imposta la tua impronta per il dispositivo in</string>
|
||||
<string name="fingerprint_setting_way_text">Impostazioni -> Sicurezza -> Impronta</string>
|
||||
<string name="fingerprint_type_password_text">Digita la tua password in Keepass DX</string>
|
||||
<string name="fingerprint_scan_to_store">Scansiona la tua impronta per salvare la tua password master in modo sicuro</string>
|
||||
<string name="fingerprint_scan_to_open">Scansiona la tua impronta quando la casella password non è selezionata per aprire il database</string>
|
||||
<string name="usage">Utilizzo</string>
|
||||
<string name="fingerprint">Impronta</string>
|
||||
<string name="fingerprint_enable_title">Rilevazione impronta</string>
|
||||
<string name="fingerprint_enable_summary">Attiva apertura database con impronta</string>
|
||||
<string name="fingerprint_delete_all_title">Elimina chiavi di cifratura</string>
|
||||
<string name="fingerprint_delete_all_summary">Elimina tutte le chiavi di cifratura relative al riconoscimento dell\'impronta</string>
|
||||
<string name="fingerprint_delete_all_warning">Sei sicuro di volere eliminare tutte le chiavi relative alle impronte?</string>
|
||||
<string name="unavailable_feature_text">Impossibile avviare questa funzione.</string>
|
||||
<string name="unavailable_feature_version">La tua versione di Android %1$s non è la minima %2$s richiesta.</string>
|
||||
<string name="unavailable_feature_hardware">L\'hardware non è stato rilevato.</string>
|
||||
<string name="file_name">Nome file</string>
|
||||
<string name="path">Percorso</string>
|
||||
<string name="assign_master_key">Assegna una chiave master</string>
|
||||
<string name="create_keepass_file">Crea un file keepass</string>
|
||||
<string name="bytes">Bytes</string>
|
||||
<string name="full_file_path_enable_title">Percorso file</string>
|
||||
<string name="full_file_path_enable_summary">Visualizza il percorso file completo</string>
|
||||
<string name="recycle_bin_title">Usa il cestino</string>
|
||||
<string name="recycle_bin_summary">Sposta un gruppo o elemento nel cestino prima di eliminare</string>
|
||||
<string name="permission_external_storage_rationale_write_database">KeePass DX richiede l\'autorizzazione di archiviazione per scrivere un database</string>
|
||||
<string name="permission_external_storage_rationale_read_database">KeePass DX richiede l\'autorizzazione di archiviazione per leggere un URI non fornito da un Content Provider</string>
|
||||
<string name="permission_external_storage_denied">Autorizzazione di archiviazione negata</string>
|
||||
<string name="permission_external_storage_never_ask">Impossibile eseguire l\'azione senza l\'autorizzazione di archiviazione</string>
|
||||
<string name="monospace_font_fields_enable_title">Carattere campi</string>
|
||||
<string name="monospace_font_fields_enable_summary">Cambia il carattere dei campi per una migliore visibilità</string>
|
||||
<string name="auto_open_file_uri_title">Apri automaticamente file selezionato</string>
|
||||
<string name="auto_open_file_uri_summary">Apri automaticamente un file dalla finestra di selezione dopo una selezione nel gestore file</string>
|
||||
<string name="allow_copy_password_title">Copia della password</string>
|
||||
<string name="allow_copy_password_summary">Permetti la copia della password e dei campi protetti negli appunti.</string>
|
||||
<string name="allow_copy_password_warning">ATTENZIONE: gli appunti sono condivisi da tutte le app. Se vengono copiati dati sensibili, altri software possono recuperarli.</string>
|
||||
<string name="warning_disabling_storage_access_framework">ATTENZIONE: disattivando questa funzione potresti non riuscire ad aprire o salvare i database</string>
|
||||
<string name="open_link_database">Link del file Kdbx da aprire</string>
|
||||
<string name="database_name_title">Nome database</string>
|
||||
<string name="database_description_title">Descrizione database</string>
|
||||
<string name="database_version_title">Versione database</string>
|
||||
<string name="text_appearance">Aspetto del testo</string>
|
||||
<string name="application_appearance">Aspetto dell\'applicazione</string>
|
||||
<string name="other">Altro</string>
|
||||
|
||||
<string name="keyboard">Tastiera</string>
|
||||
<string name="magic_keyboard_title">Magitastiera</string>
|
||||
<string name="magic_keyboard_summary">Attiva una tastiera personale che popola le tue password e i campi di identità facilmente.</string>
|
||||
<string name="magic_keyboard_preference_title">Impostazioni Magitastiera</string>
|
||||
<string name="magic_keyboard_configure_title">Come configurare la tastiera per una compilazione di campi sicura?</string>
|
||||
<string name="magic_keyboard_activate_setting_text">Attiva la Magitastiera nelle impostazioni del dispositivo.</string>
|
||||
<string name="magic_keyboard_activate_setting_path_1_text">Impostazioni -> Lingue e immissione -> Tastiera attuale -> SCEGLI TASTIERE</string>
|
||||
<string name="magic_keyboard_activate_setting_path_2_text">o (Impostazioni -> Sistema -> Lingue e immissione -> Tastiera virtuale -> Gestisci tastiere)</string>
|
||||
<string name="keyboards_choose_magikeyboard_text">Scegli la Magitastiera quando devi compilare un modulo.</string>
|
||||
<string name="keyboards_swicth_magikeyboard_text">Puoi passare facilmente dalla tastiera principale alla Magitastiera con il pulsante lingua della tastiera, una pressione lunga della barra spaziatrice, o, se non disponibile, con:</string>
|
||||
<string name="keyboard_lock_database_text">Blocca il database.</string>
|
||||
<string name="keyboard_back_main_keyboard_text">Torna alla tua tastiera principale.</string>
|
||||
|
||||
<string name="allow_no_password_title">Permetti password mancante</string>
|
||||
<string name="allow_no_password_summary">Attiva il pulsante di apertura se non è selezionata una password.</string>
|
||||
<string name="enable_read_only_title">Solo lettura</string>
|
||||
<string name="enable_read_only_summary">Apri un database in sola lettura in modo predefinito.</string>
|
||||
|
||||
<string name="enable_education_screens_title">Schermate educative</string>
|
||||
<string name="enable_education_screens_summary">Evidenzia gli elementi per imparare come funziona l\'applicazione</string>
|
||||
<string name="reset_education_screens_title">Ripristina schermate educative</string>
|
||||
<string name="reset_education_screens_summary">Ripristina la visualizzazione di elementi educativi</string>
|
||||
<string name="reset_education_screens_text">Schermate educative ripristinate</string>
|
||||
<string name="education_create_database_title">Crea il tuo file database</string>
|
||||
<string name="education_create_database_summary">Non conosci ancora KeePass DX, crea il tuo primo file di gestione password.</string>
|
||||
<string name="education_select_database_title">Apri un database esistente</string>
|
||||
<string name="education_select_database_summary">Hai già usato un gestore KeePass. Apri il tuo file Kdbx dal tuo gestore di file.</string>
|
||||
<string name="education_open_link_database_title">Un link al percorso del tuo file è sufficiente</string>
|
||||
<string name="education_open_link_database_summary">Puoi anche aprire il tuo database con un link fisico (con file:// e content:// ad esempio).</string>
|
||||
<string name="education_new_node_title">Aggiungi nuovi elementi al database</string>
|
||||
<string name="education_new_node_summary">Aggiungi elementi per gestire le tue identità digitali.
|
||||
\n
|
||||
\nAggiungi gruppi (equivalente delle cartelle) per organizzare elementi e database.</string>
|
||||
<string name="education_search_title">Cerca facilmente gli elementi</string>
|
||||
<string name="education_search_summary">Cerca elementi per titolo, nome utente o altri campi per trovare facilmente le password.</string>
|
||||
<string name="education_fingerprint_title">Sblocca il database con la tua impronta</string>
|
||||
<string name="education_fingerprint_summary">Crea un collegamento tra la tua password e la tua impronta per sbloccare facilmente il database.</string>
|
||||
<string name="education_entry_edit_title">Modifica l\'elemento</string>
|
||||
<string name="education_entry_edit_summary">Modifica l\'elemento con campi personali, puoi aggiungere riferimenti per raggruppare i dati tra campi di voci diverse.</string>
|
||||
<string name="education_generate_password_title">Crea una password robusta</string>
|
||||
<string name="education_generate_password_summary">Genera una password robusta da associare all\'elemento, definiscila a seconda dei criteri del modulo e non dimenticare una password complessa ma sicura.</string>
|
||||
<string name="education_entry_new_field_title">Aggiungi campi personali</string>
|
||||
<string name="education_entry_new_field_summary">Vuoi registrare un campo di base non fornito, inseriscine uno nuovo che puoi anche proteggere visivamente.</string>
|
||||
<string name="education_unlock_title">Sblocca il tuo database</string>
|
||||
<string name="education_read_only_title">Attiva solo lettura</string>
|
||||
<string name="education_read_only_summary">Cambia la modalità di apertura per la sessione.
|
||||
\n
|
||||
\nIn modalità di sola lettura, eviti modifiche accidentali al database.
|
||||
\n
|
||||
\nIn scrittura, puoi aggiungere, eliminare, o modificare tutti gli elementi che vuoi.</string>
|
||||
<string name="education_field_copy_title">Copia un campo</string>
|
||||
<string name="education_field_copy_summary">Copia un campo facilmente per incollarlo dove vuoi
|
||||
\n
|
||||
\nPuoi usare diversi metodi di inserimento moduli. Usa quello che preferisci!</string>
|
||||
<string name="education_lock_title">Blocca il database</string>
|
||||
<string name="education_lock_summary">Blocca velocemente il database, puoi impostare l\'app per bloccarlo dopo un certo periodo e quando lo schermo si spegne.</string>
|
||||
<string name="education_sort_title">Ordina elementi</string>
|
||||
<string name="education_sort_summary">Ordina gli elementi e i gruppi secondo parametri specifici.</string>
|
||||
<string name="education_donation_title">Partecipa</string>
|
||||
<string name="education_donation_summary">Partecipa per migliorare la stabilità, la sicurezza e aggiungere nuove funzioni.</string>
|
||||
|
||||
<string name="html_text_ad_free">Diversamente da molte app di gestione password, questa app è <strong>senza pubblicità</strong>, <strong>open source</strong> e non raccoglie dati personali nei suoi server, anche nella versione gratuita.</string>
|
||||
<string name="html_text_buy_pro">Acquistando la versione pro, avrai accesso a questa <strong>funzione visiva</strong> e aiuterai specialmente nella <strong>realizzazione di progetti della comunità.</strong></string>
|
||||
<string name="html_text_feature_generosity">Questa <strong>funzione visiva</strong> è disponibile grazie alla tua generosità.</string>
|
||||
<string name="html_text_donation">Per mantenere la nostra libertà ed essere sempre attivi, contiamo sul tuo <strong>contributo.</strong></string>
|
||||
|
||||
<string name="html_text_dev_feature">Questa funzione è <strong>in sviluppo</strong> e richiede il tuo <strong>contributo</strong> per essere disponibile a breve.</string>
|
||||
<string name="html_text_dev_feature_buy_pro">Acquistando la versione <strong>pro</strong>,</string>
|
||||
<string name="html_text_dev_feature_contibute"><strong>Contribuendo</strong>,</string>
|
||||
<string name="html_text_dev_feature_encourage">incoraggi gli sviluppatori a creare <strong>nuove funzioni</strong> e a <strong>correggere errori</strong> secondo le tue osservazioni.</string>
|
||||
<string name="html_text_dev_feature_thanks">Grazie mille per il tuo contributo.</string>
|
||||
<string name="html_text_dev_feature_work_hard">Stiamo lavorando sodo per rilasciare questa funzione a breve.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Non dimenticare di tenere aggiornata la tua applicazione.</string>
|
||||
|
||||
<string name="download">Scarica</string>
|
||||
<string name="contribute">Contribuisci</string>
|
||||
|
||||
<string name="encryption_rijndael">Rijndael (AES)</string>
|
||||
<string name="encryption_twofish">Twofish</string>
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
|
||||
<string name="kdf_AES">AES-KDF</string>
|
||||
<string name="kdf_Argon2">Argon2</string>
|
||||
|
||||
<string name="style_choose_title">Seleziona un tema</string>
|
||||
<string name="style_choose_summary">Cambia il tema dell\'applicazione modificandone i colori</string>
|
||||
<string name="icon_pack_choose_title">Seleziona un pacchetto icone</string>
|
||||
<string name="icon_pack_choose_summary">Cambia il pacchetto di icone dell\'applicazione</string>
|
||||
|
||||
<string name="keyboard_select_entry_text">Seleziona un elemento con la chiave.</string>
|
||||
<string name="keyboard_fill_field_text">Riempi i campi con i contenuti dell\'elemento.</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--
|
||||
Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
|
||||
@@ -35,13 +35,13 @@
|
||||
<string name="brackets">Parênteses</string>
|
||||
<string name="browser_intall_text">Navegação em arquivos requer o gerenciador de arquivos Open Intents, clique abaixo para instalar. Devido a algumas peculiaridades no gerenciador de arquivos, a navegação pode não funcionar na primeira vez.</string>
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="clipboard_cleared">Clipboard limpo.</string>
|
||||
<string name="clipboard_cleared">Área de transferência limpa</string>
|
||||
<string name="clipboard_timeout">Tempo limite para o clipboard</string>
|
||||
<string name="clipboard_timeout_summary">Tempo até limpar o clipboard após copiar usuário ou senha.</string>
|
||||
<string name="clipboard_timeout_summary">Tempo até limpar a área de transferência após copiar usuário ou senha</string>
|
||||
<string name="select_to_copy">Copiar %1$s para o clipboard</string>
|
||||
<string name="creating_db_key">Criando a chave do banco de dados…</string>
|
||||
<string name="creating_db_key">Criando a chave do banco de dados…</string>
|
||||
<string name="database">Banco de Dados</string>
|
||||
<string name="decrypting_db">Decifrando conteúdo do banco de dados…</string>
|
||||
<string name="decrypting_db">Decifrando conteúdo do banco de dados…</string>
|
||||
<string name="default_checkbox">Usar este banco de dados como padrão</string>
|
||||
<string name="digits">Digitos</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Kunzisoft vem com ABSOLUTAMENTE NENHUMA GARANTIA; Este é um software livre, e você está convidado a redistribui-lo sob as condições da GPL versão 3 ou posterior.</string>
|
||||
@@ -94,7 +94,7 @@
|
||||
<string name="length">Tamanho</string>
|
||||
<string name="list_size_title">Tamanho da lista de grupos</string>
|
||||
<string name="list_size_summary">Tamanho do texto na lista de grupos</string>
|
||||
<string name="loading_database">Carregando banco de dados…</string>
|
||||
<string name="loading_database">Carregando banco de dados…</string>
|
||||
<string name="lowercase">Letras minúsculas</string>
|
||||
<string name="maskpass_title">Esconder senha</string>
|
||||
<string name="maskpass_summary">Esconder senha por padrão</string>
|
||||
@@ -113,13 +113,13 @@
|
||||
<string name="menu_url">Ir para URL</string>
|
||||
<string name="minus">Menos</string>
|
||||
<string name="never">Nunca</string>
|
||||
<string name="no_results">Sem resultados na busca.</string>
|
||||
<string name="no_results">Sem resultados na busca</string>
|
||||
<string name="no_url_handler">Erro ao tratar url.</string>
|
||||
<string name="open_recent">Abrir banco de dados recente :</string>
|
||||
<string name="omitbackup_title">Não procurar entradas no backup ou na lixeira.</string>
|
||||
<string name="omitbackup_title">Não procurar entradas no backup ou na lixeira</string>
|
||||
<string name="omitbackup_summary">Omitir os grupos \'Backup\' e \'Lixeira\' dos resultados da busca</string>
|
||||
<string name="progress_create">Criando novo banco de dados…</string>
|
||||
<string name="progress_title">Trabalhando…</string>
|
||||
<string name="progress_create">Criando novo banco de dados…</string>
|
||||
<string name="progress_title">Trabalhando…</string>
|
||||
<string name="remember_keyfile_summary">Lembrar o local dos arquivos de chave</string>
|
||||
<string name="remember_keyfile_title">Salvar arquivo de chave</string>
|
||||
<string name="remove_from_filelist">Remover</string>
|
||||
@@ -128,14 +128,14 @@
|
||||
<string name="rounds">Rodadas de criptografia</string>
|
||||
<string name="rounds_explanation">Maior número de rodadas de criptografia adiciona mais proteção contra ataques de força bruta, porém pode tornar o processo de carregar e salvar mais lentos.</string>
|
||||
<string name="rounds_hint">rodadas</string>
|
||||
<string name="saving_database">Salvando banco de dados…</string>
|
||||
<string name="saving_database">Salvando banco de dados…</string>
|
||||
<string name="space">Spaço</string>
|
||||
<string name="search_label">Busca</string>
|
||||
<string name="sort_db">Ordenação do banco de dados</string>
|
||||
<string name="special">Caracteres Especiais</string>
|
||||
<string name="search">Título/Descrição da entrada</string>
|
||||
<string name="encryption_twofish">Twofish</string>
|
||||
<string name="underline">Underline</string>
|
||||
<string name="underline">Sublinhado</string>
|
||||
<string name="unsupported_db_version">Versão de banco de dados não suportada.</string>
|
||||
<string name="uppercase">Letras maiúsculas</string>
|
||||
<string name="warning_read_only">Seu cartão SD está no modo de somente leitura. Talvez não seja possível salvar modificações ao banco de dados.</string>
|
||||
@@ -160,4 +160,221 @@
|
||||
<item>Médio</item>
|
||||
<item>Grande</item>
|
||||
</string-array>
|
||||
<string name="add_string">Adicionar texto</string>
|
||||
<string name="encryption">Encriptação</string>
|
||||
<string name="key_derivation_function">Função de derivação de chave</string>
|
||||
<string name="beta_dontask">Não mostre novamente</string>
|
||||
<string name="extended_ASCII">ASCII Extendido</string>
|
||||
<string name="allow">Permitir</string>
|
||||
<string name="clipboard_error_title">Erro na área de transferência</string>
|
||||
<string name="clipboard_error">Alguns telefones Samsung Android têm um bug na implementação da área de transferência que faz com que a cópia entre aplicativos falhe. Para mais detalhes, acesse:</string>
|
||||
<string name="clipboard_error_clear">Limpeza de área de transferência falhou</string>
|
||||
<string name="clipboard_swipe_clean">Deslize para limpar a área de transferência agora</string>
|
||||
<string name="entry_not_found">Entrada não encontrada.</string>
|
||||
<string name="error_string_key">O campo nome é necessário para cada string.</string>
|
||||
<string name="error_autofill_enable_service">Serviço de preenchimento automático não pode ser habilitado.</string>
|
||||
<string name="error_move_folder_in_itself">Não é possível mover um grupo para dentro dele mesmo.</string>
|
||||
<string name="field_name">Campo Nome</string>
|
||||
<string name="field_value">Campo valor</string>
|
||||
<string name="file_not_found_content">Arquivo não encontrado. Tente reabri-lo de seu provedor de conteúdo.</string>
|
||||
<string name="invalid_algorithm">Algoritmo inválido.</string>
|
||||
<string name="keyfile_does_not_exist">Arquivo chave não existe.</string>
|
||||
<string name="keyfile_is_empty">Arquivo chave está vazio.</string>
|
||||
<string name="copy_field">Cópia de %1$s</string>
|
||||
<string name="menu_form_filling_settings">Preenchimento de formulário</string>
|
||||
<string name="menu_copy">Cópia</string>
|
||||
<string name="menu_move">Mover</string>
|
||||
<string name="menu_paste">Colar</string>
|
||||
<string name="menu_cancel">Cancelar</string>
|
||||
<string name="menu_fingerprint_remove_key">Remover a chave de impressão digital</string>
|
||||
<string name="menu_file_selection_read_only">Apenas leitura</string>
|
||||
<string name="menu_open_file_read_and_write">Leitura e escrita</string>
|
||||
<string name="protection">Proteção</string>
|
||||
<string name="read_only">Apenas leitura</string>
|
||||
<string name="read_only_warning">KeePass DX não possui permissão para escrever no local do banco de dados, então ele será aberto como apenas leitura.</string>
|
||||
<string name="read_only_kitkat_warning">Começando com o Android KitKat, alguns dispositivos não permitem mais escrita para o cartão de memória.</string>
|
||||
<string name="recentfile_title">Histórico de arquivos recentes</string>
|
||||
<string name="recentfile_summary">Lembre-se de nome de arquivos usados recentemente</string>
|
||||
<string name="encryption_explanation">Algoritmo para encriptar o banco de dados. (Senhas, usuários, notas e todos os dados no banco de dados são encriptados com o algoritmo selecionado)</string>
|
||||
<string name="kdf_explanation">Para gerar uma chave para o algoritmo de encriptação, a chave mestre comprimida (SHA-256) é transformada usando uma função de derivação de chave (com um salt aleatório).</string>
|
||||
<string name="memory_usage">Uso de memória</string>
|
||||
<string name="memory_usage_explanation">Quantidade de memória (in bytes binários) a ser usada pela função de derivação de chave.</string>
|
||||
<string name="parallelism">Paralelismo</string>
|
||||
<string name="parallelism_explanation">Grau de paralelismo (ou seja, número de threads) usado pela função de derivação de chave.</string>
|
||||
<string name="sort_menu">Ordenar</string>
|
||||
<string name="sort_ascending">Ascendente</string>
|
||||
<string name="sort_groups_before">Grupos antes</string>
|
||||
<string name="sort_recycle_bin_bottom">Lixeira no fundo</string>
|
||||
<string name="sort_title">Ordenar por título</string>
|
||||
<string name="sort_username">Ordenar por nome de usuário</string>
|
||||
<string name="sort_creation_time">Ordenar por data de criação</string>
|
||||
<string name="sort_last_modify_time">Ordenar por última modificação</string>
|
||||
<string name="sort_last_access_time">Ordenar por último acesso</string>
|
||||
<string name="search_results">Resultados da pesquisa</string>
|
||||
<string name="use_saf_summary">Use o Framework de Acesso de Armazenamento do Android para navegação de arquivos (KitKat e posterior)</string>
|
||||
<string name="use_saf_title">Framework de Acesso de Armazenamento</string>
|
||||
<string name="warning">Aviso</string>
|
||||
<string name="warning_password_encoding">O formato .kdb suporta apenas o conjunto de caracteres Latin1. Sua senha pode conter caracteres fora desse conjunto de caracteres. Todos os caracteres não-Latin1 são convertidos para o mesmo caractere, o que reduz a segurança de sua senha. Recomenda-se alterar sua senha.</string>
|
||||
<string name="warning_empty_password">Você realmente quer usar uma string vazia como senha?</string>
|
||||
<string name="warning_no_encryption_key">Você tem certeza que não quer usar uma chave de encriptação?</string>
|
||||
<string name="configure_fingerprint">Impressão digital suportada, mas não configurada para dispositivo</string>
|
||||
<string name="scanning_fingerprint">Esperando por impressão digital</string>
|
||||
<string name="encrypted_value_stored">Senha encriptada armazenada</string>
|
||||
<string name="fingerprint_invalid_key">Problema de chave de impressão digital inválida. Recupere sua senha.</string>
|
||||
<string name="fingerprint_not_recognized">Impressão digital não reconhecida</string>
|
||||
<string name="fingerprint_error">Problema da Impressão digital: %1$s</string>
|
||||
<string name="store_with_fingerprint">Use Impressão digital para armazenar essa senha</string>
|
||||
<string name="no_password_stored">Ainda não há nenhuma senha armazenada nesse banco de dados</string>
|
||||
<string name="history">Histórico</string>
|
||||
<string name="appearance">Aparência</string>
|
||||
<string name="general">Geral</string>
|
||||
<string name="autofill">Preenchimento automático</string>
|
||||
<string name="autofill_service_name">Serviço de Preenchimento Automático do KeePass DX</string>
|
||||
<string name="autofill_sign_in_prompt">Entre com o KeePass DX</string>
|
||||
<string name="set_autofill_service_title">Definir como serviço de preenchimento automático padrão</string>
|
||||
<string name="set_autofill_service_summary">Habilite o serviço para preencher formulários em outros aplicativos facilmente</string>
|
||||
<string name="password_size_title">Tamanho da senha</string>
|
||||
<string name="password_size_summary">Defina o tamanho padrão para senhas geradas</string>
|
||||
<string name="list_password_generator_options_title">Caracteres da senha</string>
|
||||
<string name="list_password_generator_options_summary">Definir os caracteres do gerador de senha padrão</string>
|
||||
<string name="clipboard_notifications_title">Notificações da área de transferência</string>
|
||||
<string name="clipboard_notifications_summary">Habilite notificações da área de transferência para copiar campos de entrada</string>
|
||||
<string name="clipboard_warning">Alguns dispositivos não podem excluir automaticamente os dados da área de transferência. Se o seu gerenciador não permitir essa exclusão, você terá que excluir manualmente o item copiado do histórico da área de transferência.</string>
|
||||
<string name="lock">Bloquear</string>
|
||||
<string name="lock_database_screen_off_title">Bloqueio de tela</string>
|
||||
<string name="lock_database_screen_off_summary">Bloqueie o banco de dados quando a tela estiver desligada</string>
|
||||
<string name="fingerprint_quick_unlock_title">Como configurar impressões digitais para desbloqueio rápido?</string>
|
||||
<string name="fingerprint_setting_text">Defina sua impressão digital pessoal para seu dispositivo</string>
|
||||
<string name="fingerprint_setting_way_text">Configurações -> Segurança -> Impressão Digital</string>
|
||||
<string name="fingerprint_type_password_text">Digite sua senha no KeePass DX</string>
|
||||
<string name="fingerprint_scan_to_store">Escaneie sua impressão digital para armazenar sua senha mestre com segurança</string>
|
||||
<string name="fingerprint_scan_to_open">Escaneie sua impressão digital quando a caixa de seleção de senha estiver desmarcada para abrir o banco de dados</string>
|
||||
<string name="usage">Uso</string>
|
||||
<string name="fingerprint">Impressão Digital</string>
|
||||
<string name="fingerprint_enable_title">Esperando Impressão digital</string>
|
||||
<string name="fingerprint_enable_summary">Habilite a abertura do banco de dados com sua Impressão digital</string>
|
||||
<string name="fingerprint_delete_all_title">Apague chaves de encriptação</string>
|
||||
<string name="fingerprint_delete_all_summary">Apague todas as chaves de encriptação relacionadas ao reconhecimento de Impressões digitais</string>
|
||||
<string name="fingerprint_delete_all_warning">Tem certeza que você quer apagar todas as chaves relacionadas as Impressões digitais?</string>
|
||||
<string name="unavailable_feature_text">Não é possível iniciar esse recurso.</string>
|
||||
<string name="unavailable_feature_version">Sua versão do Android %1$s não corresponde a a versão mínima %2$s necessária.</string>
|
||||
<string name="unavailable_feature_hardware">Hardware não foi detectado.</string>
|
||||
<string name="file_name">Nome do arquivo</string>
|
||||
<string name="path">Caminho</string>
|
||||
<string name="assign_master_key">Defina uma chave mestre</string>
|
||||
<string name="create_keepass_file">Crie um arquivo keepass</string>
|
||||
<string name="bytes">Bytes</string>
|
||||
<string name="full_file_path_enable_title">Caminho do Arquivo</string>
|
||||
<string name="full_file_path_enable_summary">Veja o caminho inteiro do arquivo</string>
|
||||
<string name="recycle_bin_title">Use a Lixeira</string>
|
||||
<string name="recycle_bin_summary">Mova um grupo ou entrada para a Lixeira antes de apagar</string>
|
||||
<string name="permission_external_storage_rationale_write_database">KeePass DX precisa de permissão de armazenamento externo para escrever um banco de dados</string>
|
||||
<string name="permission_external_storage_rationale_read_database">KeePass DX precisa de permissão de armazenamento externo para ler uma URI não fornecida pelo Provedor de Conteúdo</string>
|
||||
<string name="permission_external_storage_denied">Permissão de armazenamento externo negada</string>
|
||||
<string name="permission_external_storage_never_ask">Não é possível fazer essa ação sem permissão de armazenamento externo</string>
|
||||
<string name="monospace_font_fields_enable_title">Fonte dos Campos</string>
|
||||
<string name="monospace_font_fields_enable_summary">Mude a fonte dos campos para melhor visualização de caracteres</string>
|
||||
<string name="auto_open_file_uri_title">Abrir automaticamente o arquivo selecionado</string>
|
||||
<string name="auto_open_file_uri_summary">Automaticamente abra o arquivo da tela de seleção depois de uma seleção no gerenciador de arquivos</string>
|
||||
<string name="allow_copy_password_title">Cópia da senha</string>
|
||||
<string name="allow_copy_password_summary">Permita a cópia da senha e de campos protegidos para a área de transferência.</string>
|
||||
<string name="allow_copy_password_warning">AVISO: A área de transferência é compartilhada por todos os aplicativos. Se dados sensíveis forme copiados, outros programas podem recuperá-lo.</string>
|
||||
<string name="warning_disabling_storage_access_framework">AVISO: desativar essa função pode resultar na inabilidade de abrir ou salvar banco de dados</string>
|
||||
<string name="open_link_database">Link do arquivo Kdbx a ser aberto</string>
|
||||
<string name="database_name_title">Nome do banco de dados</string>
|
||||
<string name="database_description_title">Descrição do banco de dados</string>
|
||||
<string name="database_version_title">Versão do banco de dados</string>
|
||||
<string name="text_appearance">Aparência do texto</string>
|
||||
<string name="application_appearance">Aparência do aplicativo</string>
|
||||
<string name="other">Outros</string>
|
||||
|
||||
<string name="keyboard">Teclado</string>
|
||||
<string name="magic_keyboard_title">Magikeyboard</string>
|
||||
<string name="magic_keyboard_summary">Ative um teclado customizado que popula suas senhas e todos os campos de identidade facilmente.</string>
|
||||
<string name="magic_keyboard_preference_title">Configurações do Magikeyboard</string>
|
||||
<string name="magic_keyboard_configure_title">Como configurar um teclado para preenchimento de campos com segurança?</string>
|
||||
<string name="magic_keyboard_activate_setting_text">Ative o Magikeyboard nas configurações de dispositivo.</string>
|
||||
<string name="magic_keyboard_activate_setting_path_1_text">Configurações -> Idioma e Entrada -> Teclado Atual -> Selecionar Teclado</string>
|
||||
<string name="magic_keyboard_activate_setting_path_2_text">ou (Configurações -> Sistema -> Idioma e Entrada -> Teclado Virtual -> Gerenciar Teclados)</string>
|
||||
<string name="keyboards_choose_magikeyboard_text">Escolha o Magikeyboard quando precisar preencher um formulário.</string>
|
||||
<string name="keyboards_swicth_magikeyboard_text">Você pode facilmente trocar de seu teclado principal para o Magikeyboard com o botão de idioma em seu teclado, segure a barra de espaço de seu teclado, ou se não estivar disponível, com :</string>
|
||||
<string name="keyboard_select_entry_text">Selecione uma entrada com a chave.</string>
|
||||
<string name="keyboard_fill_field_text">Preencha seus campos com elementos da entrada.</string>
|
||||
<string name="keyboard_lock_database_text">Bloqueie o banco de dados.</string>
|
||||
<string name="keyboard_back_main_keyboard_text">Volte ao seu teclado principal.</string>
|
||||
|
||||
<string name="allow_no_password_title">Não permitir senha</string>
|
||||
<string name="allow_no_password_summary">Ative o botão de abertura se nenhuma identificação de senha for selecionada.</string>
|
||||
<string name="enable_read_only_title">Apenas leitura</string>
|
||||
<string name="enable_read_only_summary">Por padrão, abra um banco de dados no modo apenas leitura.</string>
|
||||
|
||||
<string name="enable_education_screens_title">Telas de educação</string>
|
||||
<string name="enable_education_screens_summary">Destaque os elementos para aprender como o aplicativo funciona</string>
|
||||
<string name="reset_education_screens_title">Redefinir telas de educação</string>
|
||||
<string name="reset_education_screens_summary">Redefinir a exibição de itens educacionais</string>
|
||||
<string name="reset_education_screens_text">Telas de educação redefinidas</string>
|
||||
<string name="education_create_database_title">Crie um arquivo de banco de dados</string>
|
||||
<string name="education_create_database_summary">Você ainda não conhece o KeePass DX, crie seu primeiro arquivo de gerenciamento de senhas.</string>
|
||||
<string name="education_select_database_title">Abra um banco de dados existente</string>
|
||||
<string name="education_select_database_summary">Você já usou um gerenciador KeePass. Basta abrir o arquivo Kdbx do seu navegador de arquivos.</string>
|
||||
<string name="education_open_link_database_title">Um link para a localização do seu arquivo é suficiente</string>
|
||||
<string name="education_open_link_database_summary">Você também pode abrir seu banco com um link físico (com file:// e content:// por exemplo).</string>
|
||||
<string name="education_new_node_title">Adicione novos itens ao seu banco</string>
|
||||
<string name="education_new_node_summary">Adicione entradas para gerenciar suas identidades digitais.
|
||||
\n
|
||||
\nAdicione grupos (o equivalente de pastas) para organizar suas entradas e seu banco de dados.</string>
|
||||
<string name="education_search_title">Pesquise facilmente suas entradas</string>
|
||||
<string name="education_search_summary">Pesquise entradas por título, nome de usuário ou outros campos para recuperar facilmente suas senhas.</string>
|
||||
<string name="education_fingerprint_title">Desbloqueie seu banco de dados com sua Impressão digital</string>
|
||||
<string name="education_fingerprint_summary">Faça o link entre sua senha e sua impressão digital para desbloquear facilmente seu banco de dados.</string>
|
||||
<string name="education_entry_edit_title">Modifique a entrada</string>
|
||||
<string name="education_entry_edit_summary">Editar a sua entrada com campos personalizados, você pode adicionar referências para o conjunto de dados entre campos de entradas diferentes.</string>
|
||||
<string name="education_generate_password_title">Crie uma senha forte</string>
|
||||
<string name="education_generate_password_summary">Gere uma senha forte para associar a sua entrada, defina-a facilmente de acordo com os critérios do formulário e não esqueça de uma senha difícil, mas segura.</string>
|
||||
<string name="education_entry_new_field_title">Adicione campos customizados</string>
|
||||
<string name="education_entry_new_field_summary">Se desejar registrar um campo básico não fornecido, basta preencher um novo campo que você também pode proteger visualmente.</string>
|
||||
<string name="education_unlock_title">Desbloqueie seu banco de dados</string>
|
||||
<string name="education_read_only_title">Habilitar apenas leitura</string>
|
||||
<string name="education_read_only_summary">Altere o modo de abertura para a sessão.
|
||||
\n
|
||||
\nNo modo somente leitura, você evita alterações não intencionais no banco de dados.
|
||||
\n
|
||||
\nNo modo de gravação, você pode adicionar, excluir ou modificar todos os elementos que desejar.</string>
|
||||
<string name="education_field_copy_title">Copiar um campo</string>
|
||||
<string name="education_field_copy_summary">Copie um campo facilmente para colá-lo onde quiser
|
||||
\n
|
||||
\nVocê pode usar vários métodos de preenchimento de formulários. Use o que você preferir!</string>
|
||||
<string name="education_lock_title">Bloqueie o banco de dados</string>
|
||||
<string name="education_lock_summary">Bloquear seu banco de dados rapidamente, você pode parametrizar o aplicativo para bloqueá-lo depois de um tempo e quando a tela se apaga.</string>
|
||||
<string name="education_sort_title">Ordenar itens</string>
|
||||
<string name="education_sort_summary">Classifique entradas e grupos de acordo com parâmetros específicos.</string>
|
||||
<string name="education_donation_title">Participar</string>
|
||||
<string name="education_donation_summary">Participe para aumentar a estabilidade, a segurança e adicionar mais recursos.</string>
|
||||
|
||||
<string name="html_text_ad_free">Ao contrário de muitos aplicativos de gerenciamento de senhas, este aplicativo é <strong>livre de anúncios</strong>, <strong>código-fonte aberto</strong> e não recupera dados pessoais em seus servidores, mesmo em sua versão gratuita.</string>
|
||||
<string name="html_text_buy_pro">Ao comprar a versão pro, você terá acesso a este <strong>recurso visual</strong> e ajudará especialmente a <strong>a realização de projetos comunitários. </strong></string>
|
||||
<string name="html_text_feature_generosity">Este <strong>recurso visual</strong> está disponível graças à sua generosidade.</string>
|
||||
<string name="html_text_donation">Para manter a nossa liberdade e estar sempre ativo, contamos com a sua <strong>contribuição.</strong></string>
|
||||
|
||||
<string name="html_text_dev_feature">Esse recurso está <strong>em desenvolvimento</strong> e exige que sua <strong>contribuição</strong> para que esteja disponível em breve.</string>
|
||||
<string name="html_text_dev_feature_buy_pro">Ao comprar a versão <strong>pro</strong>,</string>
|
||||
<string name="html_text_dev_feature_contibute"><strong>contribuindo </strong>,</string>
|
||||
<string name="html_text_dev_feature_encourage">Você está incentivando os desenvolvedores a criar <strong>novos recursos</strong> e a <strong>corrigir erros </strong> de acordo com suas observações.</string>
|
||||
<string name="html_text_dev_feature_thanks">Obrigado por sua contribuição.</string>
|
||||
<string name="html_text_dev_feature_work_hard">Estamos trabalhando duro para lançar esse recurso o mais rápido possível.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Não esqueça de manter seu aplicativo atualizado.</string>
|
||||
|
||||
<string name="download">Baixar</string>
|
||||
<string name="contribute">Contribuir</string>
|
||||
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
|
||||
<string name="kdf_AES">AES-KDF</string>
|
||||
<string name="kdf_Argon2">Argon2</string>
|
||||
|
||||
<string name="style_choose_title">Selecione um tema</string>
|
||||
<string name="style_choose_summary">Alterar o tema do aplicativo, alterando as cores</string>
|
||||
<string name="icon_pack_choose_title">Selecione um pacote de ícones</string>
|
||||
<string name="icon_pack_choose_summary">Alterar o pacote de ícones do aplicativo</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Menu FAB -->
|
||||
<style name="KeepassDXStyle.v21.FabMenu" parent="KeepassDXStyle.TextAppearance.DefaultTextOnPrimary">
|
||||
<style name="KeepassDXStyle.v21.FabMenu" parent="KeepassDXStyle.TextAppearance.Default.TextOnPrimary">
|
||||
<item name="android:elevation">4dp</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--
|
||||
Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
<string name="brackets">括号</string>
|
||||
<string name="browser_intall_text"> 浏览文件需要安装Open Intents File Manager软件,点下面安装。由于一些文件管理软件的差异,在你第一次浏览时可能无法正常工作。</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="clipboard_cleared">剪贴板已清除。</string>
|
||||
<string name="clipboard_timeout">剪贴板超时。</string>
|
||||
<string name="clipboard_cleared">剪贴板已清空</string>
|
||||
<string name="clipboard_timeout">剪贴板超时</string>
|
||||
<string name="clipboard_timeout_summary">复制用户名或密码到剪贴板后清除的时间</string>
|
||||
<string name="select_to_copy">复制%1$s到剪贴板</string>
|
||||
<string name="creating_db_key">创建数据库密钥…</string>
|
||||
<string name="creating_db_key">创建数据库密钥…</string>
|
||||
<string name="database">数据库</string>
|
||||
<string name="decrypting_db">解密数据库内容中…</string>
|
||||
<string name="decrypting_db">解密数据库内容中…</string>
|
||||
<string name="default_checkbox">使用这做为我的默认数据库</string>
|
||||
<string name="digits">数字</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Kunzisoft;软件不带有绝对担保;是自由软件,您可在遵循GPL 3或者更高版本的情况下重新发布。中文简繁体翻译:wangkf@gmail.com</string>
|
||||
@@ -91,7 +91,7 @@
|
||||
<string name="length">长度</string>
|
||||
<string name="list_size_title">群列表尺寸</string>
|
||||
<string name="list_size_summary">群列表中的文本尺寸</string>
|
||||
<string name="loading_database">加载数据库中…</string>
|
||||
<string name="loading_database">加载数据库中…</string>
|
||||
<string name="lowercase">小写</string>
|
||||
<string name="maskpass_title">密码掩膜</string>
|
||||
<string name="maskpass_summary">默认隐藏密码</string>
|
||||
@@ -112,8 +112,8 @@
|
||||
<string name="no_results">没有搜索结果</string>
|
||||
<string name="no_url_handler">没有这个链接的处理程序。</string>
|
||||
<string name="open_recent">打开最近数据库:</string>
|
||||
<string name="progress_create">创建新数据库中…</string>
|
||||
<string name="progress_title">工作中…</string>
|
||||
<string name="progress_create">创建新数据库中…</string>
|
||||
<string name="progress_title">工作中…</string>
|
||||
<string name="remember_keyfile_summary">记住密钥文件的位置</string>
|
||||
<string name="remember_keyfile_title">保存密钥文件</string>
|
||||
<string name="remove_from_filelist">移除</string>
|
||||
@@ -122,7 +122,7 @@
|
||||
<string name="rounds">加密次数</string>
|
||||
<string name="rounds_explanation">更高级的加密次数对暴力攻击能提供额外保护,但也会增加加载和保存的时间。</string>
|
||||
<string name="rounds_hint">次数</string>
|
||||
<string name="saving_database">正在保存数据库…</string>
|
||||
<string name="saving_database">正在保存数据库…</string>
|
||||
<string name="space">空格</string>
|
||||
<string name="search_label">搜索</string>
|
||||
<string name="sort_db">数据库的排序顺序</string>
|
||||
@@ -153,4 +153,22 @@
|
||||
<item>中</item>
|
||||
<item>大</item>
|
||||
</string-array>
|
||||
<string name="add_string">添加字符串</string>
|
||||
<string name="encryption">加密</string>
|
||||
<string name="beta_dontask">不再显示</string>
|
||||
<string name="extended_ASCII">拓展版ASCⅡ码</string>
|
||||
<string name="allow">允许</string>
|
||||
<string name="clipboard_error_title">剪切板错误</string>
|
||||
<string name="clipboard_error">某些三星Android手机由于剪切板有bug导致无法从应用复制。更多信息参见:</string>
|
||||
<string name="clipboard_error_clear">清空剪切板失败</string>
|
||||
<string name="clipboard_swipe_clean">滑动以清空剪切板</string>
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
|
||||
<string name="kdf_AES">AES-KDF</string>
|
||||
<string name="kdf_Argon2">Argon2</string>
|
||||
|
||||
<string name="style_choose_title">选择主题</string>
|
||||
<string name="icon_pack_choose_title">选择图标包</string>
|
||||
<string name="icon_pack_choose_summary">切换应用图标包</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--
|
||||
Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
-->
|
||||
<resources>
|
||||
<string name="about_feedback">回饋:</string>
|
||||
<string name="about_homepage">主頁:</string>
|
||||
<string name="about_homepage">首頁:</string>
|
||||
<string name="about_description">KeePass DX是KeePass密碼管理軟體的Android版本。</string>
|
||||
<string name="accept">接受</string>
|
||||
<string name="add_entry">添加條目</string>
|
||||
@@ -28,21 +28,21 @@
|
||||
<string name="app_timeout">應用程式超時</string>
|
||||
<string name="app_timeout_summary">應用程式處於非活動時鎖定資料庫。</string>
|
||||
<string name="application">應用程式</string>
|
||||
<string name="menu_app_settings">應用程式設置</string>
|
||||
<string name="menu_app_settings">應用程式設定</string>
|
||||
<string name="brackets">括弧</string>
|
||||
<string name="browser_intall_text"> 流覽檔需要安裝Open Intents File Manager軟體,點下面安裝。由於一些檔管理軟體的差異,在你第一次流覽時可能無法正常工作。</string>
|
||||
<string name="browser_intall_text">流覽檔需要安裝Open Intents File Manager軟體,點下面安裝。由於一些檔管理軟體的差異,在你第一次瀏覽時可能無法正常工作。</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="clipboard_cleared">剪貼板已清除。</string>
|
||||
<string name="clipboard_timeout">剪貼板超時。</string>
|
||||
<string name="clipboard_cleared">剪貼板已清除</string>
|
||||
<string name="clipboard_timeout">剪貼板超時</string>
|
||||
<string name="clipboard_timeout_summary">複製用戶名或密碼到剪貼板後清除的時間</string>
|
||||
<string name="select_to_copy">複製%1$s到剪貼板</string>
|
||||
<string name="creating_db_key">創建資料庫密鑰…</string>
|
||||
<string name="creating_db_key">創建資料庫密鑰…</string>
|
||||
<string name="database">資料庫</string>
|
||||
<string name="decrypting_db">解密資料庫內容中…</string>
|
||||
<string name="default_checkbox">使用這做為我的默認資料庫</string>
|
||||
<string name="decrypting_db">解密資料庫內容中…</string>
|
||||
<string name="default_checkbox">使用這作為我的預設資料庫</string>
|
||||
<string name="digits">數字</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Kunzisoft;軟體不帶有絕對擔保;是自由軟體,您可在遵循GPL 3或者更高版本的情況下重新發佈。中文簡繁體翻譯:wangkf@gmail.com</string>
|
||||
<string name="select_database_file">輸入資料庫名</string>
|
||||
<string name="select_database_file">選擇一個已存在之資料庫</string>
|
||||
<string name="entry_accessed">訪問時間</string>
|
||||
<string name="entry_cancel">取消</string>
|
||||
<string name="entry_comment">備註</string>
|
||||
@@ -61,21 +61,21 @@
|
||||
<string name="error_could_not_create_parent">無法創建上級目錄。</string>
|
||||
<string name="error_database_exists">文件已存在。</string>
|
||||
<string name="error_failed_to_launch_link">運行鏈結失敗。</string>
|
||||
<string name="error_filename_required">請求一個檔案名:</string>
|
||||
<string name="error_file_not_create">不能創建檔:</string>
|
||||
<string name="error_invalid_db">非法資料庫。</string>
|
||||
<string name="error_filename_required">檔案名稱為必填.</string>
|
||||
<string name="error_file_not_create">不能創建檔案:</string>
|
||||
<string name="error_invalid_db">無效的資料庫或無法辨識的主密鑰。</string>
|
||||
<string name="error_invalid_path">非法路徑。</string>
|
||||
<string name="error_no_name">用戶名是必須的。</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>
|
||||
<string name="error_rounds_not_number">次數必須是數位。</string>
|
||||
<string name="error_rounds_too_large">次數太大。最大設置到2147483648。</string>
|
||||
<string name="error_title_required">標題是必填項。</string>
|
||||
<string name="error_pass_match">密碼不正確。</string>
|
||||
<string name="error_rounds_not_number">次數必須是數字。</string>
|
||||
<string name="error_rounds_too_large">次數太多。最大設置到2147483648。</string>
|
||||
<string name="error_title_required">標題為必填。</string>
|
||||
<string name="error_wrong_length">長度欄位輸入一個正整數</string>
|
||||
<string name="file_not_found">文件未找到。</string>
|
||||
<string name="file_browser">檔流覽</string>
|
||||
<string name="file_browser">檔案管理器</string>
|
||||
<string name="generate_password">生成密碼</string>
|
||||
<string name="hint_conf_pass">確認密碼</string>
|
||||
<string name="hint_generated_password">生成密碼</string>
|
||||
@@ -84,23 +84,23 @@
|
||||
<string name="hint_length">長度</string>
|
||||
<string name="password">密碼</string>
|
||||
<string name="hint_pass">密碼</string>
|
||||
<string name="install_from_play_store">從電子市場安裝</string>
|
||||
<string name="install_from_f_droid">從網路安裝</string>
|
||||
<string name="InvalidPassword">非法的密碼或密鑰檔。</string>
|
||||
<string name="install_from_play_store">從 Play 商店安裝</string>
|
||||
<string name="install_from_f_droid">從 F-Droid 安裝</string>
|
||||
<string name="InvalidPassword">無效的密碼或密鑰檔。</string>
|
||||
<string name="invalid_db_sig">資料庫格式無法識別。</string>
|
||||
<string name="length">長度</string>
|
||||
<string name="list_size_title">群列表尺寸</string>
|
||||
<string name="list_size_summary">群列表中的文本尺寸</string>
|
||||
<string name="loading_database">載入資料庫中…</string>
|
||||
<string name="loading_database">載入資料庫中…</string>
|
||||
<string name="lowercase">小寫</string>
|
||||
<string name="maskpass_title">密碼掩膜</string>
|
||||
<string name="maskpass_summary">默認隱藏密碼</string>
|
||||
<string name="maskpass_title">密碼遮罩</string>
|
||||
<string name="maskpass_summary">預設隱藏密碼</string>
|
||||
<string name="menu_about">關於</string>
|
||||
<string name="menu_change_key">改變主密鑰</string>
|
||||
<string name="settings">設置</string>
|
||||
<string name="menu_db_settings">資料庫設置</string>
|
||||
<string name="menu_change_key">變更主密鑰</string>
|
||||
<string name="settings">設定</string>
|
||||
<string name="menu_db_settings">資料庫設定</string>
|
||||
<string name="menu_delete">刪除</string>
|
||||
<string name="menu_donate">捐贈</string>
|
||||
<string name="menu_donate">贊助</string>
|
||||
<string name="menu_edit">編輯</string>
|
||||
<string name="menu_hide_password">隱藏密碼</string>
|
||||
<string name="menu_lock">鎖定資料庫</string>
|
||||
@@ -111,20 +111,20 @@
|
||||
<string name="never">從不</string>
|
||||
<string name="no_results">沒有搜索結果</string>
|
||||
<string name="no_url_handler">沒有這個鏈結的處理程式。</string>
|
||||
<string name="open_recent">打開最近資料庫:</string>
|
||||
<string name="progress_create">創建新資料庫中…</string>
|
||||
<string name="progress_title">工作中…</string>
|
||||
<string name="open_recent">最近打開的資料庫:</string>
|
||||
<string name="progress_create">創建新資料庫中…</string>
|
||||
<string name="progress_title">工作中…</string>
|
||||
<string name="remember_keyfile_summary">記住密鑰檔的位置</string>
|
||||
<string name="remember_keyfile_title">保存密鑰檔</string>
|
||||
<string name="remove_from_filelist">移除</string>
|
||||
<string name="encryption_rijndael">Rijndael加密(AES)</string>
|
||||
<string name="root">Root</string>
|
||||
<string name="rounds">加密次數</string>
|
||||
<string name="rounds_explanation">更高級的加密次數對暴力攻擊能提供額外保護,但也會增加載入和保存的時間。</string>
|
||||
<string name="rounds_explanation">更高級的加密次數對暴力攻擊能提供額外保護,但也會增加讀取和保存的時間。</string>
|
||||
<string name="rounds_hint">次數</string>
|
||||
<string name="saving_database">正在保存資料庫…</string>
|
||||
<string name="saving_database">正在保存資料庫…</string>
|
||||
<string name="space">空格</string>
|
||||
<string name="search_label">搜索</string>
|
||||
<string name="search_label">搜尋</string>
|
||||
<string name="sort_db">資料庫的排序順序</string>
|
||||
<string name="special">特別</string>
|
||||
<string name="search">條目名稱/說明</string>
|
||||
@@ -132,10 +132,10 @@
|
||||
<string name="underline">強調</string>
|
||||
<string name="unsupported_db_version">不支援的資料庫版本。</string>
|
||||
<string name="uppercase">大寫</string>
|
||||
<string name="warning_read_only">你的SD卡目前是唯讀狀態。您可能無法將更改保存到資料庫。</string>
|
||||
<string name="warning_unmounted">你的SD卡目前尚未安裝在您的設備上。你將無法載入或創建您的資料庫。</string>
|
||||
<string name="warning_read_only">你的SD卡目前是唯讀狀態。您可能將無法保存任何變更到資料庫。</string>
|
||||
<string name="warning_unmounted">你的SD卡目前尚未安裝在您的設備上。你將無法讀或創建您的資料庫。</string>
|
||||
|
||||
<string name="education_unlock_summary">輸入密碼和/或一個密鑰檔來解鎖你的資料庫 </string>
|
||||
<string name="education_unlock_summary">輸入密碼和/或一個密鑰檔來解鎖你的資料庫.</string>
|
||||
|
||||
<string-array name="timeout_options">
|
||||
<item>5秒</item>
|
||||
@@ -153,4 +153,30 @@
|
||||
<item>中</item>
|
||||
<item>大</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
<string name="beta_dontask">下次不要再顯示</string>
|
||||
<string name="extended_ASCII">增強的ASCII</string>
|
||||
<string name="allow">允許</string>
|
||||
<string name="clipboard_error_title">剪貼簿錯誤</string>
|
||||
<string name="clipboard_error">部份 Samsung 手機在複製到剪貼簿時會產生錯誤,詳細內容:</string>
|
||||
<string name="clipboard_error_clear">清除剪貼簿錯誤</string>
|
||||
<string name="clipboard_swipe_clean">現在清除剪貼簿</string>
|
||||
<string name="error_autofill_enable_service">自動填入服務無法啟用。</string>
|
||||
<string name="error_move_folder_in_itself">無法移動一個群組至自己本身。</string>
|
||||
<string name="invalid_algorithm">無效的演算法。</string>
|
||||
<string name="keyfile_does_not_exist">密鑰檔不存在。</string>
|
||||
<string name="keyfile_is_empty">密鑰檔是空白的。</string>
|
||||
<string name="menu_form_filling_settings">表格填入</string>
|
||||
<string name="menu_copy">複製</string>
|
||||
<string name="menu_move">移動</string>
|
||||
<string name="menu_paste">貼上</string>
|
||||
<string name="menu_cancel">取消</string>
|
||||
<string name="menu_showpass">顯示密碼</string>
|
||||
<string name="menu_fingerprint_remove_key">移除指紋密鑰</string>
|
||||
<string name="menu_file_selection_read_only">唯讀</string>
|
||||
<string name="menu_open_file_read_and_write">讀寫</string>
|
||||
<string name="omitbackup_title">不要搜尋備份的項目</string>
|
||||
<string name="protection">保護</string>
|
||||
<string name="read_only">唯讀</string>
|
||||
<string name="read_only_warning">KeePass DX 無法存取資料庫所在位置,將以唯讀模式開啟資料庫。</string>
|
||||
<string name="read_only_kitkat_warning">Adnroid 4.4 開始,許多裝置不允許應用程式對 SD 卡進行寫入。</string>
|
||||
</resources>
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
<string name="maskpass_key" translatable="false">maskpass</string>
|
||||
<string name="omitbackup_key" translatable="false">omitbackup</string>
|
||||
<string name="recentfile_key" translatable="false">recentfile</string>
|
||||
<string name="list_entries_show_username_key" translatable="false">list_entries_show_username_key</string>
|
||||
<string name="list_size_key" translatable="false">list_size</string>
|
||||
<string name="show_beta_warning" translatable="false">show_beta_warning</string>
|
||||
<string name="show_read_only_warning" translatable="false">show_read_only_warning</string>
|
||||
@@ -77,6 +78,7 @@
|
||||
<string name="monospace_font_fields_enable_key" translatable="false">monospace_font_extra_fields_enable_key</string>
|
||||
<string name="auto_open_file_uri_key" translatable="false">auto_open_file_uri_key</string>
|
||||
<string name="allow_copy_password_key" translatable="false">allow_copy_password_key</string>
|
||||
<string name="allow_copy_password_first_time_key" translatable="false">allow_copy_password_first_time_key</string>
|
||||
<string name="database_general_key" translatable="false">database_general_key</string>
|
||||
<string name="database_name_key" translatable="false">database_name_key</string>
|
||||
<string name="database_description_key" translatable="false">database_description_key</string>
|
||||
@@ -88,6 +90,7 @@
|
||||
<string name="education_select_db_key" translatable="false">education_select_db_key</string>
|
||||
<string name="education_open_link_db_key" translatable="false">education_open_link_db_key</string>
|
||||
<string name="education_unlock_key" translatable="false">education_unlock_key</string>
|
||||
<string name="education_read_only_key" translatable="false">education_read_only_key</string>
|
||||
<string name="education_search_key" translatable="false">education_search_key</string>
|
||||
<string name="education_new_node_key" translatable="false">education_new_node_key</string>
|
||||
<string name="education_sort_key" translatable="false">education_sort_key</string>
|
||||
@@ -102,6 +105,7 @@
|
||||
<string name="magic_keyboard_key" translatable="false">magic_keyboard_key</string>
|
||||
<string name="magic_keyboard_preference_key" translatable="false">magic_keyboard_preference_key</string>
|
||||
<string name="allow_no_password_key" translatable="false">allow_no_password_key</string>
|
||||
<string name="enable_read_only_key" translatable="false">enable_read_only_key</string>
|
||||
|
||||
<bool name="maskpass_default" translatable="false">true</bool>
|
||||
<bool name="keyfile_default" translatable="false">true</bool>
|
||||
@@ -116,14 +120,17 @@
|
||||
<bool name="sort_group_before_default" translatable="false">true</bool>
|
||||
<bool name="sort_ascending_default" translatable="false">true</bool>
|
||||
<bool name="sort_recycle_bin_bottom_default" translatable="false">true</bool>
|
||||
<bool name="list_entries_show_username_default" translatable="false">true</bool>
|
||||
<bool name="monospace_font_fields_enable_default" translatable="false">true</bool>
|
||||
<bool name="auto_open_file_uri_default" translatable="false">true</bool>
|
||||
<bool name="allow_copy_password_default" translatable="false">false</bool>
|
||||
<bool name="allow_copy_password_first_time_default" translatable="false">true</bool>
|
||||
<bool name="enable_education_screens_default" translatable="false">true</bool>
|
||||
<bool name="education_create_db_default" translatable="false">false</bool>
|
||||
<bool name="education_select_db_default" translatable="false">false</bool>
|
||||
<bool name="education_open_link_db_default" translatable="false">false</bool>
|
||||
<bool name="education_unlock_default" translatable="false">false</bool>
|
||||
<bool name="education_read_only_default" translatable="false">false</bool>
|
||||
<bool name="education_search_default" translatable="false">false</bool>
|
||||
<bool name="education_new_node_default" translatable="false">false</bool>
|
||||
<bool name="education_sort_default" translatable="false">false</bool>
|
||||
@@ -135,6 +142,7 @@
|
||||
<bool name="education_screen_reclicked_default" translatable="false">false</bool>
|
||||
<bool name="magic_keyboard_default" translatable="false">false</bool>
|
||||
<bool name="allow_no_password_default" translatable="false">true</bool>
|
||||
<bool name="enable_read_only_default" translatable="false">false</bool>
|
||||
|
||||
<string name="app_timeout_default" translatable="false">300000</string>
|
||||
<string name="clipboard_timeout_default" translatable="false">60000</string>
|
||||
@@ -151,11 +159,12 @@
|
||||
<item translatable="false">-1</item>
|
||||
</string-array>
|
||||
|
||||
<integer name="list_icon_size_default" translatable="false">32</integer>
|
||||
<string name="list_size_default" translatable="false">18</string>
|
||||
<dimen name="list_icon_size_default" translatable="false">32dp</dimen>
|
||||
<integer name="list_small_size_default" translatable="false">13</integer>
|
||||
<string name="list_size_default" translatable="false">16</string>
|
||||
<string-array name="list_size_values">
|
||||
<item translatable="false">14</item>
|
||||
<item translatable="false">18</item>
|
||||
<item translatable="false">@string/list_size_default</item>
|
||||
<item translatable="false">22</item>
|
||||
</string-array>
|
||||
|
||||
|
||||
@@ -23,23 +23,24 @@
|
||||
<string name="about_description">KeePass DX is an Android implementation of the KeePass password manager.</string>
|
||||
<string name="accept">Accept</string>
|
||||
<string name="add_entry">Add entry</string>
|
||||
<string name="edit_entry">Edit entry</string>
|
||||
<string name="add_group">Add group</string>
|
||||
<string name="add_string">Add string</string>
|
||||
<string name="encryption">Encryption</string>
|
||||
<string name="encryption_algorithm">Encryption Algorithm</string>
|
||||
<string name="key_derivation_function">Key Derivation Function</string>
|
||||
<string name="app_timeout">Application timeout</string>
|
||||
<string name="app_timeout_summary">Time before locking database when the application is inactive.</string>
|
||||
<string name="application">Application</string>
|
||||
<string name="app_timeout">App timeout</string>
|
||||
<string name="app_timeout_summary">Time before locking database when the app is inactive</string>
|
||||
<string name="application">App</string>
|
||||
<string name="beta_dontask">Don\'t show again</string>
|
||||
<string name="brackets">Brackets</string>
|
||||
<string name="extended_ASCII">Extended ASCII</string>
|
||||
<string name="browser_intall_text">File browsing requires the Open Intents File Manager, click below to install it. Due to some quirks in the file manager, browsing may not work correctly, the first time you browse.</string>
|
||||
<string name="browser_intall_text">File browsing requires the OpenIntents File Manager to be installed, click below to do so. Due to some quirks in the file manager, browsing may not work correctly the first time around.</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="allow">Allow</string>
|
||||
<string name="clipboard_cleared">Clipboard cleared</string>
|
||||
<string name="clipboard_error_title">Clipboard error</string>
|
||||
<string name="clipboard_error">Some Samsung Android phones have a bug in the clipboard implementation that causes copying from applications to fail. For more details go to:</string>
|
||||
<string name="clipboard_error">Some Samsung Android phones have a bug in the clipboard implementation causing copying from apps to fail. More details:</string>
|
||||
<string name="clipboard_error_clear">Clearing the clipboard failed</string>
|
||||
<string name="clipboard_timeout">Clipboard timeout</string>
|
||||
<string name="clipboard_timeout_summary">Time before clearing clipboard after copying username or password</string>
|
||||
@@ -48,7 +49,7 @@
|
||||
<string name="creating_db_key">Creating database key…</string>
|
||||
<string name="database">Database</string>
|
||||
<string name="decrypting_db">Decrypting database contents…</string>
|
||||
<string name="default_checkbox">Use this as my default database</string>
|
||||
<string name="default_checkbox">Use this as default database</string>
|
||||
<string name="digits">Digits</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Kunzisoft comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 3 or later.</string>
|
||||
<string name="entry_accessed">Accessed</string>
|
||||
@@ -64,30 +65,32 @@
|
||||
<string name="entry_save">Save</string>
|
||||
<string name="entry_title">Title</string>
|
||||
<string name="entry_url">URL</string>
|
||||
<string name="entry_user_name">User Name</string>
|
||||
<string name="error_arc4">The ArcFour stream cipher is not supported.</string>
|
||||
<string name="error_can_not_handle_uri">KeePass DX cannot handle this uri.</string>
|
||||
<string name="entry_user_name">Username</string>
|
||||
<string name="error_arc4">The ARCFOUR stream cipher is not supported.</string>
|
||||
<string name="error_can_not_handle_uri">KeePass DX cannot handle this URI.</string>
|
||||
<string name="error_could_not_create_parent">Could not create parent directory.</string>
|
||||
<string name="error_database_exists">This file already exists.</string>
|
||||
<string name="error_failed_to_launch_link">Failed to launch link.</string>
|
||||
<string name="error_failed_to_launch_link">Could not open link.</string>
|
||||
<string name="error_filename_required">A filename is required.</string>
|
||||
<string name="error_file_not_create">Could not create file:</string>
|
||||
<string name="error_invalid_db">Invalid database or unrecognized master key.</string>
|
||||
<string name="error_invalid_path">Invalid path.</string>
|
||||
<string name="error_no_name">A name 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_out_of_memory">The phone ran out of memory while parsing your database. It may be too large for your device.</string>
|
||||
<string name="error_load_database">Database can\'t be load</string>
|
||||
<string name="error_load_database_KDF_memory">Unable to load the key, try to decrease the memory used by the KDF.</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>
|
||||
<string name="error_rounds_not_number">Rounds must be a number.</string>
|
||||
<string name="error_rounds_too_large">Rounds too big. Setting to 2147483648.</string>
|
||||
<string name="error_string_key">A field name is required for each string.</string>
|
||||
<string name="error_pass_match">The passwords do not match.</string>
|
||||
<string name="error_rounds_not_number">\"Rounds\" must be a number.</string>
|
||||
<string name="error_rounds_too_large">\"Rounds\" too big. Setting to 2147483648.</string>
|
||||
<string name="error_string_key">Each string must have a field name.</string>
|
||||
<string name="error_title_required">A title is required.</string>
|
||||
<string name="error_wrong_length">Enter a positive integer on length field</string>
|
||||
<string name="error_wrong_length">Enter a positive whole number in the \"Length\" field</string>
|
||||
<string name="error_autofill_enable_service">Autofill service can\'t be enabled.</string>
|
||||
<string name="error_move_folder_in_itself">Unable to move a group in itself.</string>
|
||||
<string name="error_move_folder_in_itself">Unable to move a group into itself.</string>
|
||||
<string name="field_name">Field Name</string>
|
||||
<string name="field_value">Field value</string>
|
||||
<string name="field_value">Field Value</string>
|
||||
<string name="file_not_found">File not found.</string>
|
||||
<string name="file_not_found_content">File not found. Try reopening from your content provider.</string>
|
||||
<string name="file_browser">File Browser</string>
|
||||
@@ -104,9 +107,11 @@
|
||||
<string name="InvalidPassword">Invalid password or key file.</string>
|
||||
<string name="invalid_algorithm">Invalid algorithm.</string>
|
||||
<string name="invalid_db_sig">Database format not recognized.</string>
|
||||
<string name="keyfile_does_not_exist">Key file does not exist.</string>
|
||||
<string name="keyfile_is_empty">Key file is empty.</string>
|
||||
<string name="keyfile_does_not_exist">No keyfile exists.</string>
|
||||
<string name="keyfile_is_empty">The keyfile is empty.</string>
|
||||
<string name="length">Length</string>
|
||||
<string name="list_entries_show_username_title">Display usernames</string>
|
||||
<string name="list_entries_show_username_summary">Display usernames in entry lists</string>
|
||||
<string name="list_size_title">Size of list items</string>
|
||||
<string name="list_size_summary">Text size in the element list</string>
|
||||
<string name="loading_database">Loading database…</string>
|
||||
@@ -117,7 +122,7 @@
|
||||
<string name="menu_change_key">Change Master Key</string>
|
||||
<string name="copy_field">Copy of %1$s</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="menu_app_settings">Application settings</string>
|
||||
<string name="menu_app_settings">App settings</string>
|
||||
<string name="menu_form_filling_settings">Form filling</string>
|
||||
<string name="menu_db_settings">Database settings</string>
|
||||
<string name="menu_donate">Donate</string>
|
||||
@@ -134,20 +139,22 @@
|
||||
<string name="menu_showpass">Show pass</string>
|
||||
<string name="menu_fingerprint_remove_key">Remove the fingerprint key</string>
|
||||
<string name="menu_url">Go to URL</string>
|
||||
<string name="menu_file_selection_read_only">Read only</string>
|
||||
<string name="menu_open_file_read_and_write">Read and write</string>
|
||||
<string name="minus">Minus</string>
|
||||
<string name="never">Never</string>
|
||||
<string name="no_results">No search results</string>
|
||||
<string name="no_url_handler">No handler for this url.</string>
|
||||
<string name="no_url_handler">No handler for this URL.</string>
|
||||
<string name="select_database_file">Select an existing database</string>
|
||||
<string name="open_recent">Recent databases :</string>
|
||||
<string name="omitbackup_title">Don\'t search backup entries</string>
|
||||
<string name="omitbackup_summary">Omit \'Backup\' group from search results (applies to .kdb only)</string>
|
||||
<string name="open_recent">Recent databases:</string>
|
||||
<string name="omitbackup_title">Don\'t search through backup entries</string>
|
||||
<string name="omitbackup_summary">Omit \'Backup\' group from search results (only applies to .kdb files)</string>
|
||||
<string name="progress_create">Creating new database…</string>
|
||||
<string name="progress_title">Working…</string>
|
||||
<string name="protection">Protection</string>
|
||||
<string name="read_only">Read-only</string>
|
||||
<string name="read_only_warning">KeePass DX does not have permission to write to the database location, so your database will be opened read-only.</string>
|
||||
<string name="read_only_kitkat_warning">Starting with Android KitKat, some devices no longer allow applications to write to the sdcard.</string>
|
||||
<string name="read_only_warning">KeePass DX does not have permission to write to your database location, so it will be opened read-only.</string>
|
||||
<string name="read_only_kitkat_warning">Starting with Android KitKat, some devices no longer allow apps to write to the SD card.</string>
|
||||
<string name="recentfile_title">Recent file history</string>
|
||||
<string name="recentfile_summary">Remember recently used file names</string>
|
||||
<string name="remember_keyfile_summary">Remember the location of keyfiles</string>
|
||||
@@ -155,7 +162,7 @@
|
||||
<string name="remove_from_filelist">Remove</string>
|
||||
<string name="root">Root</string>
|
||||
<string name="encryption_explanation">Algorithm to encrypt the whole database. (Passwords, usernames, notes and all data in the database are encrypted with the selected algorithm)</string>
|
||||
<string name="kdf_explanation">In order to generate the key for the encryption algorithm, the compressed master key (SHA-256) is transformed using a key derivation function (with a random salt).</string>
|
||||
<string name="kdf_explanation">To generate the key for the encryption algorithm, the compressed master key (SHA-256) is transformed using a randomly salted key derivation function.</string>
|
||||
<string name="rounds">Transform Rounds</string>
|
||||
<string name="rounds_explanation">Higher encryption rounds provide additional protection against brute force attacks, but can really slow down loading and saving.</string>
|
||||
<string name="rounds_hint">rounds</string>
|
||||
@@ -167,38 +174,38 @@
|
||||
<string name="space">Space</string>
|
||||
<string name="search_label">Search</string>
|
||||
<string name="sort_menu">Sort</string>
|
||||
<string name="sort_ascending">Ascending</string>
|
||||
<string name="sort_ascending">Lowest first ↓</string>
|
||||
<string name="sort_groups_before">Groups before</string>
|
||||
<string name="sort_recycle_bin_bottom">Recycle bin at the bottom</string>
|
||||
<string name="sort_db">DB sort order</string>
|
||||
<string name="sort_title">Sort by Title</string>
|
||||
<string name="sort_username">Sort by Username</string>
|
||||
<string name="sort_creation_time">Sort by Creation Time</string>
|
||||
<string name="sort_last_modify_time">Sort by Last Modify Time</string>
|
||||
<string name="sort_last_access_time">Sort by Last Access Time</string>
|
||||
<string name="sort_title">Title</string>
|
||||
<string name="sort_username">Username</string>
|
||||
<string name="sort_creation_time">Creation Time</string>
|
||||
<string name="sort_last_modify_time">Last Modification Time</string>
|
||||
<string name="sort_last_access_time">Last Access Time</string>
|
||||
<string name="special">Special</string>
|
||||
<string name="search">Search</string>
|
||||
<string name="search_results">Search results</string>
|
||||
<string name="underline">Underline</string>
|
||||
<string name="unsupported_db_version">Unsupported database version.</string>
|
||||
<string name="uppercase">Upper-case</string>
|
||||
<string name="use_saf_summary">Use Android Storage Access Framework for file browsing (KitKat and later)</string>
|
||||
<string name="use_saf_summary">Use Android storage access (SAF) framework for file browsing (KitKat and later)</string>
|
||||
<string name="use_saf_title">Storage Access Framework</string>
|
||||
<string name="warning">Warning</string>
|
||||
<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_password_encoding">Your password may contain letters not supported by the Latin-1 character set used by .kdb files. As these are all converted to the same letter, it is recomended to change your password to make it safer.</string>
|
||||
<string name="warning_read_only">Your SD card currently read-only. You may not be able to save changes to your database.</string>
|
||||
<string name="warning_unmounted">Your SD card 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 your 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="configure_fingerprint">The fingerprint is supported but not configured for this device</string>
|
||||
<string name="scanning_fingerprint">Listening for fingerprints</string>
|
||||
<string name="encrypted_value_stored">Encrypted password stored</string>
|
||||
<string name="fingerprint_invalid_key">Invalid fingerprint key problem. Restore your password.</string>
|
||||
<string name="fingerprint_not_recognized">Fingerprint not recognized</string>
|
||||
<string name="fingerprint_error">Fingerprint problem : %1$s</string>
|
||||
<string name="fingerprint_error">Fingerprint problem: %1$s</string>
|
||||
<string name="store_with_fingerprint">Use fingerprint to store this password</string>
|
||||
<string name="no_password_stored">No password stored yet for this database</string>
|
||||
<string name="no_password_stored">No password stored for this database yet</string>
|
||||
<string name="history">History</string>
|
||||
<string name="appearance">Appearance</string>
|
||||
<string name="general">General</string>
|
||||
@@ -206,92 +213,97 @@
|
||||
<string name="autofill_service_name">KeePass DX Autofill Service</string>
|
||||
<string name="autofill_sign_in_prompt">Sign in with KeePass DX</string>
|
||||
<string name="set_autofill_service_title">Set default Autofill service</string>
|
||||
<string name="set_autofill_service_summary">Enable the service to easily fill out forms from other applications</string>
|
||||
<string name="set_autofill_service_summary">Enable the service to easily fill out forms from other apps</string>
|
||||
<string name="password_size_title">Password size</string>
|
||||
<string name="password_size_summary">Set the default size of the generated password</string>
|
||||
<string name="list_password_generator_options_title">Password characters</string>
|
||||
<string name="list_password_generator_options_summary">Set the default password generator characters</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
<string name="clipboard">Clipboard</string>
|
||||
<string name="clipboard_notifications_title">Clipboard Notifications</string>
|
||||
<string name="clipboard_notifications_summary">Enable clipboard notifications to copy entry fields</string>
|
||||
<string name="clipboard_warning">Some devices are not able to automatically delete clips from the clipboard. If your manager does not allow this deletion, you will have to manually delete the copied item from your clipboard history.</string>
|
||||
<string name="clipboard_warning">If your device is not able to delete clips from the clipboard automatically, delete the copied item from your clipboard history manually.</string>
|
||||
<string name="lock">Lock</string>
|
||||
<string name="lock_database_screen_off_title">Screen lock</string>
|
||||
<string name="lock_database_screen_off_summary">Lock the database when the screen is off</string>
|
||||
<string name="fingerprint_quick_unlock_title">How to configure fingerprint for quick unlocking ?</string>
|
||||
<string name="fingerprint_quick_unlock_title">How to configure fingerprint for quick unlocking?</string>
|
||||
<string name="fingerprint_setting_text">Set your personnal fingerprint for your device in </string>
|
||||
<string name="fingerprint_setting_way_text">Settings -> Security -> Fingerprint</string>
|
||||
<!-- Use ← for LTR languages -->
|
||||
<string name="fingerprint_setting_way_text">\"Settings\" → \"Security\" → \"Fingerprint\"</string>
|
||||
<string name="fingerprint_type_password_text">Type your password in Keepass DX</string>
|
||||
<string name="fingerprint_scan_to_store">Scan your fingerprint to store your master password securely</string>
|
||||
<string name="fingerprint_scan_to_open">Scan your fingerprint when the password checkbox is unchecked to open the database</string>
|
||||
<string name="usage">Usage</string>
|
||||
<string name="fingerprint">Fingerprint</string>
|
||||
<string name="fingerprint_enable_title">Fingerprint listening</string>
|
||||
<string name="fingerprint_enable_title">Scanning for fingerprints</string>
|
||||
<string name="fingerprint_enable_summary">Enable database opening by fingerprint</string>
|
||||
<string name="fingerprint_delete_all_title">Delete encryption keys</string>
|
||||
<string name="fingerprint_delete_all_summary">Delete all encryption keys related to fingerprint recognition</string>
|
||||
<string name="fingerprint_delete_all_warning">Are you sure you want to delete all the keys related to fingerprints?</string>
|
||||
<string name="unavailable_feature_text">Can not start this feature.</string>
|
||||
<string name="unavailable_feature_version">Your Android version %1$s is not the minimum version %2$s required.</string>
|
||||
<string name="unavailable_feature_text">Could not start this feature.</string>
|
||||
<string name="unavailable_feature_version">Your Android version %1$s does not meet the minimum version %2$s required.</string>
|
||||
<string name="unavailable_feature_hardware">The hardware is not detected.</string>
|
||||
<string name="file_name">File name</string>
|
||||
<string name="file_name">Filename</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 name="create_keepass_file">Create a KeePass file</string>
|
||||
<string name="bytes">Bytes</string>
|
||||
<string name="full_file_path_enable_title">File Path</string>
|
||||
<string name="full_file_path_enable_summary">View the full file path</string>
|
||||
<string name="recycle_bin_title">Use Recycle Bin</string>
|
||||
<string name="recycle_bin_summary">Move a group or entry to the Recycle Bin before deleting</string>
|
||||
<string name="permission_external_storage_rationale_write_database">KeePass DX need external storage permission to write a database</string>
|
||||
<string name="permission_external_storage_rationale_read_database">KeePass DX need external storage permission to read an URI not provided by a Content Provider</string>
|
||||
<string name="recycle_bin_summary">Move a group or entry to the \"Recycle bin\" before deleting</string>
|
||||
<string name="permission_external_storage_rationale_write_database">KeePass DX needs external storage permission to write a database</string>
|
||||
<string name="permission_external_storage_rationale_read_database">KeePass DX needs external storage permission to read an URI not provided by a content provider</string>
|
||||
<string name="permission_external_storage_denied">External storage permission denied</string>
|
||||
<string name="permission_external_storage_never_ask">Can\'t perform the action without external storage permission</string>
|
||||
<string name="monospace_font_fields_enable_title">Fields Font</string>
|
||||
<string name="monospace_font_fields_enable_summary">Change the font of the fields for better character visibility</string>
|
||||
<string name="monospace_font_fields_enable_title">Field Font</string>
|
||||
<string name="monospace_font_fields_enable_summary">Change the font used in fields for better character visibility</string>
|
||||
<string name="auto_open_file_uri_title">Auto open selected file</string>
|
||||
<string name="auto_open_file_uri_summary">Automatically open a file from the selection screen after a selection in the file browser</string>
|
||||
<string name="auto_open_file_uri_summary">Open a file from the selection screen automatically after a selection is made in the file browser</string>
|
||||
<string name="allow_copy_password_title">Copy of password</string>
|
||||
<string name="allow_copy_password_summary">Allow the copy of the password and protected fields to the clipboard.</string>
|
||||
<string name="allow_copy_password_warning">WARNING : The clipboard is shared by all applications. If sensitive data is copied, other software may recover it.</string>
|
||||
<string name="warning_disabling_storage_access_framework">WARNING : disabling this feature may result in an inability to open or save the databases</string>
|
||||
<string name="open_link_database">Link of the Kdbx file to open</string>
|
||||
<string name="allow_copy_password_summary">Allow the copy of the password and protected fields to the clipboard</string>
|
||||
<string name="allow_copy_password_warning">WARNING: The clipboard is shared by all apps. If sensitive data is copied, other software may recover it.</string>
|
||||
<string name="warning_disabling_storage_access_framework">WARNING: Disabling this feature may result in an inability to open or save databases</string>
|
||||
<string name="open_link_database">Link of the KDBX file to open</string>
|
||||
<string name="database_name_title">Database name</string>
|
||||
<string name="database_description_title">Database description</string>
|
||||
<string name="database_version_title">Database version</string>
|
||||
<string name="text_appearance">Text appearance</string>
|
||||
<string name="application_appearance">Application appearance</string>
|
||||
<string name="application_appearance">App appearance</string>
|
||||
<string name="other">Other</string>
|
||||
|
||||
<string name="keyboard">Keyboard</string>
|
||||
<string name="magic_keyboard_title">Magikeyboayd</string>
|
||||
<string name="magic_keyboard_summary">Activate a custom keyboard that populates your passwords and all your identity fields easily.</string>
|
||||
<string name="magic_keyboard_title">Magikeyboard</string>
|
||||
<string name="magic_keyboard_summary">Activate a custom keyboard that populates your passwords and all your identity fields easily</string>
|
||||
<string name="magic_keyboard_preference_title">Magikeyboard settings</string>
|
||||
<string name="magic_keyboard_configure_title">How to configure the keyboard for secure form filling?</string>
|
||||
<string name="magic_keyboard_activate_setting_text">Activate the Magikeyboard in the device setting.</string>
|
||||
<string name="magic_keyboard_activate_setting_path_1_text">Settings -> Language & input -> Current keyboard -> CHOOSE KEYBOARDS</string>
|
||||
<string name="magic_keyboard_activate_setting_path_2_text">or (Settings -> System -> Language & input -> Virtual keyboard -> Manage keyboards)</string>
|
||||
<string name="magic_keyboard_activate_setting_text">Activate the Magikeyboard in the device settings.</string>
|
||||
<!-- Use ← for LTR languages -->
|
||||
<string name="magic_keyboard_activate_setting_path_1_text">\"Settings\" → \"Language & input\" → \"Current Keyboard\" and pick one.</string>
|
||||
<!-- Use ← for LTR languages -->
|
||||
<string name="magic_keyboard_activate_setting_path_2_text">or (\"Settings\" → \"Language & input\" → \"Virtual keyboard\" and pick one.")</string>
|
||||
<string name="keyboards_choose_magikeyboard_text">Choose the Magikeyboard when you need to fill a form.</string>
|
||||
<string name="keyboards_swicth_magikeyboard_text">You can easily switch from your main keyboard to Magikeyboard with the language button of your keyboard, a long press on the space bar of your keyboard, or, if it is not available, with : </string>
|
||||
<string name="keyboard_select_entry_text">Select your entry with the key.</string>
|
||||
<string name="keyboard_fill_field_text">Fill in your fields with the elements of the entry.</string>
|
||||
<string name="keyboard_fill_field_text">Fill in your fields using the elements of the entry.</string>
|
||||
<string name="keyboard_lock_database_text">Lock the database.</string>
|
||||
<string name="keyboard_back_main_keyboard_text">Go back to your main keyboard.</string>
|
||||
|
||||
<string name="allow_no_password_title">Allow no password</string>
|
||||
<string name="allow_no_password_summary">Enable the open button if no password identification is selected.</string>
|
||||
<string name="allow_no_password_summary">Enable the open button if no password identification is selected</string>
|
||||
<string name="enable_read_only_title">Read only</string>
|
||||
<string name="enable_read_only_summary">By default, open databases read-only</string>
|
||||
|
||||
<string name="enable_education_screens_title">Education screens</string>
|
||||
<string name="enable_education_screens_summary">Highlight the elements to learn how the application works</string>
|
||||
<string name="enable_education_screens_summary">Highlight the elements to learn how the app works</string>
|
||||
<string name="reset_education_screens_title">Reset education screens</string>
|
||||
<string name="reset_education_screens_summary">Reset the display of education items</string>
|
||||
<string name="reset_education_screens_text">Education screens reseted</string>
|
||||
<string name="reset_education_screens_text">Education screens reset</string>
|
||||
<string name="education_create_database_title">Create your database file</string>
|
||||
<string name="education_create_database_summary">You don\'t know KeePass DX yet, create your first password management file.</string>
|
||||
<string name="education_select_database_title">Open an existing database</string>
|
||||
<string name="education_select_database_summary">You have already used a KeePass manager. Just open your Kdbx file from your file browser.</string>
|
||||
<string name="education_select_database_summary">You have already used a KeePass manager. Just open your KDBX file from your file browser.</string>
|
||||
<string name="education_open_link_database_title">A link to the location of your file is sufficient</string>
|
||||
<string name="education_open_link_database_summary">You can also open your base with a physical link (With file:// and content:// for example).</string>
|
||||
<string name="education_open_link_database_summary">You can also open your database with a physical link (with file:// and content:// for example).</string>
|
||||
<string name="education_new_node_title">Add new items to your base</string>
|
||||
<string name="education_new_node_summary">Add entries to manage your digital identities.\n\nAdd groups (the equivalent of folders) to organize your entries and your database.</string>
|
||||
<string name="education_search_title">Easily search your entries</string>
|
||||
@@ -299,24 +311,26 @@
|
||||
<string name="education_fingerprint_title">Unlock your database with your fingerprint</string>
|
||||
<string name="education_fingerprint_summary">Make the link between your password and your fingerprint to easily unlock your database.</string>
|
||||
<string name="education_entry_edit_title">Edit the entry</string>
|
||||
<string name="education_entry_edit_summary">Edit your entry with custom fields, you can add references to pool data between fields of different entries.</string>
|
||||
<string name="education_entry_edit_summary">Edit your entry with custom fields, references to pool data can be added between fields of different entries.</string>
|
||||
<string name="education_generate_password_title">Create a strong password</string>
|
||||
<string name="education_generate_password_summary">Generate a strong password to associate with your entry, easily define it according to the criteria of the form and don\'t forget a difficult but secure password.</string>
|
||||
<string name="education_generate_password_summary">Generate a strong password to associate with your entry, easily define it according to the criteria of the form and don\'t forget secure password you can remember.</string>
|
||||
<string name="education_entry_new_field_title">Add custom fields</string>
|
||||
<string name="education_entry_new_field_summary">You want to register a basic non-supplied field, simply fill in a new one that you can also protect visually.</string>
|
||||
<string name="education_unlock_title">Unlock your database</string>
|
||||
<string name="education_unlock_summary">Enter a password and/or a key file to unlock your database.\n\nRemember to save a copy of your file in a safe place after each modification.</string>
|
||||
<string name="education_unlock_summary">Enter a password and/or a key file to unlock your database.\n\nRemember to save a copy of your .kdbx file in a safe place after each modification.</string>
|
||||
<string name="education_read_only_title">Enable read-only</string>
|
||||
<string name="education_read_only_summary">Change the opening mode for the session.\n\nIn read-only mode, you prevent unintended changes to the database.\n\nIn write mode, you can add, delete, or modify all the elements as you want.</string>
|
||||
<string name="education_field_copy_title">Copy a field</string>
|
||||
<string name="education_field_copy_summary">Copy a field easily to paste it where you want\n\nYou can use several forms filling methods. Use the one you prefer!</string>
|
||||
<string name="education_field_copy_summary">Copy a field easily to paste it where you want\n\nYou can use several forms filling methods. Use the one you prefer.</string>
|
||||
<string name="education_lock_title">Lock the database</string>
|
||||
<string name="education_lock_summary">Lock your database quickly, you can parameter the application to lock it after a while and when the screen goes off.</string>
|
||||
<string name="education_lock_summary">Lock your database quickly, you can set up the app to lock it after a while, and when the screen goes off.</string>
|
||||
<string name="education_sort_title">Sort items</string>
|
||||
<string name="education_sort_summary">Sort entries and groups according to specific parameters.</string>
|
||||
<string name="education_donation_title">Participate</string>
|
||||
<string name="education_donation_summary">Participate to increase the stability, the security and to add more features.</string>
|
||||
<string name="education_donation_summary">Participate to help increase the stability, security and in adding more features.</string>
|
||||
|
||||
<string name="html_text_ad_free">Unlike many password management applications, this app is <strong>ad-free</strong>, <strong>open source</strong> and does not recover personal data on its servers, even in its free version.</string>
|
||||
<string name="html_text_buy_pro">By buying the pro version, you will have access to this <strong>visual feature</strong> and you will help especially to <strong>the realization of community projects.</strong></string>
|
||||
<string name="html_text_ad_free">Unlike many password management apps, this one is <strong>ad-free</strong>, <strong>copylefted libre software</strong> and does not recover personal data on its servers, even in its free version.</string>
|
||||
<string name="html_text_buy_pro">By buying the pro version, you will have access to this <strong>visual feature</strong> and you will especially help <strong>the realization of community projects.</strong></string>
|
||||
<string name="html_text_feature_generosity">This <strong>visual feature</strong> is available thanks to your generosity.</string>
|
||||
<string name="html_text_donation">In order to keep our freedom and to be always active, we count on your <strong>contribution.</strong></string>
|
||||
|
||||
@@ -326,7 +340,7 @@
|
||||
<string name="html_text_dev_feature_encourage">you\'re encouraging developers to create <strong>new features</strong> and to <strong>fix bugs</strong> according to your remarks.</string>
|
||||
<string name="html_text_dev_feature_thanks">Thanks a lot for your contribution.</string>
|
||||
<string name="html_text_dev_feature_work_hard">We are working hard to release this feature quickly.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Do not forget to keep your application up to date.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Do not forget to keep your app up to date.</string>
|
||||
|
||||
<string name="download">Download</string>
|
||||
<string name="contribute">Contribute</string>
|
||||
@@ -337,7 +351,7 @@
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
|
||||
<!-- Key Derivation Functions -->
|
||||
<string name="kdf_AES">AES-KDF</string>
|
||||
<string name="kdf_AES">AES KDF</string>
|
||||
<string name="kdf_Argon2">Argon2</string>
|
||||
|
||||
<string-array name="timeout_options">
|
||||
@@ -358,16 +372,16 @@
|
||||
</string-array>
|
||||
|
||||
<string name="style_choose_title">Select a theme</string>
|
||||
<string name="style_choose_summary">Change the theme of the application by changing the colors</string>
|
||||
<string name="style_choose_summary">Change the app theme by changing the colors</string>
|
||||
<string-array name="list_style_names">
|
||||
<item>Light Theme</item>
|
||||
<item>Night Theme</item>
|
||||
<item>Classic Dark Theme</item>
|
||||
<item>Sky and Ocean Theme</item>
|
||||
<item>Red Volcano Theme</item>
|
||||
<item>Purple Pro Theme</item>
|
||||
<item>Light</item>
|
||||
<item>Night</item>
|
||||
<item>Classic Dark</item>
|
||||
<item>Sky and Ocean</item>
|
||||
<item>Red Volcano</item>
|
||||
<item>Purple Pro</item>
|
||||
</string-array>
|
||||
<string name="icon_pack_choose_title">Select an icon pack</string>
|
||||
<string name="icon_pack_choose_summary">Change the icon pack of the application</string>
|
||||
<string name="icon_pack_choose_summary">Change the icon pack of the app</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -201,13 +201,14 @@
|
||||
<style name="KeepassDXStyle.TextAppearance" parent="android:style/TextAppearance">
|
||||
<item name="android:textColor">?android:attr/textColor</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.Inverse" parent="android:style/TextAppearance">
|
||||
<style name="KeepassDXStyle.TextAppearance.Default.TextOnPrimary" parent="android:style/TextAppearance">
|
||||
<item name="android:textColor">?attr/textColorInverse</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.DefaultTextOnPrimary" parent="android:style/TextAppearance">
|
||||
<item name="android:textColor">?attr/textColorInverse</item>
|
||||
<style name="KeepassDXStyle.TextAppearance.Secondary.TextOnPrimary" parent="KeepassDXStyle.TextAppearance.Default.TextOnPrimary">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textStyle">italic</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.TitleTextOnPrimary" parent="KeepassDXStyle.TextAppearance.DefaultTextOnPrimary">
|
||||
<style name="KeepassDXStyle.TextAppearance.Title.TextOnPrimary" parent="KeepassDXStyle.TextAppearance.Default.TextOnPrimary">
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
@@ -221,8 +222,8 @@
|
||||
<style name="KeepassDXStyle.TextAppearance.Large" parent="KeepassDXStyle.TextAppearance">
|
||||
<item name="android:textSize">18sp</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.FolderTitle" parent="KeepassDXStyle.TextAppearance.Default">
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<style name="KeepassDXStyle.TextAppearance.Secondary" parent="KeepassDXStyle.TextAppearance.Small">
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.Title" parent="KeepassDXStyle.TextAppearance">
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
@@ -236,9 +237,6 @@
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.SecondaryText" parent="KeepassDXStyle.TextAppearance">
|
||||
<item name="android:textSize">14sp</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.TinyText" parent="KeepassDXStyle.TextAppearance">
|
||||
<item name="android:textSize">12sp</item>
|
||||
</style>
|
||||
@@ -269,7 +267,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Menu FAB -->
|
||||
<style name="KeepassDXStyle.v21.FabMenu" parent="KeepassDXStyle.TextAppearance.DefaultTextOnPrimary" />
|
||||
<style name="KeepassDXStyle.v21.FabMenu" parent="KeepassDXStyle.TextAppearance.Default.TextOnPrimary" />
|
||||
<style name="KeepassDXStyle.FabMenu" parent="KeepassDXStyle.v21.FabMenu">
|
||||
<item name="android:textSize">15sp</item>
|
||||
<item name="android:background">@drawable/button_small_background</item>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user