Compare commits

...

15 Commits

Author SHA1 Message Date
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
34 changed files with 761 additions and 208 deletions

View File

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

@@ -6,10 +6,10 @@ android {
defaultConfig {
applicationId "com.kunzisoft.keepass"
minSdkVersion 15
minSdkVersion 14
targetSdkVersion 27
versionCode = 14
versionName = "2.5.0.0beta14"
versionCode = 15
versionName = "2.5.0.0beta15"
multiDexEnabled true
testApplicationId = "com.kunzisoft.keepass.tests"

View File

@@ -78,15 +78,15 @@ 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) {
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 +110,7 @@ public class EntryActivity extends LockingHideActivity {
finish();
return;
}
readOnly = db.isReadOnly();
readOnly = db.isReadOnly() || readOnly;
mShowPassword = !PreferencesUtil.isPasswordMask(this);

View File

@@ -80,6 +80,8 @@ import com.kunzisoft.keepass.view.AddNodeButtonView;
import net.cachapa.expandablelayout.ExpandableLayout;
import static com.kunzisoft.keepass.activities.ReadOnlyHelper.READ_ONLY_DEFAULT;
public class GroupActivity extends ListNodesActivity
implements GroupEditDialogFragment.EditGroupListener,
IconPickerDialogFragment.IconPickerListener,
@@ -88,6 +90,8 @@ public class GroupActivity extends ListNodesActivity
private static final String TAG = GroupActivity.class.getName();
protected static final String GROUP_ID_KEY = "GROUP_ID_KEY";
private Toolbar toolbar;
private ExpandableLayout toolbarPasteExpandableLayout;
@@ -99,7 +103,6 @@ public class GroupActivity extends ListNodesActivity
protected boolean addGroupEnabled = false;
protected boolean addEntryEnabled = false;
protected boolean isRoot = false;
protected boolean readOnly = false;
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";
@@ -107,64 +110,67 @@ public class GroupActivity extends ListNodesActivity
private PwGroup oldGroupToUpdate;
private PwNode nodeToCopy;
private PwNode nodeToMove;
public static void launch(Activity act) {
// 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);
}
}
@@ -254,22 +260,20 @@ public class GroupActivity extends ListNodesActivity
pwGroupId = getIntent().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;
currentGroup = rootGroup;
} else {
currentGroup = db.getPwDatabase().getGroupByGroupId(pwGroupId);
currentGroup = database.getPwDatabase().getGroupByGroupId(pwGroupId);
}
if (currentGroup != null) {
addGroupEnabled = !readOnly;
addEntryEnabled = !readOnly; // TODO consultation mode
isRoot = (currentGroup == root);
addEntryEnabled = !readOnly;
isRoot = (currentGroup == rootGroup);
if (!currentGroup.allowAddEntryIfIsRoot())
addEntryEnabled = !isRoot && addEntryEnabled;
}
@@ -496,7 +500,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.isVisible()) {
TapTargetView.showFor(this,
TapTarget.forView(findViewById(R.id.add_button),
@@ -633,7 +638,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

View File

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

View File

@@ -35,15 +35,16 @@ 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.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.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.selection.EntrySelectionHelper;
import com.kunzisoft.keepass.utils.MenuUtil;
public abstract class ListNodesActivity extends LockingActivity
@@ -51,11 +52,11 @@ public abstract class ListNodesActivity extends LockingActivity
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 Database database;
protected PwGroup rootGroup;
protected PwGroup mCurrentGroup;
protected TextView groupNameView;
@@ -69,15 +70,18 @@ public abstract class ListNodesActivity extends LockingActivity
if ( isFinishing() ) {
return;
}
database = App.getDB();
// Likely the app has been killed exit the activity
if ( ! App.getDB().getLoaded() ) {
if ( ! database.getLoaded() ) {
finish();
return;
}
invalidateOptionsMenu();
rootGroup = database.getPwDatabase().getRootGroup();
mCurrentGroup = retrieveCurrentGroup(savedInstanceState);
initializeListNodesFragment(mCurrentGroup);
@@ -102,7 +106,7 @@ public abstract class ListNodesActivity extends LockingActivity
listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
.findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
if (listNodesFragment == null)
listNodesFragment = ListNodesFragment.newInstance(currentGroup.getId());
listNodesFragment = ListNodesFragment.newInstance(currentGroup, readOnly);
}
/**
@@ -151,7 +155,7 @@ public abstract class ListNodesActivity extends LockingActivity
switch ( item.getItemId() ) {
default:
// Check the time lock before launching settings
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, true);
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, readOnly, true);
return super.onOptionsItemSelected(item);
}
}
@@ -193,7 +197,7 @@ public abstract class ListNodesActivity extends LockingActivity
openGroup((PwGroup) node);
break;
case ENTRY:
EntryActivity.launch(this, (PwEntry) node);
EntryActivity.launch(this, (PwEntry) node, readOnly);
break;
}
}
@@ -205,7 +209,7 @@ public abstract class ListNodesActivity extends LockingActivity
if (checkTimeIsAllowedOrFinish(this)) {
startRecordTime(this);
ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group.getId());
ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group, readOnly);
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
R.anim.slide_in_left, R.anim.slide_out_right)

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,7 +34,6 @@ 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 NodeAdapter.NodeClickCallback nodeClickCallback;
private NodeAdapter.NodeMenuListener nodeMenuListener;
@@ -49,21 +46,14 @@ public class ListNodesFragment extends StylishFragment implements
// Preferences for sorting
private SharedPreferences prefs;
public static ListNodesFragment newInstance(PwGroup group) {
private boolean readOnly;
public static ListNodesFragment newInstance(PwGroup group, boolean readOnly) {
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);
}
ReadOnlyHelper.putReadOnlyInBundle(bundle, readOnly);
ListNodesFragment listNodesFragment = new ListNodesFragment();
listNodesFragment.setArguments(bundle);
return listNodesFragment;
@@ -101,46 +91,33 @@ public class ListNodesFragment extends StylishFragment implements
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
if ( getActivity() != null ) {
setHasOptionsMenu(true);
mCurrentGroup = initCurrentGroup();
if (getActivity() != null) {
mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater());
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState, getArguments());
if (getArguments() != null) {
// Contains all the group in element
if (getArguments().containsKey(GROUP_KEY)) {
mCurrentGroup = getArguments().getParcelable(GROUP_KEY);
}
}
mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater(), readOnly);
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

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

@@ -61,6 +61,7 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
private NodeClickCallback nodeClickCallback;
private NodeMenuListener nodeMenuListener;
private boolean activateContextMenu;
private boolean readOnly;
private int iconGroupColor;
private int iconEntryColor;
@@ -69,12 +70,13 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
* Create node list adapter with contextMenu or not
* @param context Context to use
*/
public NodeAdapter(final Context context, MenuInflater menuInflater) {
public NodeAdapter(final Context context, MenuInflater menuInflater, boolean readOnly) {
this.inflater = LayoutInflater.from(context);
this.menuInflater = menuInflater;
this.context = context;
assignPreferences();
this.activateContextMenu = false;
this.readOnly = readOnly;
this.nodeSortedList = new SortedList<>(PwNode.class, new SortedListAdapterCallback<PwNode>(this) {
@Override public int compare(PwNode item1, PwNode item2) {
@@ -217,7 +219,7 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
// Context menu
if (activateContextMenu) {
holder.container.setOnCreateContextMenuListener(
new ContextMenuBuilder(subNode, nodeMenuListener));
new ContextMenuBuilder(subNode, nodeMenuListener, readOnly));
}
// Assign image and text size
// Relative size of the icon
@@ -287,24 +289,26 @@ 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);
}
MenuItem menuItem = contextMenu.findItem(R.id.menu_open);
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
if (!App.getDB().isReadOnly() && !node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
if (readOnly || node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
contextMenu.removeItem(R.id.menu_edit);
contextMenu.removeItem(R.id.menu_copy);
contextMenu.removeItem(R.id.menu_move);
contextMenu.removeItem(R.id.menu_delete);
} else {
// Edition
menuItem = contextMenu.findItem(R.id.menu_edit);
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
@@ -312,6 +316,9 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
if (node.getType().equals(PwNode.Type.ENTRY)) {
menuItem = contextMenu.findItem(R.id.menu_copy);
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
} else {
// TODO COPY For Group
contextMenu.removeItem(R.id.menu_copy);
}
// Move
menuItem = contextMenu.findItem(R.id.menu_move);

View File

@@ -96,10 +96,14 @@ 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;
try {
jDate = (Date) in.readSerializable();
jDateBuilt = in.readByte() != 0;
in.readByteArray(cDate);
cDateBuilt = in.readByte() != 0;
} catch (Exception e) {
e.printStackTrace();
}
}
@Override

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

@@ -55,9 +55,9 @@ import android.widget.Toast;
import com.getkeepsafe.taptargetview.TapTarget;
import com.getkeepsafe.taptargetview.TapTargetView;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
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.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)) {
@@ -414,7 +429,39 @@ public class PasswordActivity extends StylishActivity
}
});
// TODO make a period for donation
PreferencesUtil.saveEducationPreference(PasswordActivity.this, R.string.education_unlock_key);
PreferencesUtil.saveEducationPreference(PasswordActivity.this,
R.string.education_unlock_key);
} else 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);
}
@Override
public void onOuterCircleClick(TapTargetView view) {
super.onOuterCircleClick(view);
view.dismiss(false);
}
});
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 +1000,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 +1015,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 +1051,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

