mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Add modification
This commit is contained in:
@@ -60,7 +60,7 @@ public class DeleteEntry extends AndroidTestCase {
|
|||||||
assertNotNull("Could not find group1", group1);
|
assertNotNull("Could not find group1", group1);
|
||||||
|
|
||||||
// Delete the group
|
// Delete the group
|
||||||
DeleteGroup task = new DeleteGroup(db, group1, null, true);
|
DeleteGroup task = new DeleteGroup(null, db, group1, null, true);
|
||||||
task.run();
|
task.run();
|
||||||
|
|
||||||
// Verify the entries were deleted
|
// Verify the entries were deleted
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ public class EntryEditActivity extends LockingHideActivity
|
|||||||
if ( uuidBytes == null ) {
|
if ( uuidBytes == null ) {
|
||||||
PwGroupId parentId = (PwGroupId) intent.getSerializableExtra(KEY_PARENT);
|
PwGroupId parentId = (PwGroupId) intent.getSerializableExtra(KEY_PARENT);
|
||||||
PwGroup parent = pm.getGroupByGroupId(parentId);
|
PwGroup parent = pm.getGroupByGroupId(parentId);
|
||||||
mEntry = PwEntry.getInstance(parent);
|
mEntry = db.createEntry(parent);
|
||||||
mIsNew = true;
|
mIsNew = true;
|
||||||
// Add the default icon
|
// Add the default icon
|
||||||
if (IconPackChooser.getSelectedIconPack(this).tintable()) {
|
if (IconPackChooser.getSelectedIconPack(this).tintable()) {
|
||||||
|
|||||||
@@ -53,11 +53,13 @@ import com.kunzisoft.keepass.database.Database;
|
|||||||
import com.kunzisoft.keepass.database.PwEntry;
|
import com.kunzisoft.keepass.database.PwEntry;
|
||||||
import com.kunzisoft.keepass.database.PwGroup;
|
import com.kunzisoft.keepass.database.PwGroup;
|
||||||
import com.kunzisoft.keepass.database.PwGroupId;
|
import com.kunzisoft.keepass.database.PwGroupId;
|
||||||
|
import com.kunzisoft.keepass.database.PwIconStandard;
|
||||||
import com.kunzisoft.keepass.database.PwNode;
|
import com.kunzisoft.keepass.database.PwNode;
|
||||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||||
import com.kunzisoft.keepass.database.edit.AddGroup;
|
import com.kunzisoft.keepass.database.edit.AddGroup;
|
||||||
import com.kunzisoft.keepass.database.edit.DeleteEntry;
|
import com.kunzisoft.keepass.database.edit.DeleteEntry;
|
||||||
import com.kunzisoft.keepass.database.edit.DeleteGroup;
|
import com.kunzisoft.keepass.database.edit.DeleteGroup;
|
||||||
|
import com.kunzisoft.keepass.database.edit.UpdateGroup;
|
||||||
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
|
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
|
||||||
import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment;
|
import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment;
|
||||||
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
|
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
|
||||||
@@ -82,13 +84,10 @@ public class GroupActivity extends ListNodesActivity
|
|||||||
protected boolean addEntryEnabled = false;
|
protected boolean addEntryEnabled = false;
|
||||||
protected boolean isRoot = false;
|
protected boolean isRoot = false;
|
||||||
protected boolean readOnly = false;
|
protected boolean readOnly = false;
|
||||||
protected EditGroupDialogAction editGroupDialogAction = EditGroupDialogAction.NONE;
|
|
||||||
|
|
||||||
private enum EditGroupDialogAction {
|
|
||||||
CREATION, UPDATE, NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String TAG = "Group Activity:";
|
private static final String TAG = "Group Activity:";
|
||||||
|
|
||||||
|
private PwGroup oldGroupToUpdate;
|
||||||
|
|
||||||
public static void launch(Activity act) {
|
public static void launch(Activity act) {
|
||||||
recordFirstTimeBeforeLaunch(act);
|
recordFirstTimeBeforeLaunch(act);
|
||||||
@@ -160,10 +159,9 @@ public class GroupActivity extends ListNodesActivity
|
|||||||
toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp);
|
toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp);
|
||||||
|
|
||||||
addNodeButtonView.setAddGroupClickListener(v -> {
|
addNodeButtonView.setAddGroupClickListener(v -> {
|
||||||
editGroupDialogAction = EditGroupDialogAction.CREATION;
|
GroupEditDialogFragment.build()
|
||||||
GroupEditDialogFragment groupEditDialogFragment = new GroupEditDialogFragment();
|
.show(getSupportFragmentManager(),
|
||||||
groupEditDialogFragment.show(getSupportFragmentManager(),
|
GroupEditDialogFragment.TAG_CREATE_GROUP);
|
||||||
GroupEditDialogFragment.TAG_CREATE_GROUP);
|
|
||||||
});
|
});
|
||||||
addNodeButtonView.setAddEntryClickListener(v ->
|
addNodeButtonView.setAddEntryClickListener(v ->
|
||||||
EntryEditActivity.launch(GroupActivity.this, mCurrentGroup));
|
EntryEditActivity.launch(GroupActivity.this, mCurrentGroup));
|
||||||
@@ -215,7 +213,6 @@ public class GroupActivity extends ListNodesActivity
|
|||||||
nodeAdapter.setNodeMenuListener(new NodeAdapter.NodeMenuListener() {
|
nodeAdapter.setNodeMenuListener(new NodeAdapter.NodeMenuListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onOpenMenuClick(PwNode node) {
|
public boolean onOpenMenuClick(PwNode node) {
|
||||||
mAdapter.registerANodeToUpdate(node);
|
|
||||||
switch (node.getType()) {
|
switch (node.getType()) {
|
||||||
case GROUP:
|
case GROUP:
|
||||||
GroupActivity.launch(GroupActivity.this, (PwGroup) node);
|
GroupActivity.launch(GroupActivity.this, (PwGroup) node);
|
||||||
@@ -229,14 +226,12 @@ public class GroupActivity extends ListNodesActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onEditMenuClick(PwNode node) {
|
public boolean onEditMenuClick(PwNode node) {
|
||||||
mAdapter.registerANodeToUpdate(node);
|
|
||||||
switch (node.getType()) {
|
switch (node.getType()) {
|
||||||
case GROUP:
|
case GROUP:
|
||||||
editGroupDialogAction = EditGroupDialogAction.UPDATE;
|
oldGroupToUpdate = (PwGroup) node;
|
||||||
GroupEditDialogFragment groupEditDialogFragment =
|
GroupEditDialogFragment.build(node)
|
||||||
GroupEditDialogFragment.build(node);
|
.show(getSupportFragmentManager(),
|
||||||
groupEditDialogFragment.show(getSupportFragmentManager(),
|
GroupEditDialogFragment.TAG_CREATE_GROUP);
|
||||||
GroupEditDialogFragment.TAG_CREATE_GROUP);
|
|
||||||
break;
|
break;
|
||||||
case ENTRY:
|
case ENTRY:
|
||||||
EntryEditActivity.launch(GroupActivity.this, (PwEntry) node);
|
EntryEditActivity.launch(GroupActivity.this, (PwEntry) node);
|
||||||
@@ -528,28 +523,53 @@ public class GroupActivity extends ListNodesActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void approveEditGroup(Bundle bundle) {
|
public void approveEditGroup(GroupEditDialogFragment.EditGroupDialogAction action,
|
||||||
String GroupName = bundle.getString(GroupEditDialogFragment.KEY_NAME);
|
String name,
|
||||||
int GroupIconID = bundle.getInt(GroupEditDialogFragment.KEY_ICON_ID);
|
int iconId) {
|
||||||
switch (editGroupDialogAction) {
|
Database database = App.getDB(); // TODO encapsulate iconFactory
|
||||||
|
PwIconStandard icon = database.getPwDatabase().getIconFactory().getIcon(iconId);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
case CREATION:
|
case CREATION:
|
||||||
// If edit group creation
|
// If group creation
|
||||||
Handler handler = new Handler();
|
// Build the group
|
||||||
AddGroup task = new AddGroup(this, App.getDB(), GroupName, GroupIconID, mCurrentGroup,
|
PwGroup newGroup = database.createGroup(mCurrentGroup);
|
||||||
new AfterAddNode(handler), false);
|
newGroup.setName(name);
|
||||||
ProgressTask pt = new ProgressTask(this, task, R.string.saving_database);
|
newGroup.setIcon(icon);
|
||||||
pt.run();
|
|
||||||
|
new ProgressTask(this,
|
||||||
|
new AddGroup(this,
|
||||||
|
App.getDB(),
|
||||||
|
newGroup,
|
||||||
|
new AfterAddNode(new Handler())),
|
||||||
|
R.string.saving_database)
|
||||||
|
.run();
|
||||||
break;
|
break;
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
// If edit group update
|
// If update add new elements
|
||||||
// TODO UpdateGroup
|
PwGroup updateGroup = oldGroupToUpdate.clone();
|
||||||
|
updateGroup.setName(name);
|
||||||
|
updateGroup.setIcon(icon);
|
||||||
|
|
||||||
|
mAdapter.removeNode(oldGroupToUpdate);
|
||||||
|
// If group update
|
||||||
|
new ProgressTask(this,
|
||||||
|
new UpdateGroup(this,
|
||||||
|
App.getDB(),
|
||||||
|
oldGroupToUpdate,
|
||||||
|
updateGroup,
|
||||||
|
new AfterUpdateNode(new Handler())),
|
||||||
|
R.string.saving_database)
|
||||||
|
.run();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
editGroupDialogAction = EditGroupDialogAction.NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancelEditGroup(Bundle bundle) {
|
public void cancelEditGroup(GroupEditDialogFragment.EditGroupDialogAction action,
|
||||||
|
String name,
|
||||||
|
int iconId) {
|
||||||
// Do nothing here
|
// Do nothing here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import com.kunzisoft.keepass.database.PwEntry;
|
|||||||
import com.kunzisoft.keepass.database.PwGroup;
|
import com.kunzisoft.keepass.database.PwGroup;
|
||||||
import com.kunzisoft.keepass.database.PwNode;
|
import com.kunzisoft.keepass.database.PwNode;
|
||||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||||
import com.kunzisoft.keepass.database.edit.AfterAddNodeOnFinish;
|
import com.kunzisoft.keepass.database.edit.AfterActionNodeOnFinish;
|
||||||
import com.kunzisoft.keepass.database.edit.OnFinish;
|
import com.kunzisoft.keepass.database.edit.OnFinish;
|
||||||
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
|
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
|
||||||
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
|
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
|
||||||
@@ -143,8 +143,6 @@ public abstract class ListNodesActivity extends LockingActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onNodeClick(PwNode node) {
|
public void onNodeClick(PwNode node) {
|
||||||
|
|
||||||
mAdapter.registerANodeToUpdate(node);
|
|
||||||
|
|
||||||
// Add event when we have Autofill
|
// Add event when we have Autofill
|
||||||
AssistStructure assistStructure = null;
|
AssistStructure assistStructure = null;
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
@@ -302,15 +300,30 @@ public abstract class ListNodesActivity extends LockingActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AfterAddNode extends AfterAddNodeOnFinish {
|
class AfterAddNode extends AfterActionNodeOnFinish {
|
||||||
AfterAddNode(Handler handler) {
|
AfterAddNode(Handler handler) {
|
||||||
super(handler);
|
super(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(PwNode pwNode) {
|
public void run(PwNode oldNode, PwNode newNode) {
|
||||||
super.run();
|
super.run();
|
||||||
if (mSuccess) {
|
if (mSuccess) {
|
||||||
mAdapter.addNode(pwNode);
|
mAdapter.addNode(newNode);
|
||||||
|
} else {
|
||||||
|
displayMessage(ListNodesActivity.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AfterUpdateNode extends AfterActionNodeOnFinish {
|
||||||
|
AfterUpdateNode(Handler handler) {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(PwNode oldNode, PwNode newNode) {
|
||||||
|
super.run();
|
||||||
|
if (mSuccess) {
|
||||||
|
mAdapter.updateNode(oldNode, newNode);
|
||||||
} else {
|
} else {
|
||||||
displayMessage(ListNodesActivity.this);
|
displayMessage(ListNodesActivity.this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.v7.util.SortedList;
|
import android.support.v7.util.SortedList;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.util.SortedListAdapterCallback;
|
import android.support.v7.widget.util.SortedListAdapterCallback;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -54,7 +53,6 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
|||||||
private boolean ascendingSort;
|
private boolean ascendingSort;
|
||||||
|
|
||||||
private OnNodeClickCallback onNodeClickCallback;
|
private OnNodeClickCallback onNodeClickCallback;
|
||||||
private int nodePositionToUpdate;
|
|
||||||
private NodeMenuListener nodeMenuListener;
|
private NodeMenuListener nodeMenuListener;
|
||||||
private boolean activateContextMenu;
|
private boolean activateContextMenu;
|
||||||
|
|
||||||
@@ -73,7 +71,6 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
|||||||
this.groupsBeforeSort = PreferencesUtil.getGroupsBeforeSort(context);
|
this.groupsBeforeSort = PreferencesUtil.getGroupsBeforeSort(context);
|
||||||
this.ascendingSort = PreferencesUtil.getAscendingSort(context);
|
this.ascendingSort = PreferencesUtil.getAscendingSort(context);
|
||||||
this.activateContextMenu = false;
|
this.activateContextMenu = false;
|
||||||
this.nodePositionToUpdate = -1;
|
|
||||||
|
|
||||||
this.nodeSortedList = new SortedList<>(PwNode.class, new SortedListAdapterCallback<PwNode>(this) {
|
this.nodeSortedList = new SortedList<>(PwNode.class, new SortedListAdapterCallback<PwNode>(this) {
|
||||||
@Override public int compare(PwNode item1, PwNode item2) {
|
@Override public int compare(PwNode item1, PwNode item2) {
|
||||||
@@ -119,43 +116,25 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a node to update before an action
|
* Remove a node in the list
|
||||||
* Call updateLastNodeRegister() after the action to update the node
|
|
||||||
* @param node Node to register
|
|
||||||
*/
|
|
||||||
public void registerANodeToUpdate(PwNode node) {
|
|
||||||
nodePositionToUpdate = nodeSortedList.indexOf(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the last Node register in the list
|
|
||||||
* Work if only registerANodeToUpdate(PwNode node) is called before
|
|
||||||
*/
|
|
||||||
public void updateLastNodeRegister(PwNode node) {
|
|
||||||
// Don't really update here, sorted list knows each original ref, so we just notify a change
|
|
||||||
try {
|
|
||||||
if (nodePositionToUpdate != -1) {
|
|
||||||
// Don't know why but there is a bug to remove a node after this update
|
|
||||||
nodeSortedList.updateItemAt(nodePositionToUpdate, node);
|
|
||||||
nodeSortedList.recalculatePositionOfItemAt(nodePositionToUpdate);
|
|
||||||
nodePositionToUpdate = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log.e(NodeAdapter.class.getName(), "registerANodeToUpdate must be called before updateLastNodeRegister");
|
|
||||||
}
|
|
||||||
} catch (IndexOutOfBoundsException e) {
|
|
||||||
Log.e(NodeAdapter.class.getName(), e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove node in the list
|
|
||||||
* @param node Node to delete
|
* @param node Node to delete
|
||||||
*/
|
*/
|
||||||
public void removeNode(PwNode node) {
|
public void removeNode(PwNode node) {
|
||||||
nodeSortedList.remove(node);
|
nodeSortedList.remove(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a node in the list
|
||||||
|
* @param oldNode Node before the update
|
||||||
|
* @param newNode Node after the update
|
||||||
|
*/
|
||||||
|
public void updateNode(PwNode oldNode, PwNode newNode) {
|
||||||
|
nodeSortedList.beginBatchedUpdates();
|
||||||
|
nodeSortedList.remove(oldNode);
|
||||||
|
nodeSortedList.add(newNode);
|
||||||
|
nodeSortedList.endBatchedUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify a change sort of the list
|
* Notify a change sort of the list
|
||||||
*/
|
*/
|
||||||
@@ -170,6 +149,7 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
|||||||
return nodeSortedList.get(position).getType().ordinal();
|
return nodeSortedList.get(position).getType().ordinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public BasicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public BasicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
BasicViewHolder basicViewHolder;
|
BasicViewHolder basicViewHolder;
|
||||||
@@ -290,9 +270,10 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
|||||||
MenuItem clearMenu = contextMenu.add(Menu.NONE, MENU_OPEN, Menu.NONE, R.string.menu_open);
|
MenuItem clearMenu = contextMenu.add(Menu.NONE, MENU_OPEN, Menu.NONE, R.string.menu_open);
|
||||||
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
|
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||||
if (!App.getDB().isReadOnly() && !node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
|
if (!App.getDB().isReadOnly() && !node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
|
||||||
// TODO make edit for group
|
// Edition
|
||||||
// clearMenu = contextMenu.add(Menu.NONE, MENU_EDIT, Menu.NONE, R.string.menu_edit);
|
clearMenu = contextMenu.add(Menu.NONE, MENU_EDIT, Menu.NONE, R.string.menu_edit);
|
||||||
// clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
|
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||||
|
// Deletion
|
||||||
clearMenu = contextMenu.add(Menu.NONE, MENU_DELETE, Menu.NONE, R.string.menu_delete);
|
clearMenu = contextMenu.add(Menu.NONE, MENU_DELETE, Menu.NONE, R.string.menu_delete);
|
||||||
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
|
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -368,6 +368,37 @@ public class Database {
|
|||||||
getPwDatabase().setNumberKeyEncryptionRounds(numberRounds);
|
getPwDatabase().setNumberKeyEncryptionRounds(numberRounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PwEntry createEntry(PwGroup parent) {
|
||||||
|
PwEntry newPwEntry = null;
|
||||||
|
try {
|
||||||
|
switch (getPwDatabase().getVersion()) {
|
||||||
|
case V3:
|
||||||
|
newPwEntry = new PwEntryV3((PwGroupV3) parent);
|
||||||
|
case V4:
|
||||||
|
newPwEntry = new PwEntryV4((PwGroupV4) parent);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "This version of PwEntry can't be created", e);
|
||||||
|
}
|
||||||
|
return newPwEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PwGroup createGroup(PwGroup parent) {
|
||||||
|
PwGroup newPwGroup = null;
|
||||||
|
try {
|
||||||
|
switch (getPwDatabase().getVersion()) {
|
||||||
|
case V3:
|
||||||
|
newPwGroup = new PwGroupV3((PwGroupV3) parent);
|
||||||
|
case V4:
|
||||||
|
newPwGroup = new PwGroupV4((PwGroupV4) parent);
|
||||||
|
}
|
||||||
|
newPwGroup.setId(pm.newGroupId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "This version of PwGroup can't be created", e);
|
||||||
|
}
|
||||||
|
return newPwGroup;
|
||||||
|
}
|
||||||
|
|
||||||
public void addEntryTo(PwEntry entry, PwGroup parent) {
|
public void addEntryTo(PwEntry entry, PwGroup parent) {
|
||||||
try {
|
try {
|
||||||
switch (getPwDatabase().getVersion()) {
|
switch (getPwDatabase().getVersion()) {
|
||||||
@@ -501,6 +532,21 @@ public class Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateGroup(PwGroup oldGroup, PwGroup newGroup) {
|
||||||
|
try {
|
||||||
|
switch (getPwDatabase().getVersion()) {
|
||||||
|
case V3:
|
||||||
|
((PwGroupV3) oldGroup).updateWith((PwGroupV3) newGroup);
|
||||||
|
break;
|
||||||
|
case V4:
|
||||||
|
((PwGroupV4) oldGroup).updateWith((PwGroupV4) newGroup);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "This version of PwEntry can't be updated", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void deleteEntry(PwEntry entry) {
|
public void deleteEntry(PwEntry entry) {
|
||||||
try {
|
try {
|
||||||
switch (getPwDatabase().getVersion()) {
|
switch (getPwDatabase().getVersion()) {
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
|
|
||||||
package com.kunzisoft.keepass.database;
|
package com.kunzisoft.keepass.database;
|
||||||
|
|
||||||
// Java
|
|
||||||
import com.kunzisoft.keepass.crypto.keyDerivation.AesKdf;
|
import com.kunzisoft.keepass.crypto.keyDerivation.AesKdf;
|
||||||
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException;
|
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException;
|
||||||
|
|
||||||
@@ -71,13 +70,6 @@ public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
|
|||||||
|
|
||||||
private int numKeyEncRounds;
|
private int numKeyEncRounds;
|
||||||
|
|
||||||
private void initAndAddGroup(String name, int iconId, PwGroupV3 parent) {
|
|
||||||
PwGroupV3 group = createGroup();
|
|
||||||
group.initNewGroup(name, newGroupId());
|
|
||||||
group.setIcon(iconFactory.getIcon(iconId));
|
|
||||||
addGroupTo(group, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initNew(String dbPath) {
|
public void initNew(String dbPath) {
|
||||||
algorithm = PwEncryptionAlgorithm.AES_Rijndael;
|
algorithm = PwEncryptionAlgorithm.AES_Rijndael;
|
||||||
@@ -90,6 +82,14 @@ public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
|
|||||||
initAndAddGroup("eMail", 19, rootGroup);
|
initAndAddGroup("eMail", 19, rootGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initAndAddGroup(String name, int iconId, PwGroupV3 parent) {
|
||||||
|
PwGroupV3 group = createGroup();
|
||||||
|
group.setId(newGroupId());
|
||||||
|
group.setName(name);
|
||||||
|
group.setIcon(iconFactory.getIcon(iconId));
|
||||||
|
addGroupTo(group, parent);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PwVersion getVersion() {
|
public PwVersion getVersion() {
|
||||||
return PwVersion.V3;
|
return PwVersion.V3;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import com.kunzisoft.keepass.database.security.ProtectedString;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> implements Cloneable {
|
public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> {
|
||||||
|
|
||||||
private static final String PMS_TAN_ENTRY = "<TAN>";
|
private static final String PMS_TAN_ENTRY = "<TAN>";
|
||||||
|
|
||||||
@@ -36,35 +36,12 @@ public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> imp
|
|||||||
uuid = UUID.randomUUID();
|
uuid = UUID.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PwEntry getInstance(PwGroup parent) {
|
|
||||||
if (parent instanceof PwGroupV3) {
|
|
||||||
return new PwEntryV3((PwGroupV3)parent);
|
|
||||||
}
|
|
||||||
else if (parent instanceof PwGroupV4) {
|
|
||||||
return new PwEntryV4((PwGroupV4)parent);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new RuntimeException("Unknown PwGroup instance.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PwEntry clone() {
|
public PwEntry clone() {
|
||||||
PwEntry newEntry;
|
// uuid is clone automatically (IMMUTABLE)
|
||||||
try {
|
return (PwEntry) super.clone();
|
||||||
newEntry = (PwEntry) super.clone();
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
throw new RuntimeException("Clone should be supported");
|
|
||||||
}
|
|
||||||
return newEntry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void addCloneAttributesToNewEntry(PwEntry newEntry) {
|
|
||||||
super.addCloneAttributesToNewEntry(newEntry);
|
|
||||||
// uuid is clone automatically (IMMUTABLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return Type.ENTRY;
|
return Type.ENTRY;
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateWith(PwEntryV3 source) {
|
protected void updateWith(PwEntryV3 source) {
|
||||||
|
super.assign(source);
|
||||||
groupId = source.groupId;
|
groupId = source.groupId;
|
||||||
|
|
||||||
title = source.title;
|
title = source.title;
|
||||||
@@ -118,10 +119,8 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PwEntryV3 clone() {
|
public PwEntryV3 clone() {
|
||||||
PwEntryV3 newEntry = (PwEntryV3) super.clone();
|
|
||||||
|
|
||||||
// Attributes in parent
|
// Attributes in parent
|
||||||
addCloneAttributesToNewEntry(newEntry);
|
PwEntryV3 newEntry = (PwEntryV3) super.clone();
|
||||||
|
|
||||||
// Attributes here
|
// Attributes here
|
||||||
// newEntry.parent stay the same in copy
|
// newEntry.parent stay the same in copy
|
||||||
|
|||||||
@@ -89,11 +89,9 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public PwEntryV4 clone() {
|
public PwEntryV4 clone() {
|
||||||
|
// Attributes in parent
|
||||||
PwEntryV4 newEntry = (PwEntryV4) super.clone();
|
PwEntryV4 newEntry = (PwEntryV4) super.clone();
|
||||||
|
|
||||||
// Attributes in parent
|
|
||||||
addCloneAttributesToNewEntry(newEntry);
|
|
||||||
|
|
||||||
// Attributes here
|
// Attributes here
|
||||||
newEntry.customIcon = new PwIconCustom(this.customIcon);
|
newEntry.customIcon = new PwIconCustom(this.customIcon);
|
||||||
// newEntry.usageCount stay the same in copy
|
// newEntry.usageCount stay the same in copy
|
||||||
|
|||||||
@@ -30,9 +30,15 @@ public abstract class PwGroup<Parent extends PwGroup, ChildGroup extends PwGroup
|
|||||||
protected List<ChildGroup> childGroups = new ArrayList<>();
|
protected List<ChildGroup> childGroups = new ArrayList<>();
|
||||||
protected List<ChildEntry> childEntries = new ArrayList<>();
|
protected List<ChildEntry> childEntries = new ArrayList<>();
|
||||||
|
|
||||||
public void initNewGroup(String nm, PwGroupId newId) {
|
@Override
|
||||||
setId(newId);
|
public PwGroup clone() {
|
||||||
name = nm;
|
// name is clone automatically (IMMUTABLE)
|
||||||
|
return (PwGroup) super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assign(PwGroup<Parent, ChildGroup, ChildEntry> source) {
|
||||||
|
super.assign(source);
|
||||||
|
name = source.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ChildGroup> getChildGroups() {
|
public List<ChildGroup> getChildGroups() {
|
||||||
|
|||||||
@@ -40,6 +40,26 @@ public class PwGroupV3 extends PwGroup<PwGroupV3, PwGroupV3, PwEntryV3> {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PwGroupV3(PwGroupV3 p) {
|
||||||
|
construct(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateWith(PwGroupV3 source) {
|
||||||
|
super.assign(source);
|
||||||
|
groupId = source.groupId;
|
||||||
|
level = source.level;
|
||||||
|
flags = source.flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public PwGroupV3 clone() {
|
||||||
|
// newGroup.groupId stay the same in copy
|
||||||
|
// newGroup.level stay the same in copy
|
||||||
|
// newGroup.flags stay the same in copy
|
||||||
|
return (PwGroupV3) super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setParent(PwGroupV3 parent) {
|
public void setParent(PwGroupV3 parent) {
|
||||||
super.setParent(parent);
|
super.setParent(parent);
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
|
|||||||
public PwGroupV4() {
|
public PwGroupV4() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PwGroupV4(PwGroupV4 p) {
|
||||||
|
construct(p);
|
||||||
|
parentGroupLastMod = new PwDate();
|
||||||
|
}
|
||||||
|
|
||||||
public PwGroupV4(String name, PwIconStandard icon) {
|
public PwGroupV4(String name, PwIconStandard icon) {
|
||||||
this.uuid = UUID.randomUUID();
|
this.uuid = UUID.randomUUID();
|
||||||
@@ -52,10 +57,47 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
|
|||||||
this.icon = icon;
|
this.icon = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void updateWith(PwGroupV4 source) {
|
||||||
|
super.assign(source);
|
||||||
|
uuid = source.uuid;
|
||||||
|
customIcon = source.customIcon;
|
||||||
|
usageCount = source.usageCount;
|
||||||
|
parentGroupLastMod = source.parentGroupLastMod;
|
||||||
|
customData = source.customData;
|
||||||
|
|
||||||
|
expires = source.expires;
|
||||||
|
|
||||||
|
notes = source.notes;
|
||||||
|
isExpanded = source.isExpanded;
|
||||||
|
defaultAutoTypeSequence = source.defaultAutoTypeSequence;
|
||||||
|
enableAutoType = source.enableAutoType;
|
||||||
|
enableSearching = source.enableSearching;
|
||||||
|
lastTopVisibleEntry = source.lastTopVisibleEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void initNewGroup(String nm, PwGroupId newId) {
|
public PwGroupV4 clone() {
|
||||||
super.initNewGroup(nm, newId);
|
// Attributes in parent
|
||||||
parentGroupLastMod = new PwDate();
|
PwGroupV4 newGroup = (PwGroupV4) super.clone();
|
||||||
|
|
||||||
|
// Attributes here
|
||||||
|
// newGroup.uuid stay the same in copy
|
||||||
|
newGroup.customIcon = new PwIconCustom(this.customIcon);
|
||||||
|
// newGroup.usageCount stay the same in copy
|
||||||
|
newGroup.parentGroupLastMod = this.parentGroupLastMod.clone();
|
||||||
|
// TODO customData make copy from hashmap newGroup.customData = (HashMap<String, String>) this.customData.clone();
|
||||||
|
|
||||||
|
// newGroup.expires stay the same in copy
|
||||||
|
|
||||||
|
// newGroup.notes stay the same in copy
|
||||||
|
// newGroup.isExpanded stay the same in copy
|
||||||
|
// newGroup.defaultAutoTypeSequence stay the same in copy
|
||||||
|
// newGroup.enableAutoType stay the same in copy
|
||||||
|
// newGroup.enableSearching stay the same in copy
|
||||||
|
// newGroup.lastTopVisibleEntry stay the same in copy
|
||||||
|
|
||||||
|
return newGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addGroup(PwGroupV4 subGroup) {
|
public void addGroup(PwGroupV4 subGroup) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import java.io.Serializable;
|
|||||||
/**
|
/**
|
||||||
* Abstract class who manage Groups and Entries
|
* Abstract class who manage Groups and Entries
|
||||||
*/
|
*/
|
||||||
public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger, Serializable {
|
public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger, Serializable, Cloneable {
|
||||||
|
|
||||||
protected Parent parent = null;
|
protected Parent parent = null;
|
||||||
|
|
||||||
@@ -53,15 +53,23 @@ public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger
|
|||||||
this.expireDate = source.expireDate;
|
this.expireDate = source.expireDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addCloneAttributesToNewEntry(PwEntry newEntry) {
|
@Override
|
||||||
// newEntry.parent stay the same in copy
|
public PwNode clone() {
|
||||||
|
PwNode newNode;
|
||||||
|
try {
|
||||||
|
newNode = (PwNode) super.clone();
|
||||||
|
// newNode.parent stay the same in copy
|
||||||
|
|
||||||
newEntry.icon = new PwIconStandard(this.icon);
|
newNode.icon = new PwIconStandard(this.icon);
|
||||||
|
|
||||||
newEntry.creation = creation.clone();
|
newNode.creation = creation.clone();
|
||||||
newEntry.lastMod = lastMod.clone();
|
newNode.lastMod = lastMod.clone();
|
||||||
newEntry.lastAccess = lastAccess.clone();
|
newNode.lastAccess = lastAccess.clone();
|
||||||
newEntry.expireDate = expireDate.clone();
|
newNode.expireDate = expireDate.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new RuntimeException("Clone should be supported");
|
||||||
|
}
|
||||||
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,13 +29,19 @@ public class AddEntry extends RunnableOnFinish {
|
|||||||
protected Database mDb;
|
protected Database mDb;
|
||||||
private PwEntry mEntry;
|
private PwEntry mEntry;
|
||||||
private Context ctx;
|
private Context ctx;
|
||||||
|
private boolean mDontSave;
|
||||||
|
|
||||||
public AddEntry(Context ctx, Database db, PwEntry entry, OnFinish finish) {
|
public AddEntry(Context ctx, Database db, PwEntry entry, OnFinish finish) {
|
||||||
|
this(ctx, db, entry, finish, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddEntry(Context ctx, Database db, PwEntry entry, OnFinish finish, boolean dontSave) {
|
||||||
super(finish);
|
super(finish);
|
||||||
|
|
||||||
this.mDb = db;
|
this.mDb = db;
|
||||||
this.mEntry = entry;
|
this.mEntry = entry;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
|
this.mDontSave = dontSave;
|
||||||
|
|
||||||
this.mFinish = new AfterAdd(mFinish);
|
this.mFinish = new AfterAdd(mFinish);
|
||||||
}
|
}
|
||||||
@@ -45,7 +51,7 @@ public class AddEntry extends RunnableOnFinish {
|
|||||||
mDb.addEntryTo(mEntry, mEntry.getParent());
|
mDb.addEntryTo(mEntry, mEntry.getParent());
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDB save = new SaveDB(ctx, mDb, mFinish);
|
SaveDB save = new SaveDB(ctx, mDb, mFinish, mDontSave);
|
||||||
save.run();
|
save.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,28 +22,25 @@ package com.kunzisoft.keepass.database.edit;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.Database;
|
import com.kunzisoft.keepass.database.Database;
|
||||||
import com.kunzisoft.keepass.database.PwDatabase;
|
|
||||||
import com.kunzisoft.keepass.database.PwGroup;
|
import com.kunzisoft.keepass.database.PwGroup;
|
||||||
|
|
||||||
public class AddGroup extends RunnableOnFinish {
|
public class AddGroup extends RunnableOnFinish {
|
||||||
|
|
||||||
protected Database mDb;
|
protected Database mDb;
|
||||||
private String mName;
|
private PwGroup mNewGroup;
|
||||||
private int mIconID;
|
|
||||||
private PwGroup mGroup;
|
|
||||||
private PwGroup mParent;
|
|
||||||
private Context ctx;
|
private Context ctx;
|
||||||
private boolean mDontSave;
|
private boolean mDontSave;
|
||||||
|
|
||||||
public AddGroup(Context ctx, Database db, String name, int iconid,
|
public AddGroup(Context ctx, Database db, PwGroup newGroup, AfterActionNodeOnFinish afterAddNode) {
|
||||||
PwGroup parent, AfterAddNodeOnFinish afterAddNode,
|
this(ctx, db, newGroup, afterAddNode, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddGroup(Context ctx, Database db, PwGroup newGroup, AfterActionNodeOnFinish afterAddNode,
|
||||||
boolean dontSave) {
|
boolean dontSave) {
|
||||||
super(afterAddNode);
|
super(afterAddNode);
|
||||||
|
|
||||||
this.mDb = db;
|
this.mDb = db;
|
||||||
this.mName = name;
|
this.mNewGroup = newGroup;
|
||||||
this.mIconID = iconid;
|
|
||||||
this.mParent = parent;
|
|
||||||
this.mDontSave = dontSave;
|
this.mDontSave = dontSave;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
|
|
||||||
@@ -52,13 +49,7 @@ public class AddGroup extends RunnableOnFinish {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
PwDatabase pm = mDb.getPwDatabase();
|
mDb.addGroupTo(mNewGroup, mNewGroup.getParent());
|
||||||
|
|
||||||
// Generate new group
|
|
||||||
mGroup = pm.createGroup();
|
|
||||||
mGroup.initNewGroup(mName, pm.newGroupId());
|
|
||||||
mGroup.setIcon(pm.getIconFactory().getIcon(mIconID));
|
|
||||||
mDb.addGroupTo(mGroup, mParent);
|
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDB save = new SaveDB(ctx, mDb, mFinish, mDontSave);
|
SaveDB save = new SaveDB(ctx, mDb, mFinish, mDontSave);
|
||||||
@@ -74,15 +65,15 @@ public class AddGroup extends RunnableOnFinish {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if ( !mSuccess ) {
|
if ( !mSuccess ) {
|
||||||
mDb.removeGroupFrom(mGroup, mParent);
|
mDb.removeGroupFrom(mNewGroup, mNewGroup.getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Better callback
|
// TODO Better callback
|
||||||
AfterAddNodeOnFinish afterAddNode =
|
AfterActionNodeOnFinish afterAddNode =
|
||||||
(AfterAddNodeOnFinish) super.mOnFinish;
|
(AfterActionNodeOnFinish) super.mOnFinish;
|
||||||
afterAddNode.mSuccess = mSuccess;
|
afterAddNode.mSuccess = mSuccess;
|
||||||
afterAddNode.mMessage = mMessage;
|
afterAddNode.mMessage = mMessage;
|
||||||
afterAddNode.run(mGroup);
|
afterAddNode.run(null, mNewGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ import android.os.Handler;
|
|||||||
|
|
||||||
import com.kunzisoft.keepass.database.PwNode;
|
import com.kunzisoft.keepass.database.PwNode;
|
||||||
|
|
||||||
public abstract class AfterAddNodeOnFinish extends OnFinish {
|
public abstract class AfterActionNodeOnFinish extends OnFinish {
|
||||||
public AfterAddNodeOnFinish(Handler handler) {
|
public AfterActionNodeOnFinish(Handler handler) {
|
||||||
super(handler);
|
super(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void run(PwNode pwNode);
|
public abstract void run(PwNode oldNode, PwNode newNode);
|
||||||
}
|
}
|
||||||
@@ -45,11 +45,6 @@ public class DeleteGroup extends RunnableOnFinish {
|
|||||||
super(finish);
|
super(finish);
|
||||||
setMembers(ctx, db, group, dontSave);
|
setMembers(ctx, db, group, dontSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeleteGroup(Database db, PwGroup<PwGroup, PwGroup, PwEntry> group, OnFinish finish, boolean dontSave) {
|
|
||||||
super(finish);
|
|
||||||
setMembers(null, db, group, dontSave);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setMembers(Context ctx, Database db, PwGroup<PwGroup, PwGroup, PwEntry> group, boolean dontSave) {
|
private void setMembers(Context ctx, Database db, PwGroup<PwGroup, PwGroup, PwEntry> group, boolean dontSave) {
|
||||||
mDb = db;
|
mDb = db;
|
||||||
|
|||||||
@@ -30,14 +30,20 @@ public class UpdateEntry extends RunnableOnFinish {
|
|||||||
private PwEntry mOldE;
|
private PwEntry mOldE;
|
||||||
private PwEntry mNewE;
|
private PwEntry mNewE;
|
||||||
private Context ctx;
|
private Context ctx;
|
||||||
|
private boolean mDontSave;
|
||||||
|
|
||||||
public UpdateEntry(Context ctx, Database db, PwEntry oldE, PwEntry newE, OnFinish finish) {
|
public UpdateEntry(Context ctx, Database db, PwEntry oldE, PwEntry newE, OnFinish finish) {
|
||||||
|
this(ctx, db, oldE, newE, finish, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateEntry(Context ctx, Database db, PwEntry oldE, PwEntry newE, OnFinish finish, boolean dontSave) {
|
||||||
super(finish);
|
super(finish);
|
||||||
|
|
||||||
mDb = db;
|
this.mDb = db;
|
||||||
mOldE = oldE;
|
this.mOldE = oldE;
|
||||||
mNewE = newE;
|
this.mNewE = newE;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
|
this.mDontSave = dontSave;
|
||||||
|
|
||||||
// Keep backup of original values in case save fails
|
// Keep backup of original values in case save fails
|
||||||
PwEntry backup;
|
PwEntry backup;
|
||||||
@@ -53,7 +59,7 @@ public class UpdateEntry extends RunnableOnFinish {
|
|||||||
mOldE.touch(true, true);
|
mOldE.touch(true, true);
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDB save = new SaveDB(ctx, mDb, mFinish);
|
SaveDB save = new SaveDB(ctx, mDb, mFinish, mDontSave);
|
||||||
save.run();
|
save.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||||
|
*
|
||||||
|
* This file is part of KeePass DX.
|
||||||
|
*
|
||||||
|
* KeePass DX is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePass DX is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.kunzisoft.keepass.database.edit;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.database.Database;
|
||||||
|
import com.kunzisoft.keepass.database.PwGroup;
|
||||||
|
|
||||||
|
public class UpdateGroup extends RunnableOnFinish {
|
||||||
|
|
||||||
|
private Database mDb;
|
||||||
|
private PwGroup mOldGroup;
|
||||||
|
private PwGroup mNewGroup;
|
||||||
|
private Context ctx;
|
||||||
|
private boolean mDontSave;
|
||||||
|
|
||||||
|
public UpdateGroup(Context ctx, Database db, PwGroup oldGroup, PwGroup newGroup, AfterActionNodeOnFinish finish) {
|
||||||
|
this(ctx, db, oldGroup, newGroup, finish, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateGroup(Context ctx, Database db, PwGroup oldGroup, PwGroup newGroup, AfterActionNodeOnFinish finish, boolean dontSave) {
|
||||||
|
super(finish);
|
||||||
|
|
||||||
|
this.mDb = db;
|
||||||
|
this.mOldGroup = oldGroup;
|
||||||
|
this.mNewGroup = newGroup;
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.mDontSave = dontSave;
|
||||||
|
|
||||||
|
// Keep backup of original values in case save fails
|
||||||
|
PwGroup backup;
|
||||||
|
backup = mOldGroup.clone();
|
||||||
|
|
||||||
|
this.mFinish = new AfterUpdate(backup, finish);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Update group with new values
|
||||||
|
mDb.updateGroup(mOldGroup, mNewGroup);
|
||||||
|
mOldGroup.touch(true, true);
|
||||||
|
|
||||||
|
// Commit to disk
|
||||||
|
new SaveDB(ctx, mDb, mFinish, mDontSave).run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AfterUpdate extends OnFinish {
|
||||||
|
private PwGroup mBackup;
|
||||||
|
|
||||||
|
AfterUpdate(PwGroup backup, OnFinish finish) {
|
||||||
|
super(finish);
|
||||||
|
mBackup = backup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if ( !mSuccess ) {
|
||||||
|
// If we fail to save, back out changes to global structure
|
||||||
|
mDb.updateGroup(mOldGroup, mBackup);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Better callback
|
||||||
|
AfterActionNodeOnFinish afterActionNodeOnFinish =
|
||||||
|
(AfterActionNodeOnFinish) super.mOnFinish;
|
||||||
|
afterActionNodeOnFinish.mSuccess = mSuccess;
|
||||||
|
afterActionNodeOnFinish.mMessage = mMessage;
|
||||||
|
afterActionNodeOnFinish.run(mOldGroup, mNewGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,29 +35,50 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.kunzisoft.keepass.R;
|
import com.kunzisoft.keepass.R;
|
||||||
import com.kunzisoft.keepass.app.App;
|
import com.kunzisoft.keepass.app.App;
|
||||||
|
import com.kunzisoft.keepass.database.PwIcon;
|
||||||
import com.kunzisoft.keepass.database.PwNode;
|
import com.kunzisoft.keepass.database.PwNode;
|
||||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||||
|
|
||||||
|
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION;
|
||||||
|
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE;
|
||||||
|
|
||||||
public class GroupEditDialogFragment extends DialogFragment
|
public class GroupEditDialogFragment extends DialogFragment
|
||||||
implements IconPickerDialogFragment.IconPickerListener {
|
implements IconPickerDialogFragment.IconPickerListener {
|
||||||
|
|
||||||
public static final String TAG_CREATE_GROUP = "TAG_CREATE_GROUP";
|
public static final String TAG_CREATE_GROUP = "TAG_CREATE_GROUP";
|
||||||
|
|
||||||
public static final String KEY_NAME = "name";
|
public static final String KEY_NAME = "KEY_NAME";
|
||||||
public static final String KEY_ICON_ID = "icon_id";
|
public static final String KEY_ICON_ID = "KEY_ICON_ID";
|
||||||
|
public static final String KEY_ACTION_ID = "KEY_ACTION_ID";
|
||||||
|
|
||||||
|
private EditGroupDialogAction editGroupDialogAction = EditGroupDialogAction.NONE;
|
||||||
|
|
||||||
private EditGroupListener editGroupListener;
|
private EditGroupListener editGroupListener;
|
||||||
|
|
||||||
private TextView nameField;
|
|
||||||
private ImageView iconButton;
|
private ImageView iconButton;
|
||||||
private int mSelectedIconID;
|
private int mSelectedIconID;
|
||||||
private View root;
|
|
||||||
|
public enum EditGroupDialogAction {
|
||||||
|
CREATION, UPDATE, NONE;
|
||||||
|
|
||||||
|
public static EditGroupDialogAction getActionFromOrdinal(int ordinal) {
|
||||||
|
return EditGroupDialogAction.values()[ordinal];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupEditDialogFragment build() {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt(KEY_ACTION_ID, CREATION.ordinal());
|
||||||
|
GroupEditDialogFragment fragment = new GroupEditDialogFragment();
|
||||||
|
fragment.setArguments(bundle);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
public static GroupEditDialogFragment build(PwNode group) {
|
public static GroupEditDialogFragment build(PwNode group) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putString(KEY_NAME, group.getDisplayTitle());
|
bundle.putString(KEY_NAME, group.getDisplayTitle());
|
||||||
// TODO Change
|
bundle.putSerializable(KEY_ICON_ID, group.getIcon());
|
||||||
bundle.putInt(KEY_ICON_ID, group.getIcon().hashCode());
|
bundle.putInt(KEY_ACTION_ID, UPDATE.ordinal());
|
||||||
GroupEditDialogFragment fragment = new GroupEditDialogFragment();
|
GroupEditDialogFragment fragment = new GroupEditDialogFragment();
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
return fragment;
|
return fragment;
|
||||||
@@ -80,27 +101,55 @@ public class GroupEditDialogFragment extends DialogFragment
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
assert getActivity() != null;
|
||||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||||
root = inflater.inflate(R.layout.group_edit, null);
|
View root = inflater.inflate(R.layout.group_edit, null);
|
||||||
nameField = root.findViewById(R.id.group_name);
|
TextView nameField = root.findViewById(R.id.group_name);
|
||||||
iconButton = root.findViewById(R.id.icon_button);
|
iconButton = root.findViewById(R.id.icon_button);
|
||||||
|
|
||||||
|
if (getArguments() != null
|
||||||
|
&& getArguments().containsKey(KEY_ACTION_ID))
|
||||||
|
editGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(getArguments().getInt(KEY_ACTION_ID));
|
||||||
|
|
||||||
|
// Retrieve the textColor to tint the icon
|
||||||
|
int[] attrs = {android.R.attr.textColorPrimary};
|
||||||
|
TypedArray ta = getActivity().getTheme().obtainStyledAttributes(attrs);
|
||||||
|
int iconColor = ta.getColor(0, Color.WHITE);
|
||||||
|
|
||||||
if (getArguments() != null
|
if (getArguments() != null
|
||||||
&& getArguments().containsKey(KEY_NAME)
|
&& getArguments().containsKey(KEY_NAME)
|
||||||
&& getArguments().containsKey(KEY_ICON_ID)) {
|
&& getArguments().containsKey(KEY_ICON_ID)) {
|
||||||
nameField.setText(getArguments().getString(KEY_NAME));
|
nameField.setText(getArguments().getString(KEY_NAME));
|
||||||
populateIcon(getArguments().getInt(KEY_ICON_ID));
|
// populate the icon
|
||||||
} else {
|
|
||||||
// populate the icon with the default one
|
|
||||||
if (IconPackChooser.getSelectedIconPack(getContext()).tintable()) {
|
if (IconPackChooser.getSelectedIconPack(getContext()).tintable()) {
|
||||||
// Retrieve the textColor to tint the icon
|
App.getDB().getDrawFactory()
|
||||||
int[] attrs = {android.R.attr.textColorPrimary};
|
.assignDatabaseIconTo(
|
||||||
TypedArray ta = getContext().getTheme().obtainStyledAttributes(attrs);
|
getContext(),
|
||||||
int iconColor = ta.getColor(0, Color.WHITE);
|
iconButton,
|
||||||
App.getDB().getDrawFactory().assignDefaultDatabaseIconTo(getContext(), iconButton, true, iconColor);
|
(PwIcon) getArguments().getSerializable(KEY_ICON_ID),
|
||||||
|
true,
|
||||||
|
iconColor);
|
||||||
} else {
|
} else {
|
||||||
App.getDB().getDrawFactory().assignDefaultDatabaseIconTo(getContext(), iconButton);
|
App.getDB().getDrawFactory()
|
||||||
|
.assignDatabaseIconTo(
|
||||||
|
getContext(),
|
||||||
|
iconButton,
|
||||||
|
(PwIcon) getArguments().getSerializable(KEY_ICON_ID));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// populate the icon with the default one if not found
|
||||||
|
if (IconPackChooser.getSelectedIconPack(getContext()).tintable()) {
|
||||||
|
App.getDB().getDrawFactory()
|
||||||
|
.assignDefaultDatabaseIconTo(
|
||||||
|
getContext(),
|
||||||
|
iconButton,
|
||||||
|
true,
|
||||||
|
iconColor);
|
||||||
|
} else {
|
||||||
|
App.getDB().getDrawFactory()
|
||||||
|
.assignDefaultDatabaseIconTo(
|
||||||
|
getContext(),
|
||||||
|
iconButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,10 +158,10 @@ public class GroupEditDialogFragment extends DialogFragment
|
|||||||
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
|
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
|
||||||
String name = nameField.getText().toString();
|
String name = nameField.getText().toString();
|
||||||
if ( name.length() > 0 ) {
|
if ( name.length() > 0 ) {
|
||||||
Bundle bundle = new Bundle();
|
editGroupListener.approveEditGroup(
|
||||||
bundle.putString(KEY_NAME, name);
|
editGroupDialogAction,
|
||||||
bundle.putInt(KEY_ICON_ID, mSelectedIconID);
|
name,
|
||||||
editGroupListener.approveEditGroup(bundle);
|
mSelectedIconID);
|
||||||
|
|
||||||
GroupEditDialogFragment.this.getDialog().cancel();
|
GroupEditDialogFragment.this.getDialog().cancel();
|
||||||
}
|
}
|
||||||
@@ -121,32 +170,32 @@ public class GroupEditDialogFragment extends DialogFragment
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.cancel, (dialog, id) -> {
|
.setNegativeButton(R.string.cancel, (dialog, id) -> {
|
||||||
Bundle bundle = new Bundle();
|
String name = nameField.getText().toString();
|
||||||
editGroupListener.cancelEditGroup(bundle);
|
editGroupListener.cancelEditGroup(
|
||||||
|
editGroupDialogAction,
|
||||||
|
name,
|
||||||
|
mSelectedIconID);
|
||||||
|
|
||||||
GroupEditDialogFragment.this.getDialog().cancel();
|
GroupEditDialogFragment.this.getDialog().cancel();
|
||||||
});
|
});
|
||||||
|
|
||||||
iconButton.setOnClickListener(v -> {
|
iconButton.setOnClickListener(v -> {
|
||||||
IconPickerDialogFragment iconPickerDialogFragment = new IconPickerDialogFragment();
|
IconPickerDialogFragment iconPickerDialogFragment = new IconPickerDialogFragment();
|
||||||
iconPickerDialogFragment.show(getFragmentManager(), "IconPickerDialogFragment");
|
if (getFragmentManager() != null)
|
||||||
|
iconPickerDialogFragment.show(getFragmentManager(), "IconPickerDialogFragment");
|
||||||
});
|
});
|
||||||
|
|
||||||
return builder.create();
|
return builder.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateIcon(int iconId) {
|
|
||||||
iconButton.setImageResource(IconPackChooser.getSelectedIconPack(getContext()).iconToResId(iconId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void iconPicked(Bundle bundle) {
|
public void iconPicked(Bundle bundle) {
|
||||||
mSelectedIconID = bundle.getInt(IconPickerDialogFragment.KEY_ICON_ID);
|
mSelectedIconID = bundle.getInt(IconPickerDialogFragment.KEY_ICON_ID);
|
||||||
populateIcon(mSelectedIconID);
|
iconButton.setImageResource(IconPackChooser.getSelectedIconPack(getContext()).iconToResId(mSelectedIconID));
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface EditGroupListener {
|
public interface EditGroupListener {
|
||||||
void approveEditGroup(Bundle bundle);
|
void approveEditGroup(EditGroupDialogAction action, String name, int selectedIconId);
|
||||||
void cancelEditGroup(Bundle bundle);
|
void cancelEditGroup(EditGroupDialogAction action, String name, int selectedIconId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user