Add modification

This commit is contained in:
J-Jamet
2018-04-21 14:20:43 +02:00
parent 268f716104
commit fb1b90a281
21 changed files with 443 additions and 198 deletions

View File

@@ -60,7 +60,7 @@ public class DeleteEntry extends AndroidTestCase {
assertNotNull("Could not find group1", group1);
// Delete the group
DeleteGroup task = new DeleteGroup(db, group1, null, true);
DeleteGroup task = new DeleteGroup(null, db, group1, null, true);
task.run();
// Verify the entries were deleted

View File

@@ -175,7 +175,7 @@ public class EntryEditActivity extends LockingHideActivity
if ( uuidBytes == null ) {
PwGroupId parentId = (PwGroupId) intent.getSerializableExtra(KEY_PARENT);
PwGroup parent = pm.getGroupByGroupId(parentId);
mEntry = PwEntry.getInstance(parent);
mEntry = db.createEntry(parent);
mIsNew = true;
// Add the default icon
if (IconPackChooser.getSelectedIconPack(this).tintable()) {

View File

@@ -53,11 +53,13 @@ import com.kunzisoft.keepass.database.Database;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwGroup;
import com.kunzisoft.keepass.database.PwGroupId;
import com.kunzisoft.keepass.database.PwIconStandard;
import com.kunzisoft.keepass.database.PwNode;
import com.kunzisoft.keepass.database.SortNodeEnum;
import com.kunzisoft.keepass.database.edit.AddGroup;
import com.kunzisoft.keepass.database.edit.DeleteEntry;
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.GroupEditDialogFragment;
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
@@ -82,14 +84,11 @@ public class GroupActivity extends ListNodesActivity
protected boolean addEntryEnabled = false;
protected boolean isRoot = false;
protected boolean readOnly = false;
protected EditGroupDialogAction editGroupDialogAction = EditGroupDialogAction.NONE;
private enum EditGroupDialogAction {
CREATION, UPDATE, NONE
}
private static final String TAG = "Group Activity:";
private PwGroup oldGroupToUpdate;
public static void launch(Activity act) {
recordFirstTimeBeforeLaunch(act);
launch(act, (PwGroup) null);
@@ -160,9 +159,8 @@ public class GroupActivity extends ListNodesActivity
toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp);
addNodeButtonView.setAddGroupClickListener(v -> {
editGroupDialogAction = EditGroupDialogAction.CREATION;
GroupEditDialogFragment groupEditDialogFragment = new GroupEditDialogFragment();
groupEditDialogFragment.show(getSupportFragmentManager(),
GroupEditDialogFragment.build()
.show(getSupportFragmentManager(),
GroupEditDialogFragment.TAG_CREATE_GROUP);
});
addNodeButtonView.setAddEntryClickListener(v ->
@@ -215,7 +213,6 @@ public class GroupActivity extends ListNodesActivity
nodeAdapter.setNodeMenuListener(new NodeAdapter.NodeMenuListener() {
@Override
public boolean onOpenMenuClick(PwNode node) {
mAdapter.registerANodeToUpdate(node);
switch (node.getType()) {
case GROUP:
GroupActivity.launch(GroupActivity.this, (PwGroup) node);
@@ -229,13 +226,11 @@ public class GroupActivity extends ListNodesActivity
@Override
public boolean onEditMenuClick(PwNode node) {
mAdapter.registerANodeToUpdate(node);
switch (node.getType()) {
case GROUP:
editGroupDialogAction = EditGroupDialogAction.UPDATE;
GroupEditDialogFragment groupEditDialogFragment =
GroupEditDialogFragment.build(node);
groupEditDialogFragment.show(getSupportFragmentManager(),
oldGroupToUpdate = (PwGroup) node;
GroupEditDialogFragment.build(node)
.show(getSupportFragmentManager(),
GroupEditDialogFragment.TAG_CREATE_GROUP);
break;
case ENTRY:
@@ -528,28 +523,53 @@ public class GroupActivity extends ListNodesActivity
}
@Override
public void approveEditGroup(Bundle bundle) {
String GroupName = bundle.getString(GroupEditDialogFragment.KEY_NAME);
int GroupIconID = bundle.getInt(GroupEditDialogFragment.KEY_ICON_ID);
switch (editGroupDialogAction) {
public void approveEditGroup(GroupEditDialogFragment.EditGroupDialogAction action,
String name,
int iconId) {
Database database = App.getDB(); // TODO encapsulate iconFactory
PwIconStandard icon = database.getPwDatabase().getIconFactory().getIcon(iconId);
switch (action) {
case CREATION:
// If edit group creation
Handler handler = new Handler();
AddGroup task = new AddGroup(this, App.getDB(), GroupName, GroupIconID, mCurrentGroup,
new AfterAddNode(handler), false);
ProgressTask pt = new ProgressTask(this, task, R.string.saving_database);
pt.run();
// If group creation
// Build the group
PwGroup newGroup = database.createGroup(mCurrentGroup);
newGroup.setName(name);
newGroup.setIcon(icon);
new ProgressTask(this,
new AddGroup(this,
App.getDB(),
newGroup,
new AfterAddNode(new Handler())),
R.string.saving_database)
.run();
break;
case UPDATE:
// If edit group update
// TODO UpdateGroup
// If update add new elements
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;
}
editGroupDialogAction = EditGroupDialogAction.NONE;
}
@Override
public void cancelEditGroup(Bundle bundle) {
public void cancelEditGroup(GroupEditDialogFragment.EditGroupDialogAction action,
String name,
int iconId) {
// Do nothing here
}

View File

@@ -49,7 +49,7 @@ import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwGroup;
import com.kunzisoft.keepass.database.PwNode;
import com.kunzisoft.keepass.database.SortNodeEnum;
import com.kunzisoft.keepass.database.edit.AfterAddNodeOnFinish;
import com.kunzisoft.keepass.database.edit.AfterActionNodeOnFinish;
import com.kunzisoft.keepass.database.edit.OnFinish;
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
@@ -143,8 +143,6 @@ public abstract class ListNodesActivity extends LockingActivity
@Override
public void onNodeClick(PwNode node) {
mAdapter.registerANodeToUpdate(node);
// Add event when we have Autofill
AssistStructure assistStructure = null;
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) {
super(handler);
}
public void run(PwNode pwNode) {
public void run(PwNode oldNode, PwNode newNode) {
super.run();
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 {
displayMessage(ListNodesActivity.this);
}

View File

@@ -26,7 +26,6 @@ import android.support.annotation.NonNull;
import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.util.SortedListAdapterCallback;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -54,7 +53,6 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
private boolean ascendingSort;
private OnNodeClickCallback onNodeClickCallback;
private int nodePositionToUpdate;
private NodeMenuListener nodeMenuListener;
private boolean activateContextMenu;
@@ -73,7 +71,6 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
this.groupsBeforeSort = PreferencesUtil.getGroupsBeforeSort(context);
this.ascendingSort = PreferencesUtil.getAscendingSort(context);
this.activateContextMenu = false;
this.nodePositionToUpdate = -1;
this.nodeSortedList = new SortedList<>(PwNode.class, new SortedListAdapterCallback<PwNode>(this) {
@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
* 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
* Remove a node in the list
* @param node Node to delete
*/
public void removeNode(PwNode 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
*/
@@ -170,6 +149,7 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
return nodeSortedList.get(position).getType().ordinal();
}
@NonNull
@Override
public BasicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
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);
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
if (!App.getDB().isReadOnly() && !node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
// TODO make edit for group
// clearMenu = contextMenu.add(Menu.NONE, MENU_EDIT, Menu.NONE, R.string.menu_edit);
// clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
// Edition
clearMenu = contextMenu.add(Menu.NONE, MENU_EDIT, Menu.NONE, R.string.menu_edit);
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
// Deletion
clearMenu = contextMenu.add(Menu.NONE, MENU_DELETE, Menu.NONE, R.string.menu_delete);
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
}

View File

@@ -368,6 +368,37 @@ public class Database {
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) {
try {
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) {
try {
switch (getPwDatabase().getVersion()) {

View File

@@ -45,7 +45,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
package com.kunzisoft.keepass.database;
// Java
import com.kunzisoft.keepass.crypto.keyDerivation.AesKdf;
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException;
@@ -71,13 +70,6 @@ public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
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
public void initNew(String dbPath) {
algorithm = PwEncryptionAlgorithm.AES_Rijndael;
@@ -90,6 +82,14 @@ public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
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
public PwVersion getVersion() {
return PwVersion.V3;

View File

@@ -24,7 +24,7 @@ import com.kunzisoft.keepass.database.security.ProtectedString;
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>";
@@ -36,33 +36,10 @@ public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> imp
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
public PwEntry clone() {
PwEntry newEntry;
try {
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)
return (PwEntry) super.clone();
}
@Override

View File

@@ -98,6 +98,7 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
}
protected void updateWith(PwEntryV3 source) {
super.assign(source);
groupId = source.groupId;
title = source.title;
@@ -118,10 +119,8 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
@Override
public PwEntryV3 clone() {
PwEntryV3 newEntry = (PwEntryV3) super.clone();
// Attributes in parent
addCloneAttributesToNewEntry(newEntry);
PwEntryV3 newEntry = (PwEntryV3) super.clone();
// Attributes here
// newEntry.parent stay the same in copy

View File

@@ -89,10 +89,8 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
@SuppressWarnings("unchecked")
@Override
public PwEntryV4 clone() {
PwEntryV4 newEntry = (PwEntryV4) super.clone();
// Attributes in parent
addCloneAttributesToNewEntry(newEntry);
PwEntryV4 newEntry = (PwEntryV4) super.clone();
// Attributes here
newEntry.customIcon = new PwIconCustom(this.customIcon);

View File

@@ -30,9 +30,15 @@ public abstract class PwGroup<Parent extends PwGroup, ChildGroup extends PwGroup
protected List<ChildGroup> childGroups = new ArrayList<>();
protected List<ChildEntry> childEntries = new ArrayList<>();
public void initNewGroup(String nm, PwGroupId newId) {
setId(newId);
name = nm;
@Override
public PwGroup clone() {
// 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() {

View File

@@ -40,6 +40,26 @@ public class PwGroupV3 extends PwGroup<PwGroupV3, PwGroupV3, PwEntryV3> {
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
public void setParent(PwGroupV3 parent) {
super.setParent(parent);

View File

@@ -46,16 +46,58 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
super();
}
public PwGroupV4(PwGroupV4 p) {
construct(p);
parentGroupLastMod = new PwDate();
}
public PwGroupV4(String name, PwIconStandard icon) {
this.uuid = UUID.randomUUID();
this.name = name;
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
public void initNewGroup(String nm, PwGroupId newId) {
super.initNewGroup(nm, newId);
parentGroupLastMod = new PwDate();
public PwGroupV4 clone() {
// Attributes in parent
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) {

View File

@@ -27,7 +27,7 @@ import java.io.Serializable;
/**
* 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;
@@ -53,15 +53,23 @@ public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger
this.expireDate = source.expireDate;
}
protected void addCloneAttributesToNewEntry(PwEntry newEntry) {
// newEntry.parent stay the same in copy
@Override
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();
newEntry.lastMod = lastMod.clone();
newEntry.lastAccess = lastAccess.clone();
newEntry.expireDate = expireDate.clone();
newNode.creation = creation.clone();
newNode.lastMod = lastMod.clone();
newNode.lastAccess = lastAccess.clone();
newNode.expireDate = expireDate.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Clone should be supported");
}
return newNode;
}
/**

View File

@@ -29,13 +29,19 @@ public class AddEntry extends RunnableOnFinish {
protected Database mDb;
private PwEntry mEntry;
private Context ctx;
private boolean mDontSave;
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);
this.mDb = db;
this.mEntry = entry;
this.ctx = ctx;
this.mDontSave = dontSave;
this.mFinish = new AfterAdd(mFinish);
}
@@ -45,7 +51,7 @@ public class AddEntry extends RunnableOnFinish {
mDb.addEntryTo(mEntry, mEntry.getParent());
// Commit to disk
SaveDB save = new SaveDB(ctx, mDb, mFinish);
SaveDB save = new SaveDB(ctx, mDb, mFinish, mDontSave);
save.run();
}

View File

@@ -22,28 +22,25 @@ package com.kunzisoft.keepass.database.edit;
import android.content.Context;
import com.kunzisoft.keepass.database.Database;
import com.kunzisoft.keepass.database.PwDatabase;
import com.kunzisoft.keepass.database.PwGroup;
public class AddGroup extends RunnableOnFinish {
protected Database mDb;
private String mName;
private int mIconID;
private PwGroup mGroup;
private PwGroup mParent;
private PwGroup mNewGroup;
private Context ctx;
private boolean mDontSave;
public AddGroup(Context ctx, Database db, String name, int iconid,
PwGroup parent, AfterAddNodeOnFinish afterAddNode,
public AddGroup(Context ctx, Database db, PwGroup newGroup, AfterActionNodeOnFinish afterAddNode) {
this(ctx, db, newGroup, afterAddNode, false);
}
public AddGroup(Context ctx, Database db, PwGroup newGroup, AfterActionNodeOnFinish afterAddNode,
boolean dontSave) {
super(afterAddNode);
this.mDb = db;
this.mName = name;
this.mIconID = iconid;
this.mParent = parent;
this.mNewGroup = newGroup;
this.mDontSave = dontSave;
this.ctx = ctx;
@@ -52,13 +49,7 @@ public class AddGroup extends RunnableOnFinish {
@Override
public void run() {
PwDatabase pm = mDb.getPwDatabase();
// Generate new group
mGroup = pm.createGroup();
mGroup.initNewGroup(mName, pm.newGroupId());
mGroup.setIcon(pm.getIconFactory().getIcon(mIconID));
mDb.addGroupTo(mGroup, mParent);
mDb.addGroupTo(mNewGroup, mNewGroup.getParent());
// Commit to disk
SaveDB save = new SaveDB(ctx, mDb, mFinish, mDontSave);
@@ -74,15 +65,15 @@ public class AddGroup extends RunnableOnFinish {
@Override
public void run() {
if ( !mSuccess ) {
mDb.removeGroupFrom(mGroup, mParent);
mDb.removeGroupFrom(mNewGroup, mNewGroup.getParent());
}
// TODO Better callback
AfterAddNodeOnFinish afterAddNode =
(AfterAddNodeOnFinish) super.mOnFinish;
AfterActionNodeOnFinish afterAddNode =
(AfterActionNodeOnFinish) super.mOnFinish;
afterAddNode.mSuccess = mSuccess;
afterAddNode.mMessage = mMessage;
afterAddNode.run(mGroup);
afterAddNode.run(null, mNewGroup);
}
}
}

View File

@@ -23,10 +23,10 @@ import android.os.Handler;
import com.kunzisoft.keepass.database.PwNode;
public abstract class AfterAddNodeOnFinish extends OnFinish {
public AfterAddNodeOnFinish(Handler handler) {
public abstract class AfterActionNodeOnFinish extends OnFinish {
public AfterActionNodeOnFinish(Handler handler) {
super(handler);
}
public abstract void run(PwNode pwNode);
public abstract void run(PwNode oldNode, PwNode newNode);
}

View File

@@ -46,11 +46,6 @@ public class DeleteGroup extends RunnableOnFinish {
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) {
mDb = db;
mGroup = group;

View File

@@ -30,14 +30,20 @@ public class UpdateEntry extends RunnableOnFinish {
private PwEntry mOldE;
private PwEntry mNewE;
private Context ctx;
private boolean mDontSave;
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);
mDb = db;
mOldE = oldE;
mNewE = newE;
this.mDb = db;
this.mOldE = oldE;
this.mNewE = newE;
this.ctx = ctx;
this.mDontSave = dontSave;
// Keep backup of original values in case save fails
PwEntry backup;
@@ -53,7 +59,7 @@ public class UpdateEntry extends RunnableOnFinish {
mOldE.touch(true, true);
// Commit to disk
SaveDB save = new SaveDB(ctx, mDb, mFinish);
SaveDB save = new SaveDB(ctx, mDb, mFinish, mDontSave);
save.run();
}

View File

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

View File

@@ -35,29 +35,50 @@ import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.database.PwIcon;
import com.kunzisoft.keepass.database.PwNode;
import com.kunzisoft.keepass.icons.IconPackChooser;
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION;
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE;
public class GroupEditDialogFragment extends DialogFragment
implements IconPickerDialogFragment.IconPickerListener {
public static final String TAG_CREATE_GROUP = "TAG_CREATE_GROUP";
public static final String KEY_NAME = "name";
public static final String KEY_ICON_ID = "icon_id";
public static final String KEY_NAME = "KEY_NAME";
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 TextView nameField;
private ImageView iconButton;
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) {
Bundle bundle = new Bundle();
bundle.putString(KEY_NAME, group.getDisplayTitle());
// TODO Change
bundle.putInt(KEY_ICON_ID, group.getIcon().hashCode());
bundle.putSerializable(KEY_ICON_ID, group.getIcon());
bundle.putInt(KEY_ACTION_ID, UPDATE.ordinal());
GroupEditDialogFragment fragment = new GroupEditDialogFragment();
fragment.setArguments(bundle);
return fragment;
@@ -80,27 +101,55 @@ public class GroupEditDialogFragment extends DialogFragment
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
assert getActivity() != null;
LayoutInflater inflater = getActivity().getLayoutInflater();
root = inflater.inflate(R.layout.group_edit, null);
nameField = root.findViewById(R.id.group_name);
View root = inflater.inflate(R.layout.group_edit, null);
TextView nameField = root.findViewById(R.id.group_name);
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
&& getArguments().containsKey(KEY_NAME)
&& getArguments().containsKey(KEY_ICON_ID)) {
nameField.setText(getArguments().getString(KEY_NAME));
populateIcon(getArguments().getInt(KEY_ICON_ID));
} else {
// populate the icon with the default one
// populate the icon
if (IconPackChooser.getSelectedIconPack(getContext()).tintable()) {
// Retrieve the textColor to tint the icon
int[] attrs = {android.R.attr.textColorPrimary};
TypedArray ta = getContext().getTheme().obtainStyledAttributes(attrs);
int iconColor = ta.getColor(0, Color.WHITE);
App.getDB().getDrawFactory().assignDefaultDatabaseIconTo(getContext(), iconButton, true, iconColor);
App.getDB().getDrawFactory()
.assignDatabaseIconTo(
getContext(),
iconButton,
(PwIcon) getArguments().getSerializable(KEY_ICON_ID),
true,
iconColor);
} 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) -> {
String name = nameField.getText().toString();
if ( name.length() > 0 ) {
Bundle bundle = new Bundle();
bundle.putString(KEY_NAME, name);
bundle.putInt(KEY_ICON_ID, mSelectedIconID);
editGroupListener.approveEditGroup(bundle);
editGroupListener.approveEditGroup(
editGroupDialogAction,
name,
mSelectedIconID);
GroupEditDialogFragment.this.getDialog().cancel();
}
@@ -121,32 +170,32 @@ public class GroupEditDialogFragment extends DialogFragment
}
})
.setNegativeButton(R.string.cancel, (dialog, id) -> {
Bundle bundle = new Bundle();
editGroupListener.cancelEditGroup(bundle);
String name = nameField.getText().toString();
editGroupListener.cancelEditGroup(
editGroupDialogAction,
name,
mSelectedIconID);
GroupEditDialogFragment.this.getDialog().cancel();
});
iconButton.setOnClickListener(v -> {
IconPickerDialogFragment iconPickerDialogFragment = new IconPickerDialogFragment();
if (getFragmentManager() != null)
iconPickerDialogFragment.show(getFragmentManager(), "IconPickerDialogFragment");
});
return builder.create();
}
private void populateIcon(int iconId) {
iconButton.setImageResource(IconPackChooser.getSelectedIconPack(getContext()).iconToResId(iconId));
}
@Override
public void iconPicked(Bundle bundle) {
mSelectedIconID = bundle.getInt(IconPickerDialogFragment.KEY_ICON_ID);
populateIcon(mSelectedIconID);
iconButton.setImageResource(IconPackChooser.getSelectedIconPack(getContext()).iconToResId(mSelectedIconID));
}
public interface EditGroupListener {
void approveEditGroup(Bundle bundle);
void cancelEditGroup(Bundle bundle);
void approveEditGroup(EditGroupDialogAction action, String name, int selectedIconId);
void cancelEditGroup(EditGroupDialogAction action, String name, int selectedIconId);
}
}