@@ -31,8 +31,6 @@ 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;
@@ -74,17 +72,16 @@ public class SearchResultsActivity extends ListNodesActivity {
.findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
// Directly get group and not id
if (listNodesFragment == null)
listNodesFragment = ListNodesFragment.newInstance(currentGroup);
listNodesFragment = ListNodesFragment.newInstance(currentGroup, readOnly);
}
@Override
protected PwGroup retrieveCurrentGroup(@Nullable Bundle savedInstanceState) {
Database mDb = App.getDB();
// Likely the app has been killed exit the activity
if ( ! mDb.getLoaded() ) {
if ( ! database.getLoaded() ) {
finish();
}
return mDb.search(getSearchStr(getIntent()).trim());
return database.search(getSearchStr(getIntent()).trim());
}
@Override

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

@@ -158,6 +158,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 +172,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 +252,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

@@ -86,7 +86,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 isVisible() {
return getVisibility() == VISIBLE;
}
public void setAddGroupClickListener(OnClickListener onClickListener) {

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

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

@@ -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>
@@ -341,4 +341,28 @@
<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>
</resources>

View File

@@ -350,4 +350,24 @@
<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>
</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

@@ -88,6 +88,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 +103,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>
@@ -124,6 +126,7 @@
<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 +138,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>

View File

@@ -134,6 +134,8 @@
<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>
@@ -264,7 +266,7 @@
<string name="other">Other</string>
<string name="keyboard">Keyboard</string>
<string name="magic_keyboard_title">Magikeyboayd</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>
@@ -280,6 +282,8 @@
<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="enable_read_only_title">Read only</string>
<string name="enable_read_only_summary">By default, open a database in read-only mode.</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>
@@ -306,6 +310,8 @@
<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_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_lock_title">Lock the database</string>

View File

@@ -28,6 +28,11 @@
android:defaultValue="@bool/allow_no_password_default"
android:title="@string/allow_no_password_title"
android:key="@string/allow_no_password_key"/>
<SwitchPreference
android:summary="@string/enable_read_only_summary"
android:defaultValue="@bool/enable_read_only_default"
android:title="@string/enable_read_only_title"
android:key="@string/enable_read_only_key"/>
</PreferenceCategory>

92
art/ic_read_only.svg Normal file
View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg4830"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="/home/joker/Project/Scratcheck/TestExport.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="ic_read_only.svg">
<defs
id="defs4832" />
<sodipodi:namedview
id="base"
pagecolor="#acacac"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="8"
inkscape:cx="-37.548191"
inkscape:cy="-10.060761"
inkscape:current-layer="g4770"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1023"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1">
<sodipodi:guide
position="0.99999471,22.999999"
orientation="22,0"
id="guide2987" />
<sodipodi:guide
position="0.99999471,0.99999888"
orientation="0,22"
id="guide2989" />
<sodipodi:guide
position="22.999995,0.99999888"
orientation="-22,0"
id="guide2991" />
<sodipodi:guide
position="22.999995,22.999999"
orientation="0,-22"
id="guide2993" />
<inkscape:grid
type="xygrid"
id="grid2989" />
</sodipodi:namedview>
<metadata
id="metadata4835">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-8)">
<g
id="g4770"
transform="matrix(1.7777778,0,0,1.7777778,-205.48441,-31.997877)">
<g
id="Layer_1"
transform="matrix(-0.00397893,0,0,0.00397893,125.58386,23.674135)" />
<path
inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1"
d="m 125.00684,31.305444 0,-6.644528 c 0,-0.263013 -0.21159,-0.47461 -0.4746,-0.47461 l -6.48633,0 c -1.04808,0 -1.89843,0.850344 -1.89843,1.898435 l 0,6.328127 c 0,1.048093 0.85035,1.898437 1.89843,1.898437 l 6.48633,0 c 0.26301,0 0.4746,-0.2116 0.4746,-0.474611 l 0,-0.316409 c 0,-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.36782 z m -6.32812,-4.469236 c 0,-0.06529 0.0534,-0.118652 0.11866,-0.118652 l 4.19238,0 c 0.0653,0 0.11866,0.05343 0.11866,0.118652 l 0,0.39551 c 0,0.06529 -0.0534,0.118653 -0.11866,0.118653 l -4.19238,0 c -0.0653,0 -0.11866,-0.05343 -0.11866,-0.118653 l 0,-0.39551 z m 0,1.265621 c 0,-0.06529 0.0534,-0.118653 0.11866,-0.118653 l 4.19238,0 c 0.0653,0 0.11866,0.05343 0.11866,0.118653 l 0,0.395509 c 0,0.06529 -0.0534,0.118653 -0.11866,0.118653 l -4.19238,0 c -0.0653,0 -0.11866,-0.05342 -0.11866,-0.118653 l 0,-0.395509 z m 5.0111,4.943847 -5.64391,0 c -0.35003,0 -0.63282,-0.282781 -0.63282,-0.632808 0,-0.348045 0.28476,-0.632813 0.63282,-0.632813 l 5.64391,0 c -0.0375,0.338162 -0.0375,0.927466 0,1.265621 z"
id="path4" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

92
art/ic_read_write.svg Normal file
View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg4830"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="/home/joker/Project/Scratcheck/TestExport.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="ic_read_write.svg">
<defs
id="defs4832" />
<sodipodi:namedview
id="base"
pagecolor="#acacac"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="-12.80892"
inkscape:cy="-4.0293631"
inkscape:current-layer="g4770"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1023"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1">
<sodipodi:guide
position="0.99999471,22.999999"
orientation="22,0"
id="guide2987" />
<sodipodi:guide
position="0.99999471,0.99999888"
orientation="0,22"
id="guide2989" />
<sodipodi:guide
position="22.999995,0.99999888"
orientation="-22,0"
id="guide2991" />
<sodipodi:guide
position="39,23"
orientation="0,-22"
id="guide2993" />
<inkscape:grid
type="xygrid"
id="grid2989" />
</sodipodi:namedview>
<metadata
id="metadata4835">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-8)">
<g
id="g4770"
transform="matrix(1.7777778,0,0,1.7777778,-205.48441,-31.997877)">
<g
id="Layer_1"
transform="matrix(-0.00397893,0,0,0.00397893,125.58386,23.674135)" />
<path
style="fill:#ffffff;fill-opacity:1"
d="M 4.375 3 C 2.5117466 3 1 4.5117271 1 6.375 L 1 17.625 C 1 19.488276 2.5117466 21 4.375 21 L 15.90625 21 C 16.373823 21 16.75 20.623825 16.75 20.15625 L 16.75 19.59375 C 16.75 19.330086 16.627331 19.090226 16.4375 18.935547 C 16.289944 18.394137 16.289944 16.851957 16.4375 16.310547 C 16.627438 16.159365 16.75 15.919928 16.75 15.65625 L 16.75 14.986328 L 14.371094 17.365234 C 14.362205 17.865302 14.367492 18.380007 14.408203 18.75 L 12.882812 18.75 L 9.8320312 19.417969 C 9.333649 19.527124 8.7483479 19.391267 8.3632812 19.005859 C 8.2870146 18.929486 8.2287106 18.840044 8.171875 18.75 L 4.375 18.75 C 3.7527244 18.75 3.25 18.24727 3.25 17.625 C 3.25 17.006253 3.7562267 16.5 4.375 16.5 L 8.1777344 16.5 L 8.6503906 14.349609 L 12.125 10.875 L 5.7109375 10.875 C 5.5948486 10.875 5.5 10.780031 5.5 10.664062 L 5.5 9.9609375 C 5.5 9.8448664 5.5949375 9.75 5.7109375 9.75 L 13.164062 9.75 C 13.187707 9.75 13.203276 9.7681373 13.224609 9.7753906 L 16.550781 6.4492188 L 16.75 6.25 L 16.75 3.84375 C 16.75 3.3761713 16.373823 3 15.90625 3 L 4.375 3 z M 20.390625 4.5898438 C 20.085165 4.6238231 19.766719 4.7743142 19.507812 5.0332031 L 18.324219 6.2167969 L 21.152344 9.0449219 L 22.335938 7.8613281 C 22.853786 7.3432392 22.937642 6.5860723 22.523438 6.171875 L 21.195312 4.8457031 C 20.988219 4.6386018 20.696085 4.5558644 20.390625 4.5898438 z M 17.320312 7.21875 L 9.6464844 14.894531 L 9.015625 17.767578 C 8.931145 18.15204 9.2151827 18.437711 9.5996094 18.353516 L 12.472656 17.724609 L 20.148438 10.046875 L 17.320312 7.21875 z M 5.7109375 7.5 L 13.164062 7.5 C 13.280151 7.5 13.375 7.5949873 13.375 7.7109375 L 13.375 8.4140625 C 13.375 8.5301336 13.28008 8.625 13.164062 8.625 L 5.7109375 8.625 C 5.5948486 8.625 5.5 8.5300127 5.5 8.4140625 L 5.5 7.7109375 C 5.5 7.5948664 5.5949375 7.5 5.7109375 7.5 z "
transform="matrix(0.56249999,0,0,0.56249999,115.58498,22.498806)"
id="path4" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,5 @@
* Read only mode
* Best group recovery for the navigation fragment
* Fix copies in notifications
* Fix orientation
* Added translations

View File

@@ -0,0 +1,5 @@
* Mode lecture seule
* Meilleur récupération des groupes pour le fragment de navigation
* Correction des copies dans les notifications
* Correction de l'orientation
* Ajout des traductions