Compare commits

...

61 Commits

Author SHA1 Message Date
J-Jamet
edc7324c1d Merge branch 'release/2.5.0.0beta16' 2018-08-02 11:19:41 +02:00
J-Jamet
b9190e8254 Fix translations 2018-08-02 11:18:59 +02:00
J-Jamet
534878ae99 Merge branch 'translations' into develop 2018-08-02 11:04:39 +02:00
J-Jamet
99bfd21ecc Merge branch 'master' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2018-08-02 11:03:37 +02:00
J-Jamet
cb5c324c9d Fix search / Fix icon - back #138 / Upgrade changelogs 2018-08-02 10:34:04 +02:00
J-Jamet
55dc504f26 Fix visual elements 2018-08-01 15:45:49 +02:00
J-Jamet
ecb0138c90 Add display username settings and rearrange form filling 2018-08-01 12:00:15 +02:00
J-Jamet
0860eeb87f Show website domains if entries given no title #124 and add username 2018-07-31 22:04:41 +02:00
J-Jamet
f08bff61cf Update changelogs 2018-07-31 08:52:58 +02:00
J-Jamet
432aca6465 Fix transparent toolbar 2018-07-30 22:17:23 +02:00
J-Jamet
7cdb8db146 New error message #154 2018-07-30 21:10:11 +02:00
random r
6ba9dedcb8 Translated using Weblate (Italian)
Currently translated at 100,0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2018-07-30 11:59:13 +02:00
random r
6d603608f4 Translated using Weblate (Italian)
Currently translated at 99.3% (319 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2018-07-30 11:58:11 +02:00
Kunzisoft
64f4d9fb84 Translated using Weblate (French)
Currently translated at 99.6% (320 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2018-07-29 14:37:40 +02:00
J-Jamet
60ccc450ae Fix read-only education screen 2018-07-29 09:44:01 +02:00
J-Jamet
ddb5f327a3 Add warning dialog on password copy button and sort settings 2018-07-28 18:00:57 +02:00
J-Jamet
df90ea42eb Deleting points in parameter explanations 2018-07-28 16:18:36 +02:00
Jérémy JAMET
a062d648b3 Merge pull request #158 from comradekingu/patch-1
Spelling: Language rework
2018-07-28 15:56:37 +02:00
J-Jamet
a59ae820b5 Add gray copy icon when copy not available 2018-07-28 15:18:34 +02:00
J-Jamet
228831acdd Upgrade version and add changelogs 2018-07-28 14:29:03 +02:00
J-Jamet
bf15ee43da Populate custom fields in search entry 2018-07-28 14:00:49 +02:00
J-Jamet
608f45677c Fix quick search with magikeyboard 2018-07-28 09:37:26 +02:00
Daniel
1cb15f214b Translated using Weblate (German)
Currently translated at 100.0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2018-07-28 00:37:41 +02:00
Claus Rüdinger
cd4a9e9b03 Translated using Weblate (German)
Currently translated at 100.0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2018-07-28 00:37:40 +02:00
J-Jamet
d6eae56d4f Merge branch 'feature/Search' into develop #26 #147 #153 2018-07-27 22:19:43 +02:00
J-Jamet
b5a87a63dc Fix search fragment 2018-07-27 21:39:26 +02:00
Allan Nordhøy
1eb17c4f34 Language rework 2018-07-27 15:11:56 +02:00
Hadrián Candela
8a6ce1f711 Translated using Weblate (Galician)
Currently translated at 7.4% (24 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2018-07-27 13:38:02 +02:00
J-Jamet
0f22f8af45 Add search title 2018-07-27 10:54:58 +02:00
Tobirium
b2e81e6fd9 Translated using Weblate (German)
Currently translated at 100,0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2018-07-26 23:52:55 +02:00
Daniel
f82eab942d Translated using Weblate (German)
Currently translated at 100,0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2018-07-26 23:52:55 +02:00
J-Jamet
aa29aec40f Add search suggestions 2018-07-26 14:08:48 +02:00
Hadrián Candela
181def52ab Added translation using Weblate (Galician) 2018-07-26 13:01:37 +02:00
HybridGlucose
96d2bd63cc Translated using Weblate (Chinese (Traditional))
Currently translated at 44.5% (143 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2018-07-25 20:36:13 +02:00
Claus Rüdinger
194021a957 Translated using Weblate (German)
Currently translated at 100,0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2018-07-25 18:38:46 +02:00
Daniel
9e307f94ea Translated using Weblate (German)
Currently translated at 100,0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2018-07-25 18:38:45 +02:00
Tobirium
155b2de138 Translated using Weblate (German)
Currently translated at 100,0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2018-07-25 18:38:45 +02:00
J-Jamet
c76c3fd2be Fix fragment duplication 2018-07-25 11:50:18 +02:00
Matheus Gritz
01c5554944 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (321 of 321 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2018-07-24 19:11:13 +02:00
J-Jamet
542cf65b41 Fix timeout and new animation 2018-07-24 18:32:19 +02:00
J-Jamet
f037561a67 Search in fragment 2018-07-24 18:02:08 +02:00
J-Jamet
379263a6d3 Search and Group in one activity 2018-07-24 14:48:03 +02:00
J-Jamet
c420ca01f6 Update Readme 2018-07-23 14:21:46 +02:00
J-Jamet
a1f9db6eee Try to solve the date crash 2018-07-23 14:12:07 +02:00
J-Jamet
c9212174c4 Change text by reset 2018-07-22 12:13:02 +02:00
J-Jamet
0065336377 Merge tag '2.5.0.0beta15' into develop
2.5.0.0beta15
2018-07-19 11:27:47 +02:00
J-Jamet
4f9625a3e1 Merge branch 'release/2.5.0.0beta15' 2018-07-19 11:27:18 +02:00
J-Jamet
7688ebd29b Merge branch 'master' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2018-07-19 11:15:53 +02:00
Claus Rüdinger
3f2a7f1eb3 Translated using Weblate (German)
Currently translated at 99.3% (313 of 315 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2018-07-19 11:08:28 +02:00
Veronica Small
b3d067d0c8 Translated using Weblate (Chinese (Simplified))
Currently translated at 41.9% (132 of 315 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2018-07-19 11:08:28 +02:00
Kunzisoft
a3b4ad5ac1 Translated using Weblate (French)
Currently translated at 100.0% (315 of 315 strings)

Translation: KeePass DX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2018-07-19 11:08:28 +02:00
J-Jamet
e3b329d27f Update version and changelog 2018-07-19 11:01:32 +02:00
J-Jamet
7d10c43822 Fix orientation change 2018-07-19 10:40:36 +02:00
J-Jamet
fcb0d45d39 Fix Magikeyboard string 2018-07-19 08:58:20 +02:00
J-Jamet
5492db0223 Merge branch 'feature/ReadOnlyMode' into develop 2018-07-18 18:51:51 +02:00
J-Jamet
2207b05f5f Fix PwDate 2018-07-18 18:12:43 +02:00
J-Jamet
f15a0c2591 Optimize memory 2018-07-18 17:56:32 +02:00
J-Jamet
92fb22129c #77 Add read-only mode to the floating menu 2018-07-18 16:29:18 +02:00
J-Jamet
ccca9c4400 #77 Add read-only mode 2018-07-18 14:37:39 +02:00
J-Jamet
0597cb4416 #148 fix second element to copy 2018-07-16 22:02:24 +02:00
J-Jamet
0602174e50 Merge tag '2.5.0.0beta14' into develop
2.5.0.0beta14
2018-07-15 10:59:01 +02:00
109 changed files with 3102 additions and 1404 deletions

View File

@@ -1,3 +1,18 @@
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

View File

@@ -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

View File

@@ -6,10 +6,10 @@ android {
defaultConfig {
applicationId "com.kunzisoft.keepass"
minSdkVersion 15
minSdkVersion 14
targetSdkVersion 27
versionCode = 14
versionName = "2.5.0.0beta14"
versionCode = 16
versionName = "2.5.0.0beta16"
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

View File

@@ -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"));

View File

@@ -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());

View File

@@ -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());
}

View File

@@ -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" />

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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,21 +248,129 @@ 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());
@@ -240,67 +379,105 @@ public class GroupActivity extends ListNodesActivity
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 +486,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 +541,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 +702,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 +719,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 +857,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 +871,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 +907,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 +940,7 @@ public class GroupActivity extends ListNodesActivity
return true;
case R.id.menu_search:
onSearchRequested();
//onSearchRequested();
return true;
case R.id.menu_lock:
@@ -710,8 +950,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 +978,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 +1000,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 +1029,7 @@ public class GroupActivity extends ListNodesActivity
class AfterAddNode extends AfterActionNodeOnFinish {
@Override
public void run(PwNode oldNode, PwNode newNode) {
super.run();
@@ -801,6 +1048,7 @@ public class GroupActivity extends ListNodesActivity
class AfterUpdateNode extends AfterActionNodeOnFinish {
@Override
public void run(PwNode oldNode, PwNode newNode) {
super.run();
@@ -886,16 +1134,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();
}
}
}

View File

@@ -0,0 +1,7 @@
package com.kunzisoft.keepass.activities;
import android.content.Intent;
public interface IntentBuildLauncher {
void startActivityForResult(Intent intent);
}

View File

@@ -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();
}
}
}

View File

@@ -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,20 @@ 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);
mAdapter.rebuildList(currentGroup);
assignListToNodeAdapter(listView);
}
@@ -197,7 +195,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 +253,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 +280,7 @@ public class ListNodesFragment extends StylishFragment implements
}
public PwGroup getMainGroup() {
return mCurrentGroup;
return currentGroup;
}
public interface OnScrollListener {

View File

@@ -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);
}
}

