diff --git a/src/KeePass.sln b/src/KeePass.sln
index 9ec7b121..9c7c80a1 100644
--- a/src/KeePass.sln
+++ b/src/KeePass.sln
@@ -95,6 +95,7 @@ Global
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|x64.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Any CPU.Deploy.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU
diff --git a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj
index b9c8faa5..c087ccfd 100644
--- a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj
+++ b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj
@@ -56,8 +56,9 @@
+
-
+
diff --git a/src/Kp2aBusinessLogic/UiStringKey.cs b/src/Kp2aBusinessLogic/UiStringKey.cs
index 3bc22d20..32921742 100644
--- a/src/Kp2aBusinessLogic/UiStringKey.cs
+++ b/src/Kp2aBusinessLogic/UiStringKey.cs
@@ -57,6 +57,8 @@ namespace keepass2android
CopyFileRequiredForEditing,
DuplicateUuidsError,
DuplicateUuidsErrorAdditional,
- KdbBetaWarning
+ KdbBetaWarning,
+ DeletingItems,
+ AskDeletePermanentlyItems
}
}
diff --git a/src/Kp2aBusinessLogic/database/edit/DeleteEntry.cs b/src/Kp2aBusinessLogic/database/edit/DeleteEntry.cs
index 4fcd4139..4280697c 100644
--- a/src/Kp2aBusinessLogic/database/edit/DeleteEntry.cs
+++ b/src/Kp2aBusinessLogic/database/edit/DeleteEntry.cs
@@ -16,16 +16,19 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
+using System.Collections.Generic;
using Android.Content;
using KeePassLib;
+using KeePassLib.Interfaces;
namespace keepass2android
{
public class DeleteEntry : DeleteRunnable {
private readonly PwEntry _entry;
+ private UiStringKey _statusMessage;
- public DeleteEntry(Context ctx, IKp2aApp app, PwEntry entry, OnFinish finish):base(finish, app) {
+ public DeleteEntry(Context ctx, IKp2aApp app, PwEntry entry, OnFinish finish):base(finish, app) {
Ctx = ctx;
Db = app.GetDb();
_entry = entry;
@@ -48,76 +51,15 @@ namespace keepass2android
}
}
- public override void Run()
- {
- StatusLogger.UpdateMessage(UiStringKey.DeletingEntry);
- PwDatabase pd = Db.KpDatabase;
+ protected override void PerformDelete(List touchedGroups, List permanentlyDeletedGroups)
+ {
+ DoDeleteEntry(_entry, touchedGroups);
+ }
- PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
-
- bool bUpdateGroupList = false;
- DateTime dtNow = DateTime.Now;
- PwEntry pe = _entry;
- PwGroup pgParent = pe.ParentGroup;
- if(pgParent != null)
- {
- pgParent.Entries.Remove(pe);
- //TODO check if RecycleBin is deleted
- //TODO no recycle bin in KDB
-
- if ((DeletePermanently) || (!CanRecycle))
- {
- PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow);
- pd.DeletedObjects.Add(pdo);
-
- _onFinishToRun = new ActionOnFinish((success, message) =>
- {
- if (success)
- {
- // Mark parent dirty
- Db.Dirty.Add(pgParent);
- }
- else
- {
- // Let's not bother recovering from a failure to save a deleted entry. It is too much work.
- App.LockDatabase(false);
- }
- }, OnFinishToRun);
- }
- else // Recycle
- {
- EnsureRecycleBinExists(ref pgRecycleBin, ref bUpdateGroupList);
-
- pgRecycleBin.AddEntry(pe, true, true);
- pe.Touch(false);
-
- _onFinishToRun = new ActionOnFinish( (success, message) =>
- {
- if ( success ) {
- // Mark previous parent dirty
- Db.Dirty.Add(pgParent);
- // Mark new parent dirty
- Db.Dirty.Add(pgRecycleBin);
- // mark root dirty if recycle bin was created
- if (bUpdateGroupList)
- Db.Dirty.Add(Db.Root);
- } else {
- // Let's not bother recovering from a failure to save a deleted entry. It is too much work.
- App.LockDatabase(false);
- }
-
- }, OnFinishToRun);
- }
- }
-
- // Commit database
- SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, false);
- save.SetStatusLogger(StatusLogger);
- save.Run();
-
-
- }
-
+ public override UiStringKey StatusMessage
+ {
+ get { return UiStringKey.DeletingEntry; }
+ }
}
}
diff --git a/src/Kp2aBusinessLogic/database/edit/DeleteGroup.cs b/src/Kp2aBusinessLogic/database/edit/DeleteGroup.cs
index 6341eb91..61b1d10a 100644
--- a/src/Kp2aBusinessLogic/database/edit/DeleteGroup.cs
+++ b/src/Kp2aBusinessLogic/database/edit/DeleteGroup.cs
@@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
+using System.Collections.Generic;
using Android.Content;
using KeePassLib;
@@ -68,96 +69,15 @@ namespace keepass2android
}
}
-
- public override void Run() {
- StatusLogger.UpdateMessage(UiStringKey.DeletingGroup);
- //from KP Desktop
- PwGroup pg = _group;
- PwGroup pgParent = pg.ParentGroup;
- if(pgParent == null) return; // Can't remove virtual or root group
-
- PwDatabase pd = Db.KpDatabase;
- PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
-
- pgParent.Groups.Remove(pg);
-
- if ((DeletePermanently) || (!CanRecycle))
- {
- pg.DeleteAllObjects(pd);
-
- PwDeletedObject pdo = new PwDeletedObject(pg.Uuid, DateTime.Now);
- pd.DeletedObjects.Add(pdo);
- _onFinishToRun = new AfterDeletePermanently(OnFinishToRun, App, _group);
- }
- else // Recycle
- {
- bool groupListUpdateRequired = false;
- EnsureRecycleBinExists(ref pgRecycleBin, ref groupListUpdateRequired);
-
- pgRecycleBin.AddGroup(pg, true, true);
- pg.Touch(false);
- _onFinishToRun = new ActionOnFinish((success, message) =>
- {
- if ( success ) {
- // Mark new parent (Recycle bin) dirty
- PwGroup parent = _group.ParentGroup;
- if ( parent != null ) {
- Db.Dirty.Add(parent);
- }
- //Mark old parent dirty:
- Db.Dirty.Add(pgParent);
+ protected override void PerformDelete(List touchedGroups, List permanentlyDeletedGroups)
+ {
+ DoDeleteGroup(_group, touchedGroups, permanentlyDeletedGroups);
+ }
- // mark root dirty if recycle bin was created
- if (groupListUpdateRequired)
- Db.Dirty.Add(Db.Root);
- } else {
- // Let's not bother recovering from a failure to save a deleted group. It is too much work.
- App.LockDatabase(false);
- }
- }, OnFinishToRun);
- }
-
- // Save
- SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, DontSave);
- save.SetStatusLogger(StatusLogger);
- save.Run();
-
- }
-
-
- private class AfterDeletePermanently : OnFinish {
- readonly IKp2aApp _app;
-
- readonly PwGroup _group;
-
- public AfterDeletePermanently(OnFinish finish, IKp2aApp app, PwGroup group):base(finish) {
- _app = app;
- _group = group;
- }
-
- public override void Run() {
- if ( Success ) {
- // Remove from group global
- _app.GetDb().Groups.Remove(_group.Uuid);
-
- // Remove group from the dirty global (if it is present), not a big deal if this fails (doesn't throw)
- _app.GetDb().Dirty.Remove(_group);
-
- // Mark parent dirty
- PwGroup parent = _group.ParentGroup;
- if ( parent != null ) {
- _app.GetDb().Dirty.Add(parent);
- }
- } else {
- // Let's not bother recovering from a failure to save a deleted group. It is too much work.
- _app.LockDatabase(false);
- }
-
- base.Run();
-
- }
-
- }
+ public override UiStringKey StatusMessage
+ {
+ get { return UiStringKey.DeletingGroup; }
+ }
}
}
diff --git a/src/Kp2aBusinessLogic/database/edit/DeleteRunnable.cs b/src/Kp2aBusinessLogic/database/edit/DeleteRunnable.cs
index df2c3f7e..e8fa4147 100644
--- a/src/Kp2aBusinessLogic/database/edit/DeleteRunnable.cs
+++ b/src/Kp2aBusinessLogic/database/edit/DeleteRunnable.cs
@@ -1,3 +1,5 @@
+using System;
+using System.Collections.Generic;
using Android.Content;
using KeePassLib;
@@ -5,12 +7,13 @@ namespace keepass2android
{
public abstract class DeleteRunnable : RunnableOnFinish
{
- protected DeleteRunnable(OnFinish finish, IKp2aApp app):base(finish)
+ protected DeleteRunnable(OnFinish finish, IKp2aApp app)
+ : base(finish)
{
- App = app;
+ App = app;
}
- protected IKp2aApp App;
+ protected IKp2aApp App;
protected Database Db;
@@ -22,9 +25,9 @@ namespace keepass2android
Db = db;
}
-
+
private bool _deletePermanently = true;
-
+
public bool DeletePermanently
{
get
@@ -44,52 +47,61 @@ namespace keepass2android
protected bool CanRecycleGroup(PwGroup pgParent)
{
- bool bShiftPressed = false;
PwDatabase pd = Db.KpDatabase;
PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
bool bPermanent = false;
if (pgParent != null)
{
if (pd.RecycleBinEnabled == false)
+ {
+ Android.Util.Log.Debug("KP2A", "CanRecycle? No, RecycleBinIsNotEnabled");
bPermanent = true;
- else if (bShiftPressed)
- bPermanent = true;
+ }
+
else if (pgRecycleBin == null)
{
} // Recycle
else if (pgParent == pgRecycleBin)
+ {
+ Android.Util.Log.Debug("KP2A", "CanRecycle? No, Can't recycle RecycleBin");
bPermanent = true;
+ }
+
else if (pgParent.IsContainedIn(pgRecycleBin))
+ {
+ Android.Util.Log.Debug("KP2A", "CanRecycle? No, "+pgParent.Name+" is in RecycleBin");
bPermanent = true;
+ }
+
}
return !bPermanent;
}
-
+
protected void EnsureRecycleBinExists(ref PwGroup pgRecycleBin,
- ref bool bGroupListUpdateRequired)
+ ref bool bGroupListUpdateRequired)
{
if ((Db == null) || (Db.KpDatabase == null)) { return; }
-
- if(pgRecycleBin == Db.KpDatabase.RootGroup)
+
+ if (pgRecycleBin == Db.KpDatabase.RootGroup)
{
pgRecycleBin = null;
}
-
- if(pgRecycleBin == null)
+
+ if (pgRecycleBin == null)
{
pgRecycleBin = new PwGroup(true, true, App.GetResourceString(UiStringKey.RecycleBin),
- PwIcon.TrashBin)
+ PwIcon.TrashBin)
{
- EnableAutoType = false,
- EnableSearching = false,
+ EnableAutoType = false,
+ EnableSearching = false,
IsExpanded = false
};
Db.KpDatabase.RootGroup.AddGroup(pgRecycleBin, true);
Db.Groups[pgRecycleBin.Uuid] = pgRecycleBin;
Db.KpDatabase.RecycleBinUuid = pgRecycleBin.Uuid;
-
+
bGroupListUpdateRequired = true;
}
else { System.Diagnostics.Debug.Assert(pgRecycleBin.Uuid.Equals(Db.KpDatabase.RecycleBinUuid)); }
@@ -99,36 +111,155 @@ namespace keepass2android
{
get;
}
-
+
public void Start()
{
if (CanRecycle)
{
- App.AskYesNoCancel(UiStringKey.AskDeletePermanently_title,
- QuestionsResourceId,
- (dlgSender, dlgEvt) =>
- {
- DeletePermanently = true;
- ProgressTask pt = new ProgressTask(App, Ctx, this);
- pt.Run();
- },
- (dlgSender, dlgEvt) => {
- DeletePermanently = false;
- ProgressTask pt = new ProgressTask(App, Ctx, this);
- pt.Run();
- },
- (dlgSender, dlgEvt) => {},
- Ctx);
+ App.AskYesNoCancel(UiStringKey.AskDeletePermanently_title,
+ QuestionsResourceId,
+ (dlgSender, dlgEvt) =>
+ {
+ DeletePermanently = true;
+ ProgressTask pt = new ProgressTask(App, Ctx, this);
+ pt.Run();
+ },
+ (dlgSender, dlgEvt) =>
+ {
+ DeletePermanently = false;
+ ProgressTask pt = new ProgressTask(App, Ctx, this);
+ pt.Run();
+ },
+ (dlgSender, dlgEvt) => { },
+ Ctx);
-
- } else
+
+ }
+ else
{
ProgressTask pt = new ProgressTask(App, Ctx, this);
pt.Run();
}
}
+ protected void DoDeleteEntry(PwEntry pe, List touchedGroups)
+ {
+ PwDatabase pd = Db.KpDatabase;
+
+ PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
+
+ bool bUpdateGroupList = false;
+ DateTime dtNow = DateTime.Now;
+
+ PwGroup pgParent = pe.ParentGroup;
+ if (pgParent != null)
+ {
+ pgParent.Entries.Remove(pe);
+ //TODO check if RecycleBin is deleted
+ //TODO no recycle bin in KDB
+
+ if ((DeletePermanently) || (!CanRecycle))
+ {
+ PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow);
+ pd.DeletedObjects.Add(pdo);
+ touchedGroups.Add(pgParent);
+ }
+ else // Recycle
+ {
+ EnsureRecycleBinExists(ref pgRecycleBin, ref bUpdateGroupList);
+
+ pgRecycleBin.AddEntry(pe, true, true);
+ pe.Touch(false);
+
+ touchedGroups.Add(pgParent);
+ // Mark new parent dirty
+ touchedGroups.Add(pgRecycleBin);
+ // mark root dirty if recycle bin was created
+ touchedGroups.Add(Db.Root);
+ }
+ }
+ }
+
+
+ public override void Run()
+ {
+ StatusLogger.UpdateMessage(StatusMessage);
+
+ List touchedGroups = new List();
+ List permanentlyDeletedGroups = new List();
+ Android.Util.Log.Debug("KP2A", "Calling PerformDelete..");
+ PerformDelete(touchedGroups, permanentlyDeletedGroups);
+
+ _onFinishToRun = new ActionOnFinish((success, message) =>
+ {
+ if (success)
+ {
+ foreach (var g in touchedGroups)
+ Db.Dirty.Add(g);
+ foreach (var g in permanentlyDeletedGroups)
+ {
+ //remove groups from global lists if present there
+ Db.Dirty.Remove(g);
+ Db.Groups.Remove(g.Uuid);
+ }
+
+ }
+ else
+ {
+ // Let's not bother recovering from a failure to save. It is too much work.
+ App.LockDatabase(false);
+ }
+ }, OnFinishToRun);
+
+ // Commit database
+ SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, false);
+ save.SetStatusLogger(StatusLogger);
+ save.Run();
+
+
+ }
+
+ protected abstract void PerformDelete(List touchedGroups, List permanentlyDeletedGroups);
+
+ public abstract UiStringKey StatusMessage { get; }
+
+ protected bool DoDeleteGroup(PwGroup pg, List touchedGroups, List permanentlyDeletedGroups)
+ {
+ PwGroup pgParent = pg.ParentGroup;
+ if (pgParent == null) return false;
+
+ PwDatabase pd = Db.KpDatabase;
+ PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
+
+ pgParent.Groups.Remove(pg);
+ touchedGroups.Add(pgParent);
+ if ((DeletePermanently) || (!CanRecycle))
+ {
+ pg.DeleteAllObjects(pd);
+
+ PwDeletedObject pdo = new PwDeletedObject(pg.Uuid, DateTime.Now);
+ pd.DeletedObjects.Add(pdo);
+
+
+ permanentlyDeletedGroups.Add(pg);
+
+ }
+ else // Recycle
+ {
+ bool groupListUpdateRequired = false;
+ EnsureRecycleBinExists(ref pgRecycleBin, ref groupListUpdateRequired);
+
+ pgRecycleBin.AddGroup(pg, true, true);
+ pg.Touch(false);
+ // Mark new parent (Recycle bin) touched
+ touchedGroups.Add(pg.ParentGroup);
+ // mark root touched if recycle bin was created
+ if (groupListUpdateRequired)
+ touchedGroups.Add(Db.Root);
+ }
+ return true;
+ }
}
}
diff --git a/src/Kp2aBusinessLogic/database/edit/MoveElement.cs b/src/Kp2aBusinessLogic/database/edit/MoveElement.cs
deleted file mode 100644
index 3b6bcfe0..00000000
--- a/src/Kp2aBusinessLogic/database/edit/MoveElement.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Text.RegularExpressions;
-using Android.Content;
-using KeePassLib;
-using KeePassLib.Interfaces;
-
-namespace keepass2android.database.edit
-{
- public class MoveElement: RunnableOnFinish
- {
- private readonly IStructureItem _elementToMove;
- private readonly PwGroup _targetGroup;
- private readonly Context _ctx;
- private readonly IKp2aApp _app;
-
- public MoveElement(IStructureItem elementToMove, PwGroup targetGroup, Context ctx, IKp2aApp app, OnFinish finish) : base(finish)
- {
- _elementToMove = elementToMove;
- _targetGroup = targetGroup;
- _ctx = ctx;
- _app = app;
- }
-
- public override void Run()
- {
-
- _app.GetDb().Dirty.Add(_elementToMove.ParentGroup);
-
- PwGroup pgParent = _elementToMove.ParentGroup;
- if (pgParent != _targetGroup)
- {
- if (pgParent != null) // Remove from parent
- {
- PwEntry entry = _elementToMove as PwEntry;
- if (entry != null)
- {
- pgParent.Entries.Remove(entry);
- _targetGroup.AddEntry(entry, true, true);
- }
- else
- {
- PwGroup group = (PwGroup)_elementToMove;
- if ((_targetGroup == group) || (_targetGroup.IsContainedIn(group)))
- {
- Finish(false, _app.GetResourceString(UiStringKey.CannotMoveGroupHere));
- return;
- }
- pgParent.Groups.Remove(group);
- _targetGroup.AddGroup(group, true, true);
- }
- }
- }
-
- _onFinishToRun = new ActionOnFinish((success, message) =>
- {
- if (!success)
- { // Let's not bother recovering from a failure.
- _app.LockDatabase(false);
- }
- }, OnFinishToRun);
-
- // Save
- SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, false);
- save.SetStatusLogger(StatusLogger);
- save.Run();
- }
- }
-}
diff --git a/src/keepass2android/EntryEditActivity.cs b/src/keepass2android/EntryEditActivity.cs
index 412a5d2d..df9499ed 100644
--- a/src/keepass2android/EntryEditActivity.cs
+++ b/src/keepass2android/EntryEditActivity.cs
@@ -951,7 +951,9 @@ namespace keepass2android
}
else
{
- FindViewById(Resource.Id.entry_tags_label).Visibility = ViewStates.Gone;
+ var view = FindViewById(Resource.Id.entry_tags_label);
+ if (view != null)
+ view.Visibility = ViewStates.Gone;
FindViewById(Resource.Id.entry_tags).Visibility = ViewStates.Gone;
}
diff --git a/src/keepass2android/GroupActivity.cs b/src/keepass2android/GroupActivity.cs
index ed6db2bb..051cf4d2 100644
--- a/src/keepass2android/GroupActivity.cs
+++ b/src/keepass2android/GroupActivity.cs
@@ -29,7 +29,8 @@ using Android.Content.PM;
namespace keepass2android
{
- [Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_ActionBar")]
+ [Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_ActionBar")]
+ [MetaData("android.app.searchable", Resource = AppNames.Searchable)]
[MetaData("android.app.default_searchable",Value="keepass2android.search.SearchResults")]
public class GroupActivity : GroupBaseActivity {
@@ -83,8 +84,12 @@ namespace keepass2android
get { return App.Kp2a.GetDb().CanWrite && ((this.Group.ParentGroup != null) || App.Kp2a.GetDb().DatabaseFormat.CanHaveEntriesInRootGroup); }
}
+ public override bool OnCreateOptionsMenu(IMenu menu)
+ {
+ return base.OnCreateOptionsMenu(menu);
+ }
- protected override void OnCreate (Bundle savedInstanceState)
+ protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
diff --git a/src/keepass2android/GroupBaseActivity.cs b/src/keepass2android/GroupBaseActivity.cs
index 16113561..01e26d61 100644
--- a/src/keepass2android/GroupBaseActivity.cs
+++ b/src/keepass2android/GroupBaseActivity.cs
@@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Android.App;
@@ -182,6 +183,7 @@ namespace keepass2android
private String strCachedGroupUuid = null;
+
public String UuidGroup {
get {
if (strCachedGroupUuid == null) {
@@ -222,6 +224,11 @@ namespace keepass2android
get { return (BaseAdapter) FragmentManager.FindFragmentById(Resource.Id.list_fragment).ListAdapter; }
}
+ public virtual bool IsSearchResult
+ {
+ get { return false; }
+ }
+
/*TODO
* protected override void OnListItemClick(ListView l, View v, int position, long id) {
base.OnListItemClick(l, v, position, id);
@@ -234,7 +241,9 @@ namespace keepass2android
*/
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
-
+
+ Android.Util.Log.Debug("KP2A", "Creating GBA");
+
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
// Likely the app has been killed exit the activity
@@ -266,8 +275,8 @@ namespace keepass2android
- FindViewById(Resource.Id.cancel_insert_element).Click += (sender, args) => StopMovingElement();
- FindViewById(Resource.Id.insert_element).Click += (sender, args) => InsertElement();
+ FindViewById(Resource.Id.cancel_insert_element).Click += (sender, args) => StopMovingElements();
+ FindViewById(Resource.Id.insert_element).Click += (sender, args) => InsertElements();
SetResult(KeePass.ExitNormal);
@@ -275,13 +284,15 @@ namespace keepass2android
}
- private void InsertElement()
+ private void InsertElements()
{
- MoveElementTask moveElementTask = (MoveElementTask)AppTask;
- IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(moveElementTask.Uuid, true, null);
+ MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask;
+ IEnumerable elementsToMove =
+ moveElementsTask.Uuids.Select(uuid => App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(uuid, true, null));
+
- var moveElement = new MoveElement(elementToMove, Group, this, App.Kp2a, new ActionOnFinish((success, message) => { StopMovingElement(); if (!String.IsNullOrEmpty(message)) Toast.MakeText(this, message, ToastLength.Long).Show();}));
+ var moveElement = new MoveElements(elementsToMove.ToList(), Group, this, App.Kp2a, new ActionOnFinish((success, message) => { StopMovingElements(); if (!String.IsNullOrEmpty(message)) Toast.MakeText(this, message, ToastLength.Long).Show();}));
var progressTask = new ProgressTask(App.Kp2a, this, moveElement);
progressTask.Run();
@@ -381,34 +392,34 @@ namespace keepass2android
return true;
}
}
+ /*
+ public override bool OnCreateOptionsMenu(IMenu menu) {
+ return base.OnCreateOptionsMenu(menu);
- public override bool OnCreateOptionsMenu(IMenu menu) {
- base.OnCreateOptionsMenu(menu);
-
- MenuInflater inflater = MenuInflater;
- inflater.Inflate(Resource.Menu.group, menu);
- var searchManager = (SearchManager) GetSystemService(SearchService);
- IMenuItem searchItem = menu.FindItem(Resource.Id.menu_search);
- var view = MenuItemCompat.GetActionView(searchItem);
- var searchView = view.JavaCast();
+ MenuInflater inflater = MenuInflater;
+ inflater.Inflate(Resource.Menu.group, menu);
+ var searchManager = (SearchManager) GetSystemService(SearchService);
+ IMenuItem searchItem = menu.FindItem(Resource.Id.menu_search);
+ var view = MenuItemCompat.GetActionView(searchItem);
+ var searchView = view.JavaCast();
- searchView.SetSearchableInfo(searchManager.GetSearchableInfo(ComponentName));
- searchView.SetOnSuggestionListener(new SuggestionListener(searchView.SuggestionsAdapter, this, searchItem));
- searchView.SetOnQueryTextListener(new OnQueryTextListener(this));
+ searchView.SetSearchableInfo(searchManager.GetSearchableInfo(ComponentName));
+ searchView.SetOnSuggestionListener(new SuggestionListener(searchView.SuggestionsAdapter, this, searchItem));
+ searchView.SetOnQueryTextListener(new OnQueryTextListener(this));
- var item = menu.FindItem(Resource.Id.menu_sync);
- if (item != null)
- {
- if (App.Kp2a.GetDb().Ioc.IsLocalFile())
- item.SetVisible(false);
- else
- item.SetVisible(true);
+ var item = menu.FindItem(Resource.Id.menu_sync);
+ if (item != null)
+ {
+ if (App.Kp2a.GetDb().Ioc.IsLocalFile())
+ item.SetVisible(false);
+ else
+ item.SetVisible(true);
+ }
+ //return true;
}
-
- return true;
- }
-
-
+ */
+
+
public override bool OnPrepareOptionsMenu(IMenu menu) {
if ( ! base.OnPrepareOptionsMenu(menu) ) {
@@ -613,10 +624,10 @@ namespace keepass2android
public bool IsBeingMoved(PwUuid uuid)
{
- MoveElementTask moveElementTask = AppTask as MoveElementTask;
- if (moveElementTask != null)
+ MoveElementsTask moveElementsTask = AppTask as MoveElementsTask;
+ if (moveElementsTask != null)
{
- if (moveElementTask.Uuid.Equals(uuid))
+ if (moveElementsTask.Uuids.Any(uuidMoved => uuidMoved.Equals(uuid)))
return true;
}
return false;
@@ -629,16 +640,16 @@ namespace keepass2android
}
- public void StartMovingElement()
+ public void StartMovingElements()
{
- ShowInsertElementButtons();
+ ShowInsertElementsButtons();
//TODO Required? GroupView.ListView.InvalidateViews();
BaseAdapter adapter = (BaseAdapter)ListAdapter;
adapter.NotifyDataSetChanged();
}
- public void ShowInsertElementButtons()
+ public void ShowInsertElementsButtons()
{
FindViewById(Resource.Id.fabCancelAddNew).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewGroup).Visibility = ViewStates.Gone;
@@ -649,14 +660,17 @@ namespace keepass2android
FindViewById(Resource.Id.divider2).Visibility = ViewStates.Visible;
}
- public void StopMovingElement()
+ public void StopMovingElements()
{
try
{
- MoveElementTask moveElementTask = (MoveElementTask)AppTask;
- IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(moveElementTask.Uuid, true, null);
- if (elementToMove.ParentGroup != Group)
- App.Kp2a.GetDb().Dirty.Add(elementToMove.ParentGroup);
+ MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask;
+ foreach (var uuid in moveElementsTask.Uuids)
+ {
+ IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(uuid, true, null);
+ if (elementToMove.ParentGroup != Group)
+ App.Kp2a.GetDb().Dirty.Add(elementToMove.ParentGroup);
+ }
}
catch (Exception e)
{
@@ -680,7 +694,9 @@ namespace keepass2android
public class GroupListFragment : ListFragment, AbsListView.IMultiChoiceModeListener
{
- public override void OnActivityCreated(Bundle savedInstanceState)
+ private ActionMode _mode;
+
+ public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
if (App.Kp2a.GetDb().CanWrite)
@@ -709,29 +725,53 @@ namespace keepass2android
public bool OnActionItemClicked(ActionMode mode, IMenuItem item)
{
+ var listView = FragmentManager.FindFragmentById(Resource.Id.list_fragment).ListView;
+ var checkedItemPositions = listView.CheckedItemPositions;
+
+ List checkedItems = new List();
+ for (int i = 0; i < checkedItemPositions.Size(); i++)
+ {
+ if (checkedItemPositions.ValueAt(i))
+ {
+ //TODO make sure position is also correct when scrolling (more items in adapter than on screen)
+ checkedItems.Add(((PwGroupListAdapter) ListAdapter).GetItemAtPosition(checkedItemPositions.KeyAt(i)));
+ }
+ }
+
+ //shouldn't happen, just in case...
+ if (!checkedItems.Any())
+ {
+ return false;
+ }
+
switch (item.ItemId)
{
case Resource.Id.menu_delete:
- /*Handler handler = new Handler();
- DeleteEntry task = new DeleteEntry(Activity, App.Kp2a, _entry,
- new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)));
- task.Start();*/
- Toast.MakeText(((GroupBaseActivity) Activity), "todo delete", ToastLength.Long).Show();
- return true;
+ Handler handler = new Handler();
+ DeleteMultipleItems task = new DeleteMultipleItems((GroupBaseActivity)Activity, App.Kp2a.GetDb(), checkedItems,
+ new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a);
+ task.Start();
+ break;
case Resource.Id.menu_move:
- /*NavigateToFolderAndLaunchMoveElementTask navMove =
- new NavigateToFolderAndLaunchMoveElementTask(_entry.ParentGroup, _entry.Uuid, _isSearchResult);
- ((GroupBaseActivity)Activity).StartTask(navMove);*/
- Toast.MakeText(((GroupBaseActivity)Activity), "todo move", ToastLength.Long).Show();
- return true;
- /*TODO for search results case Resource.Id.menu_navigate:
- NavigateToFolder navNavigate = new NavigateToFolder(_entry.ParentGroup, true);
- ((GroupBaseActivity)Activity).StartTask(navNavigate);
- return true;*/
+ var navMove = new NavigateToFolderAndLaunchMoveElementTask(checkedItems.First().ParentGroup, checkedItems.Select(i => i.Uuid).ToList(), ((GroupBaseActivity)Activity).IsSearchResult);
+ ((GroupBaseActivity)Activity).StartTask(navMove);
+ break;
+ /*TODO for search results case Resource.Id.menu_navigate:
+ NavigateToFolder navNavigate = new NavigateToFolder(_entry.ParentGroup, true);
+ ((GroupBaseActivity)Activity).StartTask(navNavigate);
+ break;*/
+ default:
+ return false;
+
}
- return false;
+ listView.ClearChoices();
+ ((BaseAdapter)ListAdapter).NotifyDataSetChanged();
+ if (_mode != null)
+ mode.Finish();
+
+ return true;
}
public bool OnCreateActionMode(ActionMode mode, IMenu menu)
@@ -741,7 +781,7 @@ namespace keepass2android
//mode.Title = "Select Items";
Android.Util.Log.Debug("KP2A", "Create action mode" + mode);
((PwGroupListAdapter)ListView.Adapter).NotifyDataSetChanged();
-
+ _mode = mode;
return true;
}
@@ -750,6 +790,7 @@ namespace keepass2android
Android.Util.Log.Debug("KP2A", "Destroy action mode" + mode);
((PwGroupListAdapter)ListView.Adapter).NotifyDataSetChanged();
+ _mode = null;
}
public bool OnPrepareActionMode(ActionMode mode, IMenu menu)
diff --git a/src/keepass2android/PwGroupListAdapter.cs b/src/keepass2android/PwGroupListAdapter.cs
index ca96c51e..d6a064ba 100644
--- a/src/keepass2android/PwGroupListAdapter.cs
+++ b/src/keepass2android/PwGroupListAdapter.cs
@@ -24,6 +24,7 @@ using Android.Widget;
using Android.Preferences;
using KeePassLib;
using keepass2android.view;
+using KeePassLib.Interfaces;
namespace keepass2android
{
@@ -327,7 +328,18 @@ namespace keepass2android
return ev;
}
-
+
+ public IStructureItem GetItemAtPosition(int keyAt)
+ {
+ if (keyAt < _groupsForViewing.Count)
+ {
+ return _groupsForViewing[keyAt];
+ }
+ else
+ {
+ return _entriesForViewing[keyAt - _groupsForViewing.Count];
+ }
+ }
}
}
diff --git a/src/keepass2android/QuickUnlock.cs b/src/keepass2android/QuickUnlock.cs
index 2aa46a0b..aea34942 100644
--- a/src/keepass2android/QuickUnlock.cs
+++ b/src/keepass2android/QuickUnlock.cs
@@ -68,8 +68,8 @@ namespace keepass2android
if (App.Kp2a.GetDb().KpDatabase.Name != "")
{
- FindViewById(Resource.Id.filename_label).Visibility = ViewStates.Invisible;
- ((TextView) FindViewById(Resource.Id.qu_filename)).Text = App.Kp2a.GetDb().KpDatabase.Name;
+ FindViewById(Resource.Id.filename_label).Visibility = ViewStates.Visible;
+ ((TextView) FindViewById(Resource.Id.filename_label)).Text = App.Kp2a.GetDb().KpDatabase.Name;
}
else
{
@@ -78,11 +78,11 @@ namespace keepass2android
.GetBoolean(GetString(Resource.String.RememberRecentFiles_key),
Resources.GetBoolean(Resource.Boolean.RememberRecentFiles_default)))
{
- ((TextView) FindViewById(Resource.Id.qu_filename)).Text = App.Kp2a.GetFileStorage(_ioc).GetDisplayName(_ioc);
+ ((TextView) FindViewById(Resource.Id.filename_label)).Text = App.Kp2a.GetFileStorage(_ioc).GetDisplayName(_ioc);
}
else
{
- ((TextView) FindViewById(Resource.Id.qu_filename)).Text = "*****";
+ ((TextView) FindViewById(Resource.Id.filename_label)).Text = "*****";
}
}
diff --git a/src/keepass2android/Resources/layout/QuickUnlock.xml b/src/keepass2android/Resources/layout/QuickUnlock.xml
index b54d7d6a..86769f1c 100644
--- a/src/keepass2android/Resources/layout/QuickUnlock.xml
+++ b/src/keepass2android/Resources/layout/QuickUnlock.xml
@@ -77,7 +77,7 @@
android:src="@drawable/toolbar_bg_quickunlock"
app:layout_collapseMode="parallax" />
diff --git a/src/keepass2android/Resources/layout/file_row.xml b/src/keepass2android/Resources/layout/file_row.xml
index 9db6e43e..998154ca 100644
--- a/src/keepass2android/Resources/layout/file_row.xml
+++ b/src/keepass2android/Resources/layout/file_row.xml
@@ -20,5 +20,7 @@
\ No newline at end of file
diff --git a/src/keepass2android/Resources/layout/group.xml b/src/keepass2android/Resources/layout/group.xml
index a096282d..85852ad7 100644
--- a/src/keepass2android/Resources/layout/group.xml
+++ b/src/keepass2android/Resources/layout/group.xml
@@ -26,14 +26,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
- android:text="Insert here"
+ android:text="@string/insert_element_here"
style="@style/BottomBarButton" />
+ android:paddingRight="0dp"
+ android:paddingLeft="0dp" />
\ No newline at end of file
diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml
index 7a86f0e8..29042820 100644
--- a/src/keepass2android/Resources/values/strings.xml
+++ b/src/keepass2android/Resources/values/strings.xml
@@ -9,7 +9,7 @@
Accept
Deny
Add entry
- Add entry
+ Edit entry
Create entry for URL
Add group
Add Group
@@ -348,6 +348,7 @@
Recycle Bin
Do you want to delete this entry permanently? Press No to recycle.
Do you want to delete this group permanently? Press No to recycle.
+ Do you want to delete the selected elements permanently? Press No to recycle.
Delete permanently?
Reload file?
The file which is currently open was changed by another program. Do you want to reload it?
@@ -360,6 +361,7 @@
Adding group…
Deleting entry…
Deleting group…
+ Deleting elements…
Setting password…
Undoing changes…
Transforming master key…
diff --git a/src/keepass2android/ShareUrlResults.cs b/src/keepass2android/ShareUrlResults.cs
index ac824551..5b11b0b2 100644
--- a/src/keepass2android/ShareUrlResults.cs
+++ b/src/keepass2android/ShareUrlResults.cs
@@ -53,9 +53,14 @@ namespace keepass2android
private Database _db;
+
-
- protected override void OnCreate(Bundle savedInstanceState)
+ public override bool IsSearchResult
+ {
+ get { return true; }
+ }
+
+ protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
diff --git a/src/keepass2android/app/AppTask.cs b/src/keepass2android/app/AppTask.cs
index 4b59ccdd..deb8e1e9 100644
--- a/src/keepass2android/app/AppTask.cs
+++ b/src/keepass2android/app/AppTask.cs
@@ -5,6 +5,7 @@ using Android.Content;
using Android.OS;
using Android.Widget;
using System.Collections.Generic;
+using System.Linq;
using KeePassLib;
using KeePassLib.Security;
using KeePassLib.Utility;
@@ -546,13 +547,13 @@ namespace keepass2android
///
- /// User is about to move an entry or group to another group
+ /// User is about to move entries and/or groups to another group
///
- public class MoveElementTask: AppTask
+ public class MoveElementsTask: AppTask
{
- public const String UuidKey = "MoveElement_Uuid";
+ public const String UuidsKey = "MoveElement_Uuids";
- public PwUuid Uuid
+ public IEnumerable Uuids
{
get;
set;
@@ -560,23 +561,33 @@ namespace keepass2android
public override void Setup(Bundle b)
{
- Uuid = new PwUuid(MemUtil.HexStringToByteArray(b.GetString(UuidKey)));
- }
- public override IEnumerable Extras
- {
- get
- {
- yield return new StringExtra { Key = UuidKey, Value = MemUtil.ByteArrayToHexString(Uuid.UuidBytes) };
- }
+ Uuids = b.GetString(UuidsKey).Split(';')
+ .Where(s => !String.IsNullOrEmpty(s))
+ .Select(stringPart => new PwUuid(MemUtil.HexStringToByteArray(stringPart)))
+ .ToList(); //property might be accessed several times, avoid parsing each time
}
+
+ public override IEnumerable Extras
+ {
+ get
+ {
+ yield return new StringExtra
+ {
+ Key = UuidsKey,
+ Value = Uuids.Select(uuid => MemUtil.ByteArrayToHexString(uuid.UuidBytes))
+ .Aggregate((a, b) => a + ";" + b)
+ };
+ }
+ }
+
public override void StartInGroupActivity(GroupBaseActivity groupBaseActivity)
{
base.StartInGroupActivity(groupBaseActivity);
- groupBaseActivity.StartMovingElement();
+ groupBaseActivity.StartMovingElements();
}
public override void SetupGroupBaseActivityButtons(GroupBaseActivity groupBaseActivity)
{
- groupBaseActivity.ShowInsertElementButtons();
+ groupBaseActivity.ShowInsertElementsButtons();
}
}
@@ -902,19 +913,20 @@ namespace keepass2android
public class NavigateToFolderAndLaunchMoveElementTask: NavigateAndLaunchTask {
- public NavigateToFolderAndLaunchMoveElementTask():base(){
+ public NavigateToFolderAndLaunchMoveElementTask()
+ {
}
- public NavigateToFolderAndLaunchMoveElementTask(PwGroup groups, PwUuid uuid, bool toastEnable = false)
- :base(groups, new MoveElementTask() { Uuid = uuid }, toastEnable) {
+ public NavigateToFolderAndLaunchMoveElementTask(PwGroup groups, List uuids, bool toastEnable = false)
+ :base(groups, new MoveElementsTask() { Uuids = uuids }, toastEnable) {
}
public override void Setup(Bundle b) {
base.Setup(b);
- TaskToBeLaunchedAfterNavigation = new MoveElementTask ();
+ TaskToBeLaunchedAfterNavigation = new MoveElementsTask ();
TaskToBeLaunchedAfterNavigation.Setup (b);
}
diff --git a/src/keepass2android/keepass2android.csproj b/src/keepass2android/keepass2android.csproj
index be1bf9ab..61270c2c 100644
--- a/src/keepass2android/keepass2android.csproj
+++ b/src/keepass2android/keepass2android.csproj
@@ -35,17 +35,18 @@
- False
+ True
armeabi,armeabi-v7a,x86
- True
+ False
False
False
1G
-
-
+ Xamarin
+ False
+ True
none
@@ -223,7 +224,9 @@
-
+
+ Designer
+
@@ -540,7 +543,7 @@
KeePassLib2Android
- {53A9CB7F-6553-4BC0-B56B-9410BB2E59AA}
+ {53a9cb7f-6553-4bc0-b56b-9410bb2e59aa}
Kp2aBusinessLogic
@@ -842,7 +845,9 @@
-
+
+ Designer
+
@@ -1317,7 +1322,7 @@
-
+
diff --git a/src/keepass2android/search/SearchResults.cs b/src/keepass2android/search/SearchResults.cs
index 781f0430..0cfbf21a 100644
--- a/src/keepass2android/search/SearchResults.cs
+++ b/src/keepass2android/search/SearchResults.cs
@@ -58,7 +58,8 @@ namespace keepass2android.search
get { return false; }
}
-
+
+
protected override void OnNewIntent(Intent intent)
{
ProcessIntent(intent);
@@ -156,6 +157,11 @@ namespace keepass2android.search
StartActivity(i);
return true;
}
+
+ public override bool IsSearchResult
+ {
+ get { return true; }
+ }
}
}
diff --git a/src/keepass2android/views/PwGroupView.cs b/src/keepass2android/views/PwGroupView.cs
index aae5283b..e5b515d6 100644
--- a/src/keepass2android/views/PwGroupView.cs
+++ b/src/keepass2android/views/PwGroupView.cs
@@ -125,7 +125,7 @@ namespace keepass2android.view
task.Start();
return true;
case MenuMove:
- _groupBaseActivity.StartTask(new MoveElementTask { Uuid = _pwGroup.Uuid });
+ _groupBaseActivity.StartTask(new MoveElementsTask { Uuid = _pwGroup.Uuid });
return true;
case MenuEdit:
_groupBaseActivity.EditGroup(_pwGroup);