Add contextual bar to paste and add move entry

This commit is contained in:
J-Jamet
2018-05-24 19:51:28 +02:00
parent 5286a60142
commit 9424feefce
13 changed files with 346 additions and 28 deletions

View File

@@ -37,6 +37,7 @@ import android.support.annotation.RequiresApi;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -56,6 +57,7 @@ import com.kunzisoft.keepass.database.PwIcon;
import com.kunzisoft.keepass.database.PwIconStandard;
import com.kunzisoft.keepass.database.PwNode;
import com.kunzisoft.keepass.database.action.AddGroupRunnable;
import com.kunzisoft.keepass.database.action.CopyEntryRunnable;
import com.kunzisoft.keepass.database.action.DeleteEntryRunnable;
import com.kunzisoft.keepass.database.action.DeleteGroupRunnable;
import com.kunzisoft.keepass.database.action.UpdateGroupRunnable;
@@ -257,6 +259,65 @@ public class GroupActivity extends ListNodesActivity
return true;
}
@Override
public boolean onCopyMenuClick(PwNode node) {
startActionMode(new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
actionMode.setTitle(R.string.where);
actionMode.getMenuInflater().inflate(R.menu.node_paste_menu, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
actionMode.finish();
switch (menuItem.getItemId()) {
case R.id.menu_paste:
switch (node.getType()) {
case GROUP:
break;
case ENTRY:
copyNode((PwEntry) node, mCurrentGroup);
break;
}
return true;
}
return true;
}
@Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
// TODO COPY
return false;
}
private void copyNode(PwEntry entryToCopy, PwGroup newParent) {
CopyEntryRunnable task = new CopyEntryRunnable(this, App.getDB(), entryToCopy, newParent,
new AfterAddNode(new Handler()));
task.setUpdateProgressTaskStatus(
new UpdateProgressTaskStatus(this,
SaveDatabaseProgressTaskDialogFragment.start(
getSupportFragmentManager())
));
new Thread(task).start();
}
@Override
public boolean onMoveMenuClick(PwNode node) {
// TODO MOVE
return false;
}
@Override
public boolean onDeleteMenuClick(PwNode node) {
switch (node.getType()) {
@@ -270,6 +331,29 @@ public class GroupActivity extends ListNodesActivity
return true;
}
private void deleteGroup(PwGroup group) {
//TODO Verify trash recycle bin
DeleteGroupRunnable task = new DeleteGroupRunnable(this, App.getDB(), group,
new AfterDeleteNode(new Handler(), group));
task.setUpdateProgressTaskStatus(
new UpdateProgressTaskStatus(this,
SaveDatabaseProgressTaskDialogFragment.start(
getSupportFragmentManager())
));
new Thread(task).start();
}
private void deleteEntry(PwEntry entry) {
DeleteEntryRunnable task = new DeleteEntryRunnable(this, App.getDB(), entry,
new AfterDeleteNode(new Handler(), entry));
task.setUpdateProgressTaskStatus(
new UpdateProgressTaskStatus(this,
SaveDatabaseProgressTaskDialogFragment.start(
getSupportFragmentManager())
));
new Thread(task).start();
}
@Override
protected void onResume() {
super.onResume();
@@ -420,31 +504,6 @@ public class GroupActivity extends ListNodesActivity
addNodeButtonView.hideButton();
}
private void deleteEntry(PwEntry entry) {
Handler handler = new Handler();
DeleteEntryRunnable task = new DeleteEntryRunnable(this, App.getDB(), entry,
new AfterDeleteNode(handler, entry));
task.setUpdateProgressTaskStatus(
new UpdateProgressTaskStatus(this,
SaveDatabaseProgressTaskDialogFragment.start(
getSupportFragmentManager())
));
new Thread(task).start();
}
private void deleteGroup(PwGroup group) {
//TODO Verify trash recycle bin
Handler handler = new Handler();
DeleteGroupRunnable task = new DeleteGroupRunnable(this, App.getDB(), group,
new AfterDeleteNode(handler, group));
task.setUpdateProgressTaskStatus(
new UpdateProgressTaskStatus(this,
SaveDatabaseProgressTaskDialogFragment.start(
getSupportFragmentManager())
));
new Thread(task).start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {

View File

@@ -237,6 +237,8 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
public interface NodeMenuListener {
boolean onOpenMenuClick(PwNode node);
boolean onEditMenuClick(PwNode node);
boolean onCopyMenuClick(PwNode node);
boolean onMoveMenuClick(PwNode node);
boolean onDeleteMenuClick(PwNode node);
}
@@ -264,7 +266,9 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
private static final int MENU_OPEN = Menu.FIRST;
private static final int MENU_EDIT = MENU_OPEN + 1;
private static final int MENU_DELETE = MENU_EDIT + 1;
private static final int MENU_COPY = MENU_EDIT + 1;
private static final int MENU_MOVE = MENU_COPY + 1;
private static final int MENU_DELETE = MENU_MOVE + 1;
private PwNode node;
private NodeMenuListener menuListener;
@@ -282,6 +286,12 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
// Edition
clearMenu = contextMenu.add(Menu.NONE, MENU_EDIT, Menu.NONE, R.string.menu_edit);
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
// Copy
clearMenu = contextMenu.add(Menu.NONE, MENU_COPY, Menu.NONE, R.string.menu_copy);
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
// Move
clearMenu = contextMenu.add(Menu.NONE, MENU_MOVE, Menu.NONE, R.string.menu_move);
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
// Deletion
clearMenu = contextMenu.add(Menu.NONE, MENU_DELETE, Menu.NONE, R.string.menu_delete);
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
@@ -298,6 +308,10 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
return menuListener.onOpenMenuClick(node);
case MENU_EDIT:
return menuListener.onEditMenuClick(node);
case MENU_COPY:
return menuListener.onCopyMenuClick(node);
case MENU_MOVE:
return menuListener.onMoveMenuClick(node);
case MENU_DELETE:
return menuListener.onDeleteMenuClick(node);
default:

View File

@@ -51,6 +51,9 @@ import java.io.OutputStream;
import java.io.SyncFailedException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nullable;
public class Database {
@@ -659,6 +662,42 @@ public class Database {
}
}
public @Nullable PwEntry copyEntry(PwEntry entryToCopy, PwGroup newParent) {
try {
// TODO encapsulate
switch (getPwDatabase().getVersion()) {
case V3:
PwEntryV3 entryV3Copied = ((PwEntryV3) entryToCopy).clone();
entryV3Copied.setUUID(UUID.randomUUID());
entryV3Copied.setParent((PwGroupV3) newParent);
return entryV3Copied;
case V4:
PwEntryV4 entryV4Copied = ((PwEntryV4) entryToCopy).clone();
entryV4Copied.setUUID(UUID.randomUUID());
entryV4Copied.setParent((PwGroupV4) newParent);
return entryV4Copied;
}
} catch (Exception e) {
Log.e(TAG, "This version of PwEntry can't be updated", e);
}
return null;
}
// TODO copy group
public void copyGroup(PwGroup groupToCopy, PwGroup newParent) {
}
// TODO move entry
public void moveEntry(PwEntry entryToMove, PwGroup newParent) {
}
// TODO move group
public void moveGroup(PwGroup groupToMove, PwGroup newParent) {
}
public void deleteEntry(PwEntry entry) {
try {
switch (getPwDatabase().getVersion()) {

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.action;
import android.content.Context;
import android.util.Log;
import com.kunzisoft.keepass.database.Database;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwGroup;
public class CopyEntryRunnable extends RunnableOnFinish {
private static final String TAG = CopyEntryRunnable.class.getName();
private Database mDb;
private PwEntry mEntryToCopy;
private PwEntry mEntryCopied;
private PwGroup mNewParent;
private Context mContext;
private boolean mDontSave;
public CopyEntryRunnable(Context context, Database db, PwEntry oldE, PwGroup newParent, AfterActionNodeOnFinish afterAddNode) {
this(context, db, oldE, newParent, afterAddNode, false);
}
public CopyEntryRunnable(Context context, Database db, PwEntry oldE, PwGroup newParent, AfterActionNodeOnFinish afterAddNode, boolean dontSave) {
super(afterAddNode);
this.mDb = db;
this.mEntryToCopy = oldE;
this.mNewParent = newParent;
this.mContext = context;
this.mDontSave = dontSave;
this.mFinish = new AfterCopy(afterAddNode);
}
@Override
public void run() {
// Update entry with new values
mEntryCopied = mDb.copyEntry(mEntryToCopy, mNewParent);
mDb.addEntryTo(mEntryCopied, mNewParent);
if (mEntryCopied != null) {
mEntryCopied.touch(true, true);
// Commit to disk
SaveDBRunnable save = new SaveDBRunnable(mContext, mDb, mFinish, mDontSave);
save.run();
} else {
Log.e(TAG, "Unable to create a copy of the entry");
}
}
private class AfterCopy extends OnFinishRunnable {
AfterCopy(OnFinishRunnable finish) {
super(finish);
}
@Override
public void run() {
if ( !mSuccess ) {
// If we fail to save, try to delete the copy
try {
mDb.deleteEntry(mEntryCopied);
} catch (Exception e) {
Log.i(TAG, "Unable to delete the copied entry");
}
}
// TODO Better callback
AfterActionNodeOnFinish afterAddNode =
(AfterActionNodeOnFinish) super.mOnFinish;
afterAddNode.mSuccess = mSuccess;
afterAddNode.mMessage = mMessage;
afterAddNode.run(null, mEntryCopied);
super.run();
}
}
}

View File

@@ -0,0 +1,49 @@
<?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"
android:icon="@drawable/ic_launch_white_24dp"
android:title="@string/menu_open"
android:orderInCategory="1010"
app:showAsAction="ifRoom" />
<item android:id="@+id/menu_edit"
android:icon="@drawable/ic_mode_edit_white_24dp"
android:title="@string/menu_edit"
android:orderInCategory="1020"
app:showAsAction="ifRoom" />
<!-- TODO Add menu
<item android:id="@+id/menu_copy"
android:icon="@drawable/ic_content_copy_white_24dp"
android:title="@string/menu_copy"
android:orderInCategory="1040"
app:showAsAction="ifRoom" />
<item android:id="@+id/menu_move"
android:icon="@drawable/ic_content_cut_white_24dp"
android:title="@string/menu_move"
android:orderInCategory="1030"
app:showAsAction="ifRoom" />
<item android:id="@+id/menu_delete"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/menu_delete"
android:orderInCategory="1050"
app:showAsAction="ifRoom" />
-->
</menu>

View File

@@ -0,0 +1,26 @@
<?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_paste"
android:title="@string/menu_paste"
android:orderInCategory="1090"
app:showAsAction="always|withText" />
</menu>

View File

@@ -21,6 +21,7 @@
<color name="transparent">#00ffffff</color>
<color name="white">#ffffff</color>
<color name="black">#000000</color>
<color name="dark">#0e0e0e</color>
<color name="orange_light">#ffa726</color>
<color name="orange">#fb8c00</color>

View File

@@ -121,9 +121,12 @@
<string name="menu_app_settings">Application settings</string>
<string name="menu_form_filling_settings">Form filling</string>
<string name="menu_db_settings">Database settings</string>
<string name="menu_delete">Delete</string>
<string name="menu_donate">Donate</string>
<string name="menu_edit">Edit</string>
<string name="menu_copy">Copy</string>
<string name="menu_move">Move</string>
<string name="menu_paste">Paste</string>
<string name="menu_delete">Delete</string>
<string name="menu_hide_password">Hide Pass</string>
<string name="menu_lock">Lock Database</string>
<string name="menu_open">Open</string>
@@ -131,6 +134,7 @@
<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="where">Where ?</string>
<string name="minus">Minus</string>
<string name="never">Never</string>
<string name="no_results">No search results</string>

View File

@@ -29,6 +29,7 @@
<item name="android:textColorHintInverse">@color/blue_lighter</item>
<item name="android:windowBackground">@color/background_light</item>
<item name="toolbarAppearance">@style/KeepassDXStyle.Toolbar.Blue</item>
<item name="actionModeStyle">@style/KeepassDXStyle.ActionMode.Blue</item>
</style>
<!-- Toolbar Style Blue -->
<style name="KeepassDXStyle.Toolbar.Blue" parent="KeepassDXStyle.Blue">
@@ -39,6 +40,10 @@
<item name="android:editTextColor">@color/colorTextInverse</item>
<item name="android:textColorHint">@color/blue_lighter</item>
</style>
<!-- Contextual Action Bar Blue -->
<style name="KeepassDXStyle.ActionMode.Blue" parent="@style/Widget.AppCompat.ActionMode">
<item name="background">@color/blue_dark</item>
</style>
<!-- File Picker Theme -->
<style name="KeepassDXStyle.FilePickerStyle.Blue" parent="KeepassDXStyle.FilePickerStyle">
<item name="colorPrimary">@color/blue</item>

View File

@@ -21,7 +21,7 @@
<!-- Dark Style -->
<style name="KeepassDXStyle.Dark" parent="KeepassDXStyle.Night.v21" >
<item name="colorPrimary">#212121</item>
<item name="colorPrimaryDark">#0e0e0e</item>
<item name="colorPrimaryDark">@color/dark</item>
<item name="colorAccent">#26a69a</item>
<item name="colorAccentCompat">#26a69a</item>
<item name="colorControlActivated">#80cbc4</item>
@@ -31,6 +31,7 @@
<item name="toolbarAppearance">@style/KeepassDXStyle.Toolbar.Dark</item>
<item name="android:alertDialogTheme">@style/KeepassDXStyle.Dark.Dialog</item>
<item name="alertDialogTheme">@style/KeepassDXStyle.Dark.Dialog</item>
<item name="actionModeStyle">@style/KeepassDXStyle.ActionMode.Dark</item>
</style>
<!-- Toolbar Style Dark -->
<style name="KeepassDXStyle.Toolbar.Dark" parent="KeepassDXStyle.Dark">
@@ -38,6 +39,10 @@
<item name="android:textColorPrimary">@color/colorTextInverse</item>
<item name="android:textColorSecondary">@color/colorTextSecondary</item>
</style>
<!-- Contextual Action Bar Dark -->
<style name="KeepassDXStyle.ActionMode.Dark" parent="@style/Widget.AppCompat.ActionMode">
<item name="background">@color/dark</item>
</style>
<!-- Dialog -->
<style name="KeepassDXStyle.Dark.Dialog" parent="KeepassDXStyle.Night.Dialog">
<item name="colorAccent">#fefefe</item>

View File

@@ -31,6 +31,7 @@
<item name="android:textColorHintInverse">@color/purple_lighter</item>
<item name="android:windowBackground">@color/background_purple</item>
<item name="toolbarAppearance">@style/KeepassDXStyle.Toolbar.Purple</item>
<item name="actionModeStyle">@style/KeepassDXStyle.ActionMode.Purple</item>
<item name="iconPreferenceColor">@color/purple_light</item>
</style>
<!-- Toolbar Style Purple -->
@@ -41,6 +42,10 @@
<item name="android:editTextColor">@color/colorTextInverse</item>
<item name="android:textColorHint">@color/purple_lighter</item>
</style>
<!-- Contextual Action Bar Purple -->
<style name="KeepassDXStyle.ActionMode.Purple" parent="@style/Widget.AppCompat.ActionMode">
<item name="background">@color/purple_dark</item>
</style>
<!-- File Picker Theme -->
<style name="KeepassDXStyle.FilePickerStyle.Purple" parent="KeepassDXStyle.FilePickerStyle">
<item name="colorPrimary">@color/purple</item>

View File

@@ -29,6 +29,7 @@
<item name="android:textColorHintInverse">@color/red_lighter</item>
<item name="android:windowBackground">@color/background_night</item>
<item name="toolbarAppearance">@style/KeepassDXStyle.Toolbar.Red</item>
<item name="actionModeStyle">@style/KeepassDXStyle.ActionMode.Red</item>
</style>
<!-- Toolbar Style Red -->
<style name="KeepassDXStyle.Toolbar.Red" parent="KeepassDXStyle.Red">
@@ -39,6 +40,10 @@
<item name="android:editTextColor">@color/colorTextInverse</item>
<item name="android:textColorHint">@color/red_lighter</item>
</style>
<!-- Contextual Action Bar Red -->
<style name="KeepassDXStyle.ActionMode.Red" parent="@style/Widget.AppCompat.ActionMode">
<item name="background">@color/red_dark</item>
</style>
<!-- File Picker Theme -->
<style name="KeepassDXStyle.FilePickerStyle.Red" parent="KeepassDXStyle.FilePickerStyle">
<item name="colorPrimary">@color/red</item>

View File

@@ -73,6 +73,7 @@
<!-- Toolbar -->
<item name="toolbarAppearance">@style/KeepassDXStyle.Toolbar.Light</item>
<item name="toolbarPopupAppearance">@style/KeepassDXStyle.Light.Toolbar.Popup</item>
<item name="actionModeStyle">@style/KeepassDXStyle.ActionMode</item>
<!-- White FAB -->
<item name="whiteFab">@style/KeepassDXStyle.Fab.White</item>
@@ -127,6 +128,7 @@
<!-- Toolbar -->
<item name="toolbarAppearance">@style/KeepassDXStyle.Toolbar.Night</item>
<item name="toolbarPopupAppearance">@style/KeepassDXStyle.Night.Toolbar.Popup</item>
<item name="actionModeStyle">@style/KeepassDXStyle.ActionMode</item>
<!-- White FAB -->
<item name="whiteFab">@style/KeepassDXStyle.Fab.White</item>
@@ -172,6 +174,11 @@
<item name="android:textColorHint">@color/green_lighter</item>
</style>
<!-- Contextual Action Bar -->
<style name="KeepassDXStyle.ActionMode" parent="@style/Widget.AppCompat.ActionMode">
<item name="background">@color/green_dark</item>
</style>
<!-- Dialog -->
<style name="KeepassDXStyle.Night.Dialog" parent="Theme.AppCompat.Dialog.Alert">
<item name="colorAccent">@color/orange</item>