mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Merge branch 'feature/ReadOnlyMode' into develop
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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";
|
||||
@@ -108,63 +111,66 @@ public class GroupActivity extends ListNodesActivity
|
||||
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,7 +260,7 @@ public class GroupActivity extends ListNodesActivity
|
||||
pwGroupId = getIntent().getParcelableExtra(GROUP_ID_KEY);
|
||||
}
|
||||
|
||||
readOnly = database.isReadOnly();
|
||||
readOnly = database.isReadOnly() || readOnly; // Force read only if the database is like that
|
||||
|
||||
Log.w(TAG, "Creating tree view");
|
||||
PwGroup currentGroup;
|
||||
@@ -266,7 +272,7 @@ public class GroupActivity extends ListNodesActivity
|
||||
|
||||
if (currentGroup != null) {
|
||||
addGroupEnabled = !readOnly;
|
||||
addEntryEnabled = !readOnly; // TODO consultation mode
|
||||
addEntryEnabled = !readOnly;
|
||||
isRoot = (currentGroup == rootGroup);
|
||||
if (!currentGroup.allowAddEntryIfIsRoot())
|
||||
addEntryEnabled = !isRoot && addEntryEnabled;
|
||||
@@ -494,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),
|
||||
@@ -631,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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.kunzisoft.keepass.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
public interface IntentBuildLauncher {
|
||||
void startActivityForResult(Intent intent);
|
||||
}
|
||||
@@ -42,9 +42,9 @@ 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
|
||||
@@ -52,8 +52,6 @@ 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;
|
||||
|
||||
@@ -108,7 +106,7 @@ public abstract class ListNodesActivity extends LockingActivity
|
||||
listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
|
||||
.findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
|
||||
if (listNodesFragment == null)
|
||||
listNodesFragment = ListNodesFragment.newInstance(currentGroup);
|
||||
listNodesFragment = ListNodesFragment.newInstance(currentGroup, readOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,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);
|
||||
}
|
||||
}
|
||||
@@ -199,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;
|
||||
}
|
||||
}
|
||||
@@ -211,7 +209,7 @@ public abstract class ListNodesActivity extends LockingActivity
|
||||
if (checkTimeIsAllowedOrFinish(this)) {
|
||||
startRecordTime(this);
|
||||
|
||||
ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group);
|
||||
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)
|
||||
|
||||
@@ -46,11 +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);
|
||||
}
|
||||
ReadOnlyHelper.putReadOnlyInBundle(bundle, readOnly);
|
||||
ListNodesFragment listNodesFragment = new ListNodesFragment();
|
||||
listNodesFragment.setArguments(bundle);
|
||||
return listNodesFragment;
|
||||
@@ -91,6 +94,8 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
if ( getActivity() != null ) {
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState, getArguments());
|
||||
|
||||
if (getArguments() != null) {
|
||||
// Contains all the group in element
|
||||
if (getArguments().containsKey(GROUP_KEY)) {
|
||||
@@ -98,7 +103,7 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
}
|
||||
}
|
||||
|
||||
mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater());
|
||||
mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater(), readOnly);
|
||||
mAdapter.setOnNodeClickListener(nodeClickCallback);
|
||||
|
||||
if (nodeMenuListener != null) {
|
||||
@@ -109,6 +114,12 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -72,7 +72,7 @@ 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
19
app/src/main/res/drawable/ic_read_only_white_24dp.xml
Normal file
19
app/src/main/res/drawable/ic_read_only_white_24dp.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:width="24dp"
|
||||
android:height="24dp">
|
||||
<group
|
||||
android:translateY="-8">
|
||||
<group
|
||||
android:scaleX="1.777778"
|
||||
android:scaleY="1.777778"
|
||||
android:translateX="-205.4844"
|
||||
android:translateY="-31.99788">
|
||||
<path
|
||||
android:pathData="M125.00684 31.305444l0 -6.644528c0 -0.263013 -0.21159 -0.47461 -0.4746 -0.47461l-6.48633 0c-1.04808 0 -1.89843 0.850344 -1.89843 1.898435l0 6.328127c0 1.048093 0.85035 1.898437 1.89843 1.898437l6.48633 0c0.26301 0 0.4746 -0.2116 0.4746 -0.474611l0 -0.316409c0 -0.148311 -0.0692 -0.282785 -0.176 -0.369792 -0.083 -0.304543 -0.083 -1.172685 0 -1.477229 0.10684 -0.08504 0.176 -0.219501 0.176 -0.36782zm-6.32812 -4.469236c0 -0.06529 0.0534 -0.118652 0.11866 -0.118652l4.19238 0c0.0653 0 0.11866 0.05343 0.11866 0.118652l0 0.39551c0 0.06529 -0.0534 0.118653 -0.11866 0.118653l-4.19238 0c-0.0653 0 -0.11866 -0.05343 -0.11866 -0.118653l0 -0.39551zm0 1.265621c0 -0.06529 0.0534 -0.118653 0.11866 -0.118653l4.19238 0c0.0653 0 0.11866 0.05343 0.11866 0.118653l0 0.395509c0 0.06529 -0.0534 0.118653 -0.11866 0.118653l-4.19238 0c-0.0653 0 -0.11866 -0.05342 -0.11866 -0.118653l0 -0.395509zm5.0111 4.943847l-5.64391 0c-0.35003 0 -0.63282 -0.282781 -0.63282 -0.632808 0 -0.348045 0.28476 -0.632813 0.63282 -0.632813l5.64391 0c-0.0375 0.338162 -0.0375 0.927466 0 1.265621z"
|
||||
android:fillColor="#ffffff" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
25
app/src/main/res/drawable/ic_read_write_white_24dp.xml
Normal file
25
app/src/main/res/drawable/ic_read_write_white_24dp.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:width="24dp"
|
||||
android:height="24dp">
|
||||
<group
|
||||
android:translateY="-8">
|
||||
<group
|
||||
android:scaleX="1.777778"
|
||||
android:scaleY="1.777778"
|
||||
android:translateX="-205.4844"
|
||||
android:translateY="-31.99788">
|
||||
<group
|
||||
android:scaleX="0.5625"
|
||||
android:scaleY="0.5625"
|
||||
android:translateX="115.585"
|
||||
android:translateY="22.49881">
|
||||
<path
|
||||
android:pathData="M4.375 3C2.5117466 3 1 4.5117271 1 6.375l0 11.25C1 19.488276 2.5117466 21 4.375 21l11.53125 0C16.373823 21 16.75 20.623825 16.75 20.15625l0 -0.5625c0 -0.263664 -0.122669 -0.503524 -0.3125 -0.658203 -0.147556 -0.54141 -0.147556 -2.08359 0 -2.625 0.189938 -0.151182 0.3125 -0.390619 0.3125 -0.654297l0 -0.669922 -2.378906 2.378906c-0.0089 0.500068 -0.0036 1.014773 0.03711 1.384766l-1.525391 0 -3.0507808 0.667969C9.333649 19.527124 8.7483479 19.391267 8.3632812 19.005859 8.2870146 18.929486 8.2287106 18.840044 8.171875 18.75L4.375 18.75C3.7527244 18.75 3.25 18.24727 3.25 17.625 3.25 17.006253 3.7562267 16.5 4.375 16.5l3.8027344 0L8.6503906 14.349609 12.125 10.875l-6.4140625 0C5.5948486 10.875 5.5 10.780031 5.5 10.664062l0 -0.7031245C5.5 9.8448664 5.5949375 9.75 5.7109375 9.75l7.4531245 0c0.02365 0 0.03921 0.018137 0.06055 0.025391L16.550781 6.4492188 16.75 6.25l0 -2.40625C16.75 3.3761713 16.373823 3 15.90625 3L4.375 3Zm16.015625 1.5898438c-0.30546 0.033979 -0.623906 0.1844704 -0.882813 0.4433593l-1.183593 1.1835938 2.828125 2.828125 1.183594 -1.1835938c0.517848 -0.5180889 0.601704 -1.2752558 0.1875 -1.6894531L21.195312 4.8457031C20.988219 4.6386018 20.696085 4.5558644 20.390625 4.5898438ZM17.320312 7.21875L9.6464844 14.894531 9.015625 17.767578c-0.08448 0.384462 0.1995577 0.670133 0.5839844 0.585938L12.472656 17.724609 20.148438 10.046875 17.320312 7.21875ZM5.7109375 7.5L13.164062 7.5C13.280151 7.5 13.375 7.594987 13.375 7.7109375l0 0.703125C13.375 8.5301336 13.28008 8.625 13.164062 8.625l-7.4531245 0C5.5948486 8.625 5.5 8.5300127 5.5 8.4140625l0 -0.703125C5.5 7.5948664 5.5949375 7.5 5.7109375 7.5Z"
|
||||
android:fillColor="#ffffff" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
27
app/src/main/res/menu/open_file.xml
Normal file
27
app/src/main/res/menu/open_file.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
|
||||
This file is part of KeePass DX.
|
||||
|
||||
KeePass DX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
KeePass DX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/menu_open_file_read_mode_key"
|
||||
android:icon="@drawable/ic_read_write_white_24dp"
|
||||
android:title="@string/menu_open_file_read_and_write"
|
||||
android:orderInCategory="85"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
||||
@@ -88,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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
92
art/ic_read_only.svg
Normal 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
92
art/ic_read_write.svg
Normal 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 |
Reference in New Issue
Block a user