View File

@@ -29,6 +29,7 @@ abstract class BasicViewHolder extends RecyclerView.ViewHolder {
View container;
ImageView icon;
TextView text;
TextView subText;
BasicViewHolder(View itemView) {
super(itemView);

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -27,7 +27,6 @@ import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.util.SortedListAdapterCallback;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
@@ -38,11 +37,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 +54,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 +82,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 +99,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 +113,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().getDimension(R.dimen.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 +154,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 +223,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 +331,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);
}

View File

@@ -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;
}
}

View File

@@ -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,52 @@ 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();
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, "This version of PwEntry can't be added 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 +516,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) {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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>() {

View File

@@ -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
/**

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -32,6 +32,8 @@ public abstract class PwIcon implements Parcelable {
protected PwIcon(Parcel in) {}
public abstract boolean isUnknown();
@Override
public int describeContents() {
return 0;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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());
}

View File

@@ -109,8 +109,8 @@ public enum SortNodeEnum {
new EntryNameComparator(ascending),
object1,
object2,
object1.getDisplayTitle()
.compareToIgnoreCase(object2.getDisplayTitle()));
object1.getTitle()
.compareToIgnoreCase(object2.getTitle()));
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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();
}
}
}
}

View File

@@ -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))));
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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));

View File

@@ -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) ) {

View File

@@ -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);
}

View File

@@ -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");

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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();
});

View File

@@ -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;

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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 "";
}
}

View File

@@ -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

View File

@@ -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,25 @@ 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 TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
Float.parseFloat(listSize),
ctx.getResources().getDisplayMetrics());
}
public static int getDefaultPasswordLength(Context ctx) {
@@ -139,12 +156,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 +189,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 +203,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 +283,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.
*

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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:

View File

@@ -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) {

View File

@@ -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,13 @@ public class Util {
applyFontVisibilityTo(context, (TextView) editText);
}
public static float getListTextDefaultSize(Context context) {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
(Float.parseFloat(context.getString(R.string.list_size_default))),
context.getResources().getDisplayMetrics());
}
public static void lockScreenOrientation(Activity activity) {
if (activity != null) {
int currentOrientation = activity.getResources().getConfiguration().orientation;
@@ -86,7 +96,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);
}
}
}

View File

@@ -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) {

View File

@@ -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() {

View File

@@ -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));
}
}

View File

@@ -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);
}
}
}

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"

View File

@@ -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"

View 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>

View 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>

View File

@@ -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 -&gt; Sicherheit -&gt; 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 -&gt; Sprachen &amp; Eingabe -&gt; Aktuelle Tastatur -&gt; TASTATUR ÄNDERN</string>
<string name="magic_keyboard_activate_setting_path_2_text">oder (Einstellungen -&gt; System -&gt; Sprachen &amp; Eingabe -&gt; Bildschirmtastatur -&gt; 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>

View File

@@ -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>

View File

@@ -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 -&gt; Langue et saisie -&gt; Clavier actuel -&gt; CHOISIR LES CLAVIERS</string>
<string name="magic_keyboard_activate_setting_path_2_text">ou (Paramètres -&gt; Système -&gt; Langues et saisie -&gt; Clavier virtuel -&gt; 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>

View 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>

View File

@@ -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 -&gt; Sicurezza -&gt; 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 -&gt; Lingue e immissione -&gt; Tastiera attuale -&gt; SCEGLI TASTIERE</string>
<string name="magic_keyboard_activate_setting_path_2_text">o (Impostazioni -&gt; Sistema -&gt; Lingue e immissione -&gt; Tastiera virtuale -&gt; 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>

View File

@@ -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&#8230;</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&#8230;</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&#8230;</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&#8230;</string>
<string name="progress_title">Trabalhando&#8230;</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&#8230;</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 -&gt; Segurança -&gt; 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 -&gt; Idioma e Entrada -&gt; Teclado Atual -&gt; Selecionar Teclado</string>
<string name="magic_keyboard_activate_setting_path_2_text">ou (Configurações -&gt; Sistema -&gt; Idioma e Entrada -&gt; Teclado Virtual -&gt; 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>

View File

@@ -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>

View File

@@ -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">创建数据库密钥&#8230;</string>
<string name="creating_db_key">创建数据库密钥</string>
<string name="database">数据库</string>
<string name="decrypting_db">解密数据库内容中&#8230;</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">加载数据库中&#8230;</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">创建新数据库中&#8230;</string>
<string name="progress_title">工作中&#8230;</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">正在保存数据库&#8230;</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>

View File

@@ -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">創建資料庫密鑰&#8230;</string>
<string name="creating_db_key">創建資料庫密鑰</string>
<string name="database">資料庫</string>
<string name="decrypting_db">解密資料庫內容中&#8230;</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">載入資料庫中&#8230;</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">創建新資料庫中&#8230;</string>
<string name="progress_title">工作中&#8230;</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">正在保存資料庫&#8230;</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>

View File

@@ -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,12 +159,13 @@
<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>
<dimen name="list_small_size_default" translatable="false">9sp</dimen>
<string name="list_size_default" translatable="false">11</string>
<string-array name="list_size_values">
<item translatable="false">9</item>
<item translatable="false">@string/list_size_default</item>
<item translatable="false">14</item>
<item translatable="false">18</item>
<item translatable="false">22</item>
</string-array>
<string name="list_style_name_light" translatable="false">KeepassDXStyle_Light</string>

View File

@@ -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 -&gt; Security -&gt; 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 &amp; input -> Current keyboard -> CHOOSE KEYBOARDS</string>
<string name="magic_keyboard_activate_setting_path_2_text">or (Settings -> System -> Language &amp; 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 &amp; input\" → \"Current Keyboard\" and pick one.</string>
<!-- Use ← for LTR languages -->
<string name="magic_keyboard_activate_setting_path_2_text">or (\"Settings\" → \"Language &amp; 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 &lt;strong&gt;ad-free&lt;/strong&gt;, &lt;strong&gt;open source&lt;/strong&gt; 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 &lt;strong&gt;visual feature&lt;/strong&gt; and you will help especially to &lt;strong&gt;the realization of community projects.&lt;/strong&gt;</string>
<string name="html_text_ad_free">Unlike many password management apps, this one is &lt;strong&gt;ad-free&lt;/strong&gt;, &lt;strong&gt;copylefted libre software&lt;/strong&gt; 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 &lt;strong&gt;visual feature&lt;/strong&gt; and you will especially help &lt;strong&gt;the realization of community projects.&lt;/strong&gt;</string>
<string name="html_text_feature_generosity">This &lt;strong&gt;visual feature&lt;/strong&gt; 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 &lt;strong&gt;contribution.&lt;/strong&gt;</string>
@@ -326,7 +340,7 @@
<string name="html_text_dev_feature_encourage">you\'re encouraging developers to create &lt;strong&gt;new features&lt;/strong&gt; and to &lt;strong&gt;fix bugs&lt;/strong&gt; 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>

View File

@@ -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