diff --git a/src/KeePass.sln b/src/KeePass.sln index 4226fce5..7510e05e 100644 --- a/src/KeePass.sln +++ b/src/KeePass.sln @@ -1,6 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "keepass2android", "keepass2android\keepass2android.csproj", "{A6CF8A86-37C1-4197-80FE-519DE2C842F5}" @@ -35,6 +37,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterKeePlugin", "MasterKe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\ZlibAndroid.csproj", "{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialTest2", "MaterialTest2\MaterialTest2.csproj", "{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -333,6 +337,7 @@ Global {A5F8FB02-00E0-4335-91EF-AEAA2C2F3C48}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU {A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Any CPU.Deploy.0 = Debug|Any CPU {A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU @@ -378,6 +383,30 @@ Global {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Debug|Win32.ActiveCfg = Debug|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Debug|x64.ActiveCfg = Debug|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Release|Any CPU.Build.0 = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Release|Any CPU.Deploy.0 = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Release|Win32.ActiveCfg = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.Release|x64.ActiveCfg = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Any CPU.Deploy.0 = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU + {B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3} diff --git a/src/KeePassLib2Android/PwDefs.cs b/src/KeePassLib2Android/PwDefs.cs index 73f1827a..ec563a39 100644 --- a/src/KeePassLib2Android/PwDefs.cs +++ b/src/KeePassLib2Android/PwDefs.cs @@ -111,7 +111,7 @@ namespace KeePassLib /// /// Default number of master key encryption/transformation rounds (making dictionary attacks harder). /// - public const ulong DefaultKeyEncryptionRounds = 6000; + public const ulong DefaultKeyEncryptionRounds = 500000; /// /// Default identifier string for the title field. Should not contain diff --git a/src/Kp2aBusinessLogic/IDrawableFactory.cs b/src/Kp2aBusinessLogic/IDrawableFactory.cs index fdf5733f..23f50031 100644 --- a/src/Kp2aBusinessLogic/IDrawableFactory.cs +++ b/src/Kp2aBusinessLogic/IDrawableFactory.cs @@ -7,9 +7,9 @@ namespace keepass2android { public interface IDrawableFactory { - void AssignDrawableTo (ImageView iv, Resources res, PwDatabase db, PwIcon icon, PwUuid customIconId); + void AssignDrawableTo (ImageView iv, Resources res, PwDatabase db, PwIcon icon, PwUuid customIconId, bool forGroup); - Drawable GetIconDrawable(Resources res, PwDatabase db, PwIcon icon, PwUuid customIconId); + Drawable GetIconDrawable(Resources res, PwDatabase db, PwIcon icon, PwUuid customIconId, bool forGroup); void Clear(); diff --git a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj index 67b75224..c899a0a6 100644 --- a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj +++ b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj @@ -55,8 +55,9 @@ + - + diff --git a/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs b/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs index 9e94df4a..c5ce53bc 100644 --- a/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs +++ b/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs @@ -21,10 +21,10 @@ namespace keepass2android WriteDemanded = 2 } - protected const int RequestCodeFileStorageSelectionForPrimarySelect = 983713; - private const int RequestCodeFileStorageSelectionForCopyToWritableLocation = 983714; - private const int RequestCodeFileFileBrowseForWritableLocation = 983715; - private const int RequestCodeFileBrowseForOpen = 983716; + protected const int RequestCodeFileStorageSelectionForPrimarySelect = 33713; + private const int RequestCodeFileStorageSelectionForCopyToWritableLocation = 33714; + private const int RequestCodeFileFileBrowseForWritableLocation = 33715; + private const int RequestCodeFileBrowseForOpen = 33716; protected IOConnectionInfo _selectedIoc; 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/DeleteMultipleItems.cs b/src/Kp2aBusinessLogic/database/edit/DeleteMultipleItems.cs new file mode 100644 index 00000000..d70c4a2d --- /dev/null +++ b/src/Kp2aBusinessLogic/database/edit/DeleteMultipleItems.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Linq; +using Android.Content; +using KeePassLib; +using KeePassLib.Interfaces; + +namespace keepass2android +{ + public class DeleteMultipleItems : DeleteRunnable + { + private readonly List _elementsToDelete; + private readonly bool _canRecycle; + + public DeleteMultipleItems(Context ctx, Database db, List elementsToDelete, OnFinish finish, IKp2aApp app) + : base(finish, app) + { + _elementsToDelete = elementsToDelete; + SetMembers(ctx, db); + + //determine once. The property is queried for each delete operation, but might return false + //after one entry/group is deleted (and thus in recycle bin and thus can't be recycled anymore) + _canRecycle = DetermineCanRecycle(); + } + + private bool DetermineCanRecycle() + { + Android.Util.Log.Debug("KP2A", "CanRecycle?"); + if (!App.GetDb().DatabaseFormat.CanRecycle) + { + Android.Util.Log.Debug("KP2A", "CanRecycle? No because of DB format."); + return false; + } + + + if (_elementsToDelete.OfType().Any(g => !CanRecycleGroup(g))) + { + return false; + } + + if (_elementsToDelete.OfType().Any(e => !CanRecycleGroup(e.ParentGroup))) + { + return false; + } + Android.Util.Log.Debug("KP2A", "CanRecycle? Yes."); + return true; + } + + public override bool CanRecycle + { + get { return _canRecycle; } + } + + protected override UiStringKey QuestionsResourceId + { + get { return UiStringKey.AskDeletePermanentlyItems; } + } + + protected override void PerformDelete(List touchedGroups, List permanentlyDeletedGroups) + { + foreach (var g in _elementsToDelete.OfType()) + { + Android.Util.Log.Debug("KP2A", "Deleting " + g.Name); + DoDeleteGroup(g, touchedGroups, permanentlyDeletedGroups); + + } + + foreach (var e in _elementsToDelete.OfType()) + { + Android.Util.Log.Debug("KP2A", "Deleting " + e.Strings.ReadSafe(PwDefs.TitleField)); + DoDeleteEntry(e, touchedGroups); + } + } + + public override UiStringKey StatusMessage + { + get { return UiStringKey.DeletingItems; } + } + } +} \ No newline at end of file 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/Kp2aBusinessLogic/database/edit/MoveElements.cs b/src/Kp2aBusinessLogic/database/edit/MoveElements.cs new file mode 100644 index 00000000..8b923a22 --- /dev/null +++ b/src/Kp2aBusinessLogic/database/edit/MoveElements.cs @@ -0,0 +1,99 @@ +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 MoveElements: RunnableOnFinish + { + private readonly List _elementsToMove; + private readonly PwGroup _targetGroup; + private readonly Context _ctx; + private readonly IKp2aApp _app; + + public MoveElements(List elementsToMove, PwGroup targetGroup, Context ctx, IKp2aApp app, OnFinish finish) : base(finish) + { + _elementsToMove = elementsToMove; + _targetGroup = targetGroup; + _ctx = ctx; + _app = app; + } + + public override void Run() + { + //check if we will run into problems. Then finish with error before we start doing anything. + foreach (var _elementToMove in _elementsToMove) + { + PwGroup pgParent = _elementToMove.ParentGroup; + if (pgParent != _targetGroup) + { + if (pgParent != null) + { + PwGroup group = _elementToMove as PwGroup; + if (group != null) + { + if ((_targetGroup == group) || (_targetGroup.IsContainedIn(group))) + { + Finish(false, _app.GetResourceString(UiStringKey.CannotMoveGroupHere)); + return; + } + + } + + } + } + + } + + foreach (var elementToMove in _elementsToMove) + { + + _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/Kp2aUnitTests/TestDrawableFactory.cs b/src/Kp2aUnitTests/TestDrawableFactory.cs index c2c02c9e..57d20a7c 100644 --- a/src/Kp2aUnitTests/TestDrawableFactory.cs +++ b/src/Kp2aUnitTests/TestDrawableFactory.cs @@ -9,12 +9,12 @@ namespace Kp2aUnitTests { internal class TestDrawableFactory : IDrawableFactory { - public void AssignDrawableTo(ImageView iv, Resources res, PwDatabase db, PwIcon icon, PwUuid customIconId) + public void AssignDrawableTo(ImageView iv, Resources res, PwDatabase db, PwIcon icon, PwUuid customIconId, bool forGroup) { } - public Drawable GetIconDrawable(Resources res, PwDatabase db, PwIcon icon, PwUuid customIconId) + public Drawable GetIconDrawable(Resources res, PwDatabase db, PwIcon icon, PwUuid customIconId, bool forGroup) { return res.GetDrawable(Resource.Drawable.Icon); } diff --git a/src/MasterKeePlugin/SetupMasterEntryActivity.cs b/src/MasterKeePlugin/SetupMasterEntryActivity.cs index 4f052d5e..b2ac4133 100644 --- a/src/MasterKeePlugin/SetupMasterEntryActivity.cs +++ b/src/MasterKeePlugin/SetupMasterEntryActivity.cs @@ -71,6 +71,10 @@ namespace MasterKeePlugin _showPassword = !_showPassword; MakePasswordMaskedOrVisible(); }; + Android.Graphics.PorterDuff.Mode mMode = Android.Graphics.PorterDuff.Mode.SrcAtop; + Android.Graphics.Color color = new Android.Graphics.Color (224, 224, 224); + btnTogglePassword.SetColorFilter (color, mMode); + FindViewById(Resource.Id.button_ok).Click += delegate(object sender, EventArgs args) { diff --git a/src/MaterialTest/Resources/layout/toolbar.xml b/src/MaterialTest/Resources/layout/toolbar.xml new file mode 100644 index 00000000..b6dc0a2e --- /dev/null +++ b/src/MaterialTest/Resources/layout/toolbar.xml @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/src/MaterialTest/Resources/layout/toolbar2.xml b/src/MaterialTest/Resources/layout/toolbar2.xml new file mode 100644 index 00000000..b6dc0a2e --- /dev/null +++ b/src/MaterialTest/Resources/layout/toolbar2.xml @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/src/MaterialTest/Resources/values-v21/styles.xml b/src/MaterialTest/Resources/values-v21/styles.xml new file mode 100644 index 00000000..00f20009 --- /dev/null +++ b/src/MaterialTest/Resources/values-v21/styles.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/src/MaterialTest/Resources/values/styles.xml b/src/MaterialTest/Resources/values/styles.xml new file mode 100644 index 00000000..5f5cda29 --- /dev/null +++ b/src/MaterialTest/Resources/values/styles.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/src/MaterialTest/packages.config b/src/MaterialTest/packages.config new file mode 100644 index 00000000..3cbc47d1 --- /dev/null +++ b/src/MaterialTest/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/MaterialTest2/Assets/AboutAssets.txt b/src/MaterialTest2/Assets/AboutAssets.txt new file mode 100644 index 00000000..a9b0638e --- /dev/null +++ b/src/MaterialTest2/Assets/AboutAssets.txt @@ -0,0 +1,19 @@ +Any raw assets you want to be deployed with your application can be placed in +this directory (and child directories) and given a Build Action of "AndroidAsset". + +These files will be deployed with your package and will be accessible using Android's +AssetManager, like this: + +public class ReadAsset : Activity +{ + protected override void OnCreate (Bundle bundle) + { + base.OnCreate (bundle); + + InputStream input = Assets.Open ("my_asset.txt"); + } +} + +Additionally, some Android functions will automatically load asset files: + +Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); diff --git a/src/MaterialTest2/MainActivity.cs b/src/MaterialTest2/MainActivity.cs new file mode 100644 index 00000000..0405c351 --- /dev/null +++ b/src/MaterialTest2/MainActivity.cs @@ -0,0 +1,214 @@ +using System; +using Android.App; +using Android.Content; +using Android.Graphics; +using Android.Runtime; +using Android.Support.V4.View; +using Android.Support.V4.Widget; +using Android.Support.V7.App; + +using Android.Support.Design.Widget; + +using Android.Views; +using Android.Widget; +using Android.OS; +using Android.Util; +using Toolbar = Android.Support.V7.Widget.Toolbar; +namespace MaterialTest2 +{ + public class MyDrawerLayout : Android.Support.V4.Widget.DrawerLayout + { + private bool _fitsSystemWindows; + + protected MyDrawerLayout(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) + { + } + + public MyDrawerLayout(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle) + { + } + + public MyDrawerLayout(Context context, IAttributeSet attrs) : base(context, attrs) + { + } + + public MyDrawerLayout(Context context) : base(context) + { + } + + private int[] mInsets = new int[4]; + + protected override bool FitSystemWindows(Rect insets) + { + if (Build.VERSION.SdkInt >= Build.VERSION_CODES.Kitkat) + { + // Intentionally do not modify the bottom inset. For some reason, + // if the bottom inset is modified, window resizing stops working. + // TODO: Figure out why. + + mInsets[0] = insets.Left; + mInsets[1] = insets.Top; + mInsets[2] = insets.Right; + + insets.Left = 0; + insets.Top = 0; + insets.Right = 0; + } + + return base.FitSystemWindows(insets); + + } + public int[] GetInsets() + { + return mInsets; + } + } + + + [Activity(Theme="@style/MyTheme", Label = "MaterialTest", MainLauncher = false, Icon = "@drawable/icon", WindowSoftInputMode = SoftInput.AdjustResize)] + public class MainActivity : AppCompatActivity + { + int count = 1; + + private DrawerLayout mDrawerLayout; + //private RecyclerView mDrawerList; + private ActionBarDrawerToggle mDrawerToggle; + + private string mDrawerTitle; + + public override bool OnCreateOptionsMenu(IMenu menu) + { + MenuInflater.Inflate(Resource.Menu.menu_password, menu); + return true; + } + + public override bool OnOptionsItemSelected(IMenuItem item) + { + switch (item.ItemId) + { + case Android.Resource.Id.Home: + mDrawerLayout.OpenDrawer(Android.Support.V4.View.GravityCompat.Start); + return true; + } + return base.OnOptionsItemSelected(item); + } + + protected override void OnCreate(Bundle bundle) + { + base.OnCreate(bundle); + + // Set our view from the "main" layout resource + SetContentView(Resource.Layout.Main); + + mDrawerTitle = this.Title; + //mPlanetTitles = this.Resources.GetStringArray (Resource.Array.planets_array); + mDrawerLayout = FindViewById(Resource.Id.drawer_layout); + //mDrawerList = FindViewById (Resource.Id.left_drawer); + + + //mDrawerLayout.SetDrawerShadow (Resource.Drawable.drawer_shadow, GravityCompat.Start); + // improve performance by indicating the list if fixed size. + //mDrawerList.HasFixedSize = true; + //mDrawerList.SetLayoutManager (new LinearLayoutManager (this)); + NavigationView nv; + // set up the drawer's list view with items and click listener + //mDrawerList.SetAdapter (new PlanetAdapter (mPlanetTitles, this)); + // enable ActionBar app icon to behave as action to toggle nav drawer + + // ActionBarDrawerToggle ties together the the proper interactions + // between the sliding drawer and the action bar app icon + + mDrawerToggle = new MyActionBarDrawerToggle (this, mDrawerLayout, + Resource.Drawable.abc_ic_menu_copy_mtrl_am_alpha, + Resource.String.drawer_open, + Resource.String.drawer_close); + + mDrawerLayout.SetDrawerListener (mDrawerToggle); + + // Get our button from the layout resource, + // and attach an event to it + Button button = FindViewById