Merge branch 'MaterialDesign'

This commit is contained in:
Philipp Crocoll 2015-09-24 06:13:06 +02:00
commit 287e4bfff7
727 changed files with 6688 additions and 3961 deletions

View File

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

View File

@ -111,7 +111,7 @@ namespace KeePassLib
/// <summary>
/// Default number of master key encryption/transformation rounds (making dictionary attacks harder).
/// </summary>
public const ulong DefaultKeyEncryptionRounds = 6000;
public const ulong DefaultKeyEncryptionRounds = 500000;
/// <summary>
/// Default identifier string for the title field. Should not contain

View File

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

View File

@ -55,8 +55,9 @@
</ItemGroup>
<ItemGroup>
<Compile Include="database\CheckDatabaseForChanges.cs" />
<Compile Include="database\edit\DeleteMultipleItems.cs" />
<Compile Include="database\edit\EditGroup.cs" />
<Compile Include="database\edit\MoveElement.cs" />
<Compile Include="database\edit\MoveElements.cs" />
<Compile Include="database\KdbDatabaseFormat.cs" />
<Compile Include="database\KdbxDatabaseFormat.cs" />
<Compile Include="database\PwEntryOutput.cs" />

View File

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

View File

@ -57,6 +57,8 @@ namespace keepass2android
CopyFileRequiredForEditing,
DuplicateUuidsError,
DuplicateUuidsErrorAdditional,
KdbBetaWarning
KdbBetaWarning,
DeletingItems,
AskDeletePermanentlyItems
}
}

View File

@ -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<PwGroup> touchedGroups, List<PwGroup> 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; }
}
}
}

View File

@ -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<PwGroup> touchedGroups, List<PwGroup> 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; }
}
}
}

View File

@ -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<IStructureItem> _elementsToDelete;
private readonly bool _canRecycle;
public DeleteMultipleItems(Context ctx, Database db, List<IStructureItem> 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<PwGroup>().Any(g => !CanRecycleGroup(g)))
{
return false;
}
if (_elementsToDelete.OfType<PwEntry>().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<PwGroup> touchedGroups, List<PwGroup> permanentlyDeletedGroups)
{
foreach (var g in _elementsToDelete.OfType<PwGroup>())
{
Android.Util.Log.Debug("KP2A", "Deleting " + g.Name);
DoDeleteGroup(g, touchedGroups, permanentlyDeletedGroups);
}
foreach (var e in _elementsToDelete.OfType<PwEntry>())
{
Android.Util.Log.Debug("KP2A", "Deleting " + e.Strings.ReadSafe(PwDefs.TitleField));
DoDeleteEntry(e, touchedGroups);
}
}
public override UiStringKey StatusMessage
{
get { return UiStringKey.DeletingItems; }
}
}
}

View File

@ -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<PwGroup> 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<PwGroup> touchedGroups = new List<PwGroup>();
List<PwGroup> permanentlyDeletedGroups = new List<PwGroup>();
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<PwGroup> touchedGroups, List<PwGroup> permanentlyDeletedGroups);
public abstract UiStringKey StatusMessage { get; }
protected bool DoDeleteGroup(PwGroup pg, List<PwGroup> touchedGroups, List<PwGroup> 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;
}
}
}

View File

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

View File

@ -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<IStructureItem> _elementsToMove;
private readonly PwGroup _targetGroup;
private readonly Context _ctx;
private readonly IKp2aApp _app;
public MoveElements(List<IStructureItem> 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();
}
}
}

View File

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

View File

@ -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)
{

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<!--
Base application theme for API 21+. This theme replaces
MyTheme from resources/values/styles.xml on API 21+ devices.
-->
<style name="MyTheme" parent="MyTheme.Base">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
</style>
</resources>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<style name="MyTheme" parent="MyTheme.Base">
</style>
<!-- Base theme applied no matter what API -->
<style name="MyTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowNoTitle">true</item>
<!--We will be using the toolbar so no need to show ActionBar-->
<item name="windowActionBar">false</item>
<!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette-->
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">#2196F3</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">#1976D2</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">#FF4081</item>
<!-- You can also set colorControlNormal, colorControlActivated
colorControlHighlight and colorSwitchThumbNormal. -->
</style>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Xamarin.Android.Support.v4" version="21.0.3.0" targetFramework="MonoAndroid22" />
<package id="Xamarin.Android.Support.v7.AppCompat" version="21.0.3.0" targetFramework="MonoAndroid50" />
<package id="Xamarin.Android.Support.v7.MediaRouter" version="21.0.3.0" targetFramework="MonoAndroid50" />
<package id="Xamarin.GooglePlayServices" version="22.0.0.0" targetFramework="MonoAndroid50" />
</packages>

View File

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

View File

@ -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<DrawerLayout>(Resource.Id.drawer_layout);
//mDrawerList = FindViewById<RecyclerView> (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<Button>(Resource.Id.MyButton);
button.Click += delegate { button.Text = string.Format("{0} clicks!", count++);
FindViewById(Resource.Id.MyButton).SetMinimumHeight(30*count);
};
FindViewById<ImageButton>(Resource.Id.eyebutton).Click += delegate(object sender, EventArgs args)
{
Snackbar.Make(FindViewById<ImageButton>(Resource.Id.eyebutton), "Here's a snackbar!", Snackbar.LengthLong).SetAction("Action",
new ClickListener(v =>
{
Console.WriteLine("Action handler");
})).Show();
};
var toolbar = FindViewById<Toolbar> (Resource.Id.toolbar);
//SupportActionBar.SetBackgroundDrawable(GetDrawable(Resource.Drawable.ic_keepass2android));
//Toolbar will now take on default Action Bar characteristics
SetSupportActionBar (toolbar);
//You can now use and reference the ActionBar
//SupportActionBar.Title = "Hello from Toolbar";
var collapsingToolbar = FindViewById<CollapsingToolbarLayout> (Resource.Id.collapsing_toolbar);
collapsingToolbar.SetTitle ("Unlock Database");
//SupportActionBar.SetHomeAsUpIndicator (Resource.Drawable.ic_menu);
//SupportActionBar.SetDisplayHomeAsUpEnabled (true);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
mDrawerToggle.SyncState();
var fab = FindViewById<FloatingActionButton> (Resource.Id.fab);
fab.Click += (sender, e) => {
Snackbar.Make (fab, "Here's a snackbar!", Snackbar.LengthLong).SetAction ("Action",
new ClickListener (v => {
Console.WriteLine ("Action handler");
})).Show ();
};
}
public class ClickListener : Java.Lang.Object, View.IOnClickListener
{
public ClickListener (Action<View> handler)
{
Handler = handler;
}
public Action<View> Handler { get; set; }
public void OnClick (View v)
{
var h = Handler;
if (h != null)
h (v);
}
}
internal class MyActionBarDrawerToggle : ActionBarDrawerToggle
{
MainActivity owner;
public MyActionBarDrawerToggle(MainActivity activity, DrawerLayout layout, int imgRes, int openRes, int closeRes)
: base(activity, layout, openRes, closeRes)
{
owner = activity;
}
public override void OnDrawerClosed(View drawerView)
{
owner.SupportActionBar.Title = owner.Title;
owner.InvalidateOptionsMenu();
}
public override void OnDrawerOpened(View drawerView)
{
owner.SupportActionBar.Title = owner.mDrawerTitle;
owner.InvalidateOptionsMenu();
}
}
}
}

View File

@ -0,0 +1,267 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ProjectGuid>{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>MaterialTest2</RootNamespace>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
<AndroidApplication>True</AndroidApplication>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<AssemblyName>MaterialTest2</AssemblyName>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
<ConsolePause>false</ConsolePause>
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
<Reference Include="Xamarin.Android.Support.v4">
<HintPath>..\packages\Xamarin.Android.Support.v4.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.AppCompat">
<HintPath>..\packages\Xamarin.Android.Support.v7.AppCompat.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Design">
<HintPath>..\packages\Xamarin.Android.Support.Design.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.Design.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="FileStorageSelect.cs" />
<Compile Include="GroupActivity.cs" />
<Compile Include="GroupEditActivity.cs" />
<Compile Include="GroupListFragment.cs" />
<Compile Include="MainActivity.cs" />
<Compile Include="PwEntryView.cs" />
<Compile Include="PwGroupView.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SearchProvider.cs" />
<Compile Include="SplashActivity.cs" />
<Compile Include="EntryEditActivity2.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
<None Include="Properties\AndroidManifest.xml">
<SubType>Designer</SubType>
</None>
<AndroidResource Include="Resources\drawable\group_icon_bkg_drawable.xml" />
<AndroidResource Include="Resources\layout\my_list_item.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\values\dimens.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\layout\nav_header.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\drawable-xhdpi\ic_dashboard.png" />
<AndroidResource Include="Resources\drawable-xhdpi\ic_discuss.png" />
<AndroidResource Include="Resources\drawable-xhdpi\ic_done.png" />
<AndroidResource Include="Resources\drawable-xhdpi\ic_event.png" />
<AndroidResource Include="Resources\drawable-xhdpi\ic_forum.png" />
<AndroidResource Include="Resources\drawable-xhdpi\ic_headset.png" />
<AndroidResource Include="Resources\drawable-xhdpi\ic_menu.png" />
<AndroidResource Include="Resources\layout\Splash.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\layout\filestorageselect.xml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\layout\entry_edit.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\layout\group.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\layout\generate_password.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<None Include="packages.config" />
<AndroidResource Include="Resources\drawable\search_dropdown_light.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\Main.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\values\Strings.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\drawable\Icon.png" />
<AndroidResource Include="Resources\layout\toolbar2.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\values\styles.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\values-v21\styles.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
<ItemGroup>
<AndroidResource Include="Resources\drawable\drawer_shadow.9.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic_keepass2android.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\toolbar_bg.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\list_selector.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\colors.xml" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\color\" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\menu\menu_password.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic_action_eye_open.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\splashlogo.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\createnewdb.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\opendb.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\splash_bg_selector.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\splash_button_bg.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\storagetype_grid_bg.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\storagetype_button_bg.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\group_list_entry.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\entry_list_entry.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\grouplistitem_selector.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\checked_drawable.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\listitem_unchecked_drawable.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\colortest.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\entry_icon_bkg_drawable.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\checkmark.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\rightarrow.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\grouplistfragment.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<XamarinComponentReference Include="xamandroidsupportdesign">
<Version>22.2.0.0</Version>
<Visible>False</Visible>
</XamarinComponentReference>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\group_edit.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_attachments.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_comments.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_created.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_expires.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_extras.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_group.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_modified.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_password.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_tags.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_url.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_username.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\menu\menu_entryedit.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\searchable_mattest.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
</Project>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="MaterialTest2.MaterialTest2" android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<application android:label="MaterialTest2" android:icon="@drawable/ic_discuss"></application>
</manifest>

View File

@ -0,0 +1,28 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using Android.App;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("MaterialTest2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Philipp")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.0")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -0,0 +1,44 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.axml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable/
icon.png
layout/
main.axml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called "R"
(this is an Android convention) that contains the tokens for each one of the resources
included. For example, for the above Resources layout, this is what the R class would expose:
public class R {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
to reference the layout/main.axml file, or R.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F0FFFFFF"/>
<stroke android:width="1dp" color="#A00080FF"/>
<padding android:left="5dp" android:top="0dp"
android:right="5dp" android:bottom="1dp" />
</shape>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:id="@+id/drawerLayout"
android:layout_height="match_parent">
<!-- activity view -->
<LinearLayout
android:id="@+id/layout_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar2"
layout="@layout/toolbar2" />
<ScrollView xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/main_content">
<Button
android:id="@+id/MyButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/Hello" />
<CheckBox
android:text="CheckBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/checkBox1" />
<ImageView
android:id="@+id/imglogo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="12dp"
android:scaleType="fitXY"
android:src="@drawable/ic_keepass2android" />
<EditText
android:inputType="textEmailAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editText1" />
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingRight="8dp"
android:paddingLeft="8dp"
android:choiceMode="singleChoice" />
</LinearLayout>
</ScrollView>
</LinearLayout>
<!-- navigation drawer -->
<RelativeLayout
android:layout_gravity="left|start"
android:layout_width="match_parent"
android:background="#fff"
android:layout_height="match_parent">
<Button
android:id="@+id/MyButton2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/Hello" />
</RelativeLayout>
</android.support.v4.widget.DrawerLayout>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="192dp"
android:background="?attr/colorAccent"
android:padding="16dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:orientation="vertical"
android:gravity="bottom">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Username"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
</LinearLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:minHeight="?attr/actionBarSize"
android:background="@drawable/toolbar_bg"
local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
local:popupTheme="@style/ThemeOverlay.AppCompat.Light" >
</android.support.v7.widget.Toolbar>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<!--
Base application theme for API 21+. This theme replaces
MyTheme from resources/values/styles.xml on API 21+ devices.
-->
<style name="MyTheme" parent="MyTheme.Base">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
<item name="android:actionModeBackground">@color/appAccentColor</item>
</style>
<style name="MyTheme_ActionBar" parent="MyTheme_ActionBar.Base">
<item name="android:actionModeBackground">@color/appAccentColor</item>
<item name="actionModeBackground">@color/appAccentColor</item>
</style>
<style name="EntryFieldHeader">
<item name="android:drawablePadding">2dp</item>
<item name="android:layout_marginLeft">0dip</item>
<item name="android:layout_marginRight">12dip</item>
<item name="android:layout_marginBottom">3dp</item>
<item name="android:layout_marginTop">8dp</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">12sp</item>
</style>
</resources>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="Hello">Hello World, Click Me!</string>
<string name="ApplicationName">MaterialTest</string>
<string name="app_name">MaterialTest</string>
<string name="action_settings">Settings</string>
<string name="drawer_open">open</string>
<string name="drawer_close">close</string>
<string name="group">Group</string>
<string name="action_search">Search</string>
<string name="search_hint">Search Places</string>
<string name="search_settings">Search Places</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="detail_backdrop_height">200dp</dimen>
<dimen name="fab_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,188 @@
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<style name="BottomBarButton" parEntryEditSingleLine_ImageView="@style/Widget.AppCompat.Button.Borderless">
<item name="android:textSize">16sp</item>
<item name="android:layout_margin">6dp</item>
<item name="android:layout_marginLeft">4dp</item>
<item name="android:layout_marginRight">4dp</item>
<item name="android:paddingBottom">10dp</item>
<item name="android:paddingTop">10dp</item>
<item name="android:paddingLeft">8dp</item>
<item name="android:paddingRight">8dp</item>
<item name="android:textColor">#2196f3</item>
</style>
<!--
<style name="SplashScreenButton" parent="Widget.AppCompat.Button">
<item name="colorButtonNormal">#fff</item>
<item name="android:textSize">16sp</item>
<item name="android:layout_height">32sp</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_marginTop">8dp</item>
<item name="android:layout_marginBottom">8dp</item>
</style>
-->
<style name="SplashScreenButton" parent="@style/Widget.AppCompat.Button" >
<item name="android:textSize">16sp</item>
<item name="android:layout_height">40sp</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:background">@drawable/splash_button_bg</item>
<item name="android:layout_marginTop">8dp</item>
<item name="android:layout_marginBottom">8dp</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:drawablePadding">10dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:gravity">left|center_vertical</item>
<item name="android:textColor">#737373</item>
</style>
<style name="EntryEditSingleLine_ImageView">
<item name="android:layout_width">40dp</item>
<item name="android:layout_gravity">top</item>
<item name="android:layout_marginRight">16dp</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">0</item>
</style>
<style name="EntryEditSingleLine_TextInputLayout">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
</style>
<style name="EntryEditSingleLine_EditText">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:paddingTop">0dp</item>
</style>
<style name="EntryEditSingleLine_container">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">8dp</item>
<item name="android:orientation">horizontal</item>
<item name="android:gravity">center_vertical</item>
</style>
<style name="MyTheme" parent="MyTheme.Base">
<item name="actionModeBackground">@color/appAccentColor</item>
</style>
<!--style name="MyTheme.ActionMode" parent="@style/Theme.AppCompat.Light.DarkActionBar">
<item name="actionModeBackground">#FFFFFF</item>
</style-->
<style name="MyTheme_ActionBar" parent="MyTheme_ActionBar.Base">
<item name="actionModeBackground">@color/appAccentColor</item>
</style>
<!-- Base theme applied no matter what API -->
<style name="MyTheme.Base" parent="Theme.AppCompat.Holo.Light.NoActionBar">
<item name="android:windowNoTitle">true</item>
<!--We will be using the toolbar so no need to show ActionBar-->
<item name="windowActionBar">false</item>
<!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette-->
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">@color/appPrimaryColor</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">@color/appPrimaryDarkColor</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">@color/appAccentColor</item>
<!-- You can also set colorControlNormal, colorControlActivated
colorControlHighlight and colorSwitchThumbNormal. -->
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
</style>
<style name="MyTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowNoTitle">true</item>
<!--We will be using the toolbar so no need to show ActionBar-->
<item name="windowActionBar">false</item>
<!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette-->
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">@color/appPrimaryColor</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">@color/appPrimaryDarkColor</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">@color/appAccentColor</item>
<!-- You can also set colorControlNormal, colorControlActivated
colorControlHighlight and colorSwitchThumbNormal. -->
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
</style>
<style name="MyTheme_ActionBar.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">true</item>
<item name="colorPrimary">@color/appPrimaryColor</item>
<item name="colorPrimaryDark">@color/appPrimaryDarkColor</item>
<item name="colorAccent">@color/appAccentColor</item>
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
<item name="actionModeBackground">@color/appAccentColor</item>
<item name="searchViewStyle">@style/CustomSearchViewStyle</item>
<item name="autoCompleteTextViewStyle">@style/AutoCompleteTextView</item>
</style>
<style name="AutoCompleteTextView" parent="Widget.AppCompat.Light.AutoCompleteTextView">
<item name="android:textColor">#f0f</item>
<item name="android:textCursorDrawable">@null</item>
<item name="android:textColorHighlight">#0f0</item>
</style>
<style name="CustomSearchViewStyle" parent="Widget.AppCompat.SearchView">
<item name="queryBackground">@color/appPrimaryDarkColor</item>
</style>
<style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
<item name="spinBars">true</item>
<item name="color">@android:color/white</item>
</style>
<style name="GroupDetailInSearchResult">
<item name="@android:textStyle">italic</item>
</style>
<style name="Base_Dialog" parent="Theme.AppCompat.Light.Dialog" />
<style name="Dialog" parent="Base_Dialog"></style>
<style name="TextAppearance_EditEntry">
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="TextAppearance_EditEntry_Value" parent="TextAppearance_EditEntry">
<item name="android:gravity">center_vertical</item>
<item name="android:layout_gravity">center_vertical</item>
<item name="android:layout_marginRight">12dip</item>
<item name="android:layout_marginLeft">12dip</item>
</style>
<style name="TextAppearance_EditEntry_Small">
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textAllCaps">true</item>
</style>
<style name="TextAppearance_SmallHeading" parent="TextAppearance_EditEntry_Small">
<item name="android:minHeight">24dip</item>
<item name="android:layout_width">144dip</item>
<item name="android:layout_marginTop">12dip</item>
<item name="android:layout_marginRight">16dip</item>
<item name="android:paddingRight">8dip</item>
<item name="android:layout_marginBottom">-12dip</item>
</style>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Xamarin.Android.Support.Design" version="22.2.1.0" targetFramework="MonoAndroid50" />
<package id="Xamarin.Android.Support.v4" version="22.2.1.0" targetFramework="MonoAndroid50" />
<package id="Xamarin.Android.Support.v7.AppCompat" version="22.2.1.0" targetFramework="MonoAndroid50" />
</packages>

View File

@ -10,8 +10,8 @@ namespace keepass2android
{
[Activity(Label = "@string/app_name",
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
Theme = "@style/NoTitleBar")]
[IntentFilter(new[] { "kp2a.action.AboutActivity" }, Categories = new[] { Intent.CategoryDefault })]
Theme = "@style/MyTheme_ActionBar")]
[IntentFilter(new[] { "keepass2android.AboutActivity" }, Categories = new[] { Intent.CategoryDefault })]
public class AboutActivity: Activity, IDialogInterfaceOnDismissListener
{
private AboutDialog _dialog;

View File

@ -5,6 +5,7 @@ using Android.Content.PM;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Preferences;
using Android.Support.V7.App;
using Android.Text;
using Android.Views;
using Android.Widget;
@ -19,8 +20,8 @@ namespace keepass2android
{
[Activity(Label = "@string/app_name",
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
Theme = "@style/Base")]
public class CreateDatabaseActivity : Activity
Theme = "@style/MyTheme_ActionBar")]
public class CreateDatabaseActivity : AppCompatActivity
{
private IOConnectionInfo _ioc;
private string _keyfileFilename;
@ -57,6 +58,9 @@ namespace keepass2android
base.OnCreate(bundle);
_design.ApplyTheme();
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
SetContentView(Resource.Layout.create_database);
_appTask = AppTask.GetTaskInOnCreate(bundle, Intent);
@ -140,7 +144,10 @@ namespace keepass2android
_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);
}
@ -579,6 +586,15 @@ namespace keepass2android
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Android.Resource.Id.Home:
OnBackPressed();
return true;
}
return false;
}
}
}

View File

@ -14,7 +14,7 @@ using KeePassLib.Utility;
namespace keepass2android
{
[Activity(Label = AppNames.AppName, Theme = "@style/Base")]
[Activity(Label = AppNames.AppName, Theme = "@style/MyTheme_ActionBar")]
public class DonateReminder : Activity
{
class Reminder
@ -52,23 +52,23 @@ namespace keepass2android
yield return new Reminder
{
From = new DateTime(2016, 09, 17),
From = new DateTime(2016, 09, 17),
To = new DateTime(2016, 10, 04),
Key = "DonationOktoberfest2016"
,ResourceToShow = Resource.Layout.donate
};
yield return new Reminder
{
From = new DateTime(2015, 09, 16),
To = new DateTime(2015, 10, 04),
Key = "DonationOktoberfest2017"
From = new DateTime(2017, 09, 16),
To = new DateTime(2017, 10, 04),
Key = "DonationOktoberfest2017b"//b because year was incorrectly set to 2015 in 0.9.8b
,ResourceToShow = Resource.Layout.donate
};
yield return new Reminder
{
From = new DateTime(2015, 09, 22),
To = new DateTime(2015, 10, 08),
Key = "DonationOktoberfest2018"
From = new DateTime(2018, 09, 22),
To = new DateTime(2018, 10, 08),
Key = "DonationOktoberfest2018b"//b because year was incorrectly set to 2015 in 0.9.8b
,ResourceToShow = Resource.Layout.donate
};

View File

@ -44,7 +44,8 @@ using Uri = Android.Net.Uri;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden, Theme="@style/NoTitleBar")]
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden,
Theme = "@style/MyTheme_ActionBar")]
public class EntryActivity : LockCloseActivity
{
public const String KeyEntry = "entry";
@ -125,29 +126,7 @@ namespace keepass2android
}
protected void SetupMoveButtons() {
View moveView = FindViewById(Resource.Id.entry_move);
/* Disabled for simpler UI. Wait if users demand that button.
if (App.Kp2a.GetDb().CanWrite)
{
moveView.Visibility = ViewStates.Visible;
moveView.Click += (sender, e) =>
{
NavigateToFolderAndLaunchMoveElementTask navMoveTask =
new NavigateToFolderAndLaunchMoveElementTask(Entry.ParentGroup,Entry.Uuid, false);
navMoveTask.SetActivityResult(this, KeePass.ExitNormal );
Finish();
};
}
else*/
{
moveView.Visibility = ViewStates.Gone;
}
}
private class PluginActionReceiver : BroadcastReceiver
{
private readonly EntryActivity _activity;
@ -328,9 +307,10 @@ namespace keepass2android
_showPassword =
!prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
RequestWindowFeature(WindowFeatures.IndeterminateProgress);
base.OnCreate(savedInstanceState);
RequestWindowFeature(WindowFeatures.IndeterminateProgress);
new ActivityDesign(this).ApplyTheme();
@ -375,8 +355,7 @@ namespace keepass2android
FillData();
SetupEditButtons();
SetupMoveButtons ();
App.Kp2a.GetDb().LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.GetDb().KpDatabase);
_pluginActionReceiver = new PluginActionReceiver(this);
@ -455,12 +434,14 @@ namespace keepass2android
private void PopulateExtraStrings()
{
ViewGroup extraGroup = (ViewGroup) FindViewById(Resource.Id.extra_strings);
bool hasExtras = false;
foreach (var pair in Entry.Strings.Where(pair => !PwDefs.IsStandardField(pair.Key)).OrderBy(pair => pair.Key))
{
hasExtras = true;
var stringView = CreateExtraSection(pair.Key, pair.Value.ReadString(), pair.Value.IsProtected);
extraGroup.AddView(stringView.View);
}
FindViewById(Resource.Id.extra_strings_container).Visibility = hasExtras ? ViewStates.Visible : ViewStates.Gone;
}
private ExtraStringView CreateExtraSection(string key, string value, bool isProtected)
@ -676,7 +657,7 @@ namespace keepass2android
if (extension != null)
{
MimeTypeMap mime = MimeTypeMap.Singleton;
type = mime.GetMimeTypeFromExtension(extension);
type = mime.GetMimeTypeFromExtension(extension.ToLowerInvariant());
}
return type;
}
@ -684,13 +665,13 @@ namespace keepass2android
public override void OnBackPressed()
{
base.OnBackPressed();
OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
//OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
}
protected void FillData()
{
_protectedTextViews = new List<TextView>();
ImageView iv = (ImageView) FindViewById(Resource.Id.entry_icon);
ImageView iv = (ImageView) FindViewById(Resource.Id.icon);
if (iv != null)
{
iv.SetImageDrawable(Resources.GetDrawable(Resource.Drawable.ic00));
@ -698,8 +679,9 @@ namespace keepass2android
ActionBar.Title = Entry.Strings.ReadSafe(PwDefs.TitleField);
ActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.Title = Entry.Strings.ReadSafe(PwDefs.TitleField);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
PopulateGroupText (Resource.Id.entry_group_name, Resource.Id.entryfield_group_container, KeyGroupFullPath);
@ -736,7 +718,7 @@ namespace keepass2android
}
PopulateStandardText(Resource.Id.entry_comment, Resource.Id.entryfield_container_comment, PwDefs.NotesField);
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.comment_container),
FindViewById(Resource.Id.username_vdots), PwDefs.NotesField);
FindViewById(Resource.Id.comment_vdots), PwDefs.NotesField);
PopulateText(Resource.Id.entry_tags, Resource.Id.entryfield_container_tags, concatTags(Entry.Tags));
PopulateText(Resource.Id.entry_override_url, Resource.Id.entryfield_container_overrideurl, Entry.OverrideUrl);
@ -912,6 +894,8 @@ namespace keepass2android
return base.OnPrepareOptionsMenu(menu);
}
private void UpdateTogglePasswordMenu()
@ -1005,7 +989,7 @@ namespace keepass2android
//So we can simply Finish. See this page for information on how to do this in more general (future?) cases:
//http://developer.android.com/training/implementing-navigation/ancestral.html
Finish();
OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
//OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
return true;
}

View File

@ -21,7 +21,7 @@ namespace keepass2android
get
{
//return new TextDrawable("\uF06E", _activity);
return _activity.Resources.GetDrawable(Resource.Drawable.ic_action_eye_open);
return _activity.Resources.GetDrawable(Resource.Drawable.ic_menu_view);
}
}

View File

@ -33,12 +33,13 @@ using KeePassLib.Security;
using Android.Content.PM;
using System.IO;
using System.Globalization;
using Android.Util;
using File = System.IO.File;
using Uri = Android.Net.Uri;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden, Theme="@style/NoTitleBar")]
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_ActionBar")]
public class EntryEditActivity : LockCloseActivity {
public const String KeyEntry = "entry";
public const String KeyParent = "parent";
@ -128,7 +129,7 @@ namespace keepass2android
{
String groupId = i.GetStringExtra(KeyParent);
State.ParentGroup = db.KpDatabase.RootGroup.FindGroup(new PwUuid(MemUtil.HexStringToByteArray(groupId)), true);
State.EntryInDatabase = new PwEntry(true, true);
State.EntryInDatabase.Strings.Set(PwDefs.UserNameField, new ProtectedString(
db.KpDatabase.MemoryProtection.ProtectUserName, db.KpDatabase.DefaultUserName));
@ -206,7 +207,7 @@ namespace keepass2android
if (State.SelectedIcon)
{
//TODO: custom image
iconButton.SetImageResource(Icons.IconToResId(State.SelectedIconId));
iconButton.SetImageResource(Icons.IconToResId(State.SelectedIconId, false));
}
iconButton.Click += (sender, evt) => {
UpdateEntryFromUi(State.Entry);
@ -215,8 +216,8 @@ namespace keepass2android
// Generate password button
Button generatePassword = (Button)FindViewById(Resource.Id.generate_button);
generatePassword.Click += (sender, e) => {
FindViewById(Resource.Id.generate_button).Click += (sender, e) =>
{
UpdateEntryFromUi(State.Entry);
GeneratePasswordActivity.Launch(this);
};
@ -225,21 +226,20 @@ namespace keepass2android
// Save button
ActionBar.SetCustomView(Resource.Layout.SaveButton);
ActionBar.SetDisplayShowCustomEnabled(true);
ActionBar.SetDisplayShowTitleEnabled(false);
ActionBar.SetDisplayUseLogoEnabled(false);
ActionBar.SetDisplayShowHomeEnabled(false);
ActionBar.SetDisplayOptions(ActionBarDisplayOptions.ShowCustom,
ActionBarDisplayOptions.ShowCustom);
var save = FindViewById(Resource.Id.entry_save);
save.Click += (sender, e) =>
{
SaveEntry();
};
//SupportActionBar.SetCustomView(Resource.Layout.SaveButton);
if (State.IsNew)
{
SupportActionBar.Title = GetString(Resource.String.add_entry);
}
else
{
SupportActionBar.Title = GetString(Resource.String.edit_entry);
}
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
FindViewById(Resource.Id.entry_save_cancel).Click += (sender, args) => Finish();
// Respect mask password setting
MakePasswordVisibleOrHidden();
@ -249,6 +249,9 @@ namespace keepass2android
State.ShowPassword = !State.ShowPassword;
MakePasswordVisibleOrHidden();
};
Android.Graphics.PorterDuff.Mode mMode = Android.Graphics.PorterDuff.Mode.SrcAtop;
Android.Graphics.Color color = new Android.Graphics.Color (189,189,189);
btnTogglePassword.SetColorFilter (color, mMode);
Button addButton = (Button) FindViewById(Resource.Id.add_advanced);
@ -258,7 +261,7 @@ namespace keepass2android
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
KeyValuePair<string, ProtectedString> pair = new KeyValuePair<string, ProtectedString>("" , new ProtectedString(true, ""));
LinearLayout ees = CreateExtraStringView(pair);
View ees = CreateExtraStringView(pair);
container.AddView(ees);
State.EntryModified = true;
@ -669,13 +672,13 @@ namespace keepass2android
//somehow after re-creating the activity. Maybe a Mono for Android bug?
Intent intent = Intent;
intent.PutExtra(IntentContinueWithEditing, true);
OverridePendingTransition(0, 0);
//OverridePendingTransition(0, 0);
intent.AddFlags(ActivityFlags.NoAnimation | ActivityFlags.ForwardResult);
_closeForReload = true;
SetResult(KeePass.ExitRefreshTitle); //probably the entry will be modified -> let the EditActivity refresh to be safe
Finish();
OverridePendingTransition(0, 0);
//OverridePendingTransition(0, 0);
StartActivity(intent);
}
@ -745,9 +748,11 @@ namespace keepass2android
{
label = "<attachment>";
}
Button binaryButton = new Button(this) {Text = label};
//Button binaryButton = new Button(this, null, Resource.Style.EditEntryButton) {Text = label};
Button binaryButton = (Button)LayoutInflater.Inflate(Resource.Layout.EntryEditButtonDelete, null);
binaryButton.Text = label;
binaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuDelete),null, null, null);
//binaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuDelete),null, null, null);
binaryButton.Click += (sender, e) =>
{
State.EntryModified = true;
@ -759,10 +764,14 @@ namespace keepass2android
}
//Button addBinaryButton = new Button(this, null, Resource.Style.EditEntryButton ) {Text = GetString(Resource.String.add_binary)};
//addBinaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuAdd) , null, null, null);
Button addBinaryButton = (Button)LayoutInflater.Inflate(Resource.Layout.EntryEditButtonAdd, null);
addBinaryButton.Text = GetString(Resource.String.add_binary);
Button addBinaryButton = new Button(this) {Text = GetString(Resource.String.add_binary)};
addBinaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuAdd) , null, null, null);
addBinaryButton.Enabled = true;
if (!App.Kp2a.GetDb().DatabaseFormat.CanHaveMultipleAttachments)
addBinaryButton.Enabled = !State.Entry.Binaries.Any();
addBinaryButton.Click += (sender, e) =>
@ -795,13 +804,18 @@ namespace keepass2android
public override bool OnOptionsItemSelected(IMenuItem item) {
switch ( item.ItemId ) {
case Resource.Id.menu_donate:
return Util.GotoDonateUrl(this);
case Resource.Id.menu_save:
SaveEntry();
return true;
case Resource.Id.menu_cancel:
Finish();
return true;
case Android.Resource.Id.Home:
OnBackPressed();
return true;
default:
return base.OnOptionsItemSelected(item);
}
return base.OnOptionsItemSelected(item);
}
@ -819,15 +833,18 @@ namespace keepass2android
FindViewById(Resource.Id.entry_expires).Enabled = State.Entry.Expires;
}
public override Java.Lang.Object OnRetainNonConfigurationInstance()
/*
* TODO required??
*
* public override Java.Lang.Object OnRetainNonConfigurationInstance()
{
UpdateEntryFromUi(State.Entry);
return this;
}
}*/
LinearLayout CreateExtraStringView(KeyValuePair<string, ProtectedString> pair)
RelativeLayout CreateExtraStringView(KeyValuePair<string, ProtectedString> pair)
{
LinearLayout ees = (LinearLayout)LayoutInflater.Inflate(Resource.Layout.entry_edit_section, null);
RelativeLayout ees = (RelativeLayout)LayoutInflater.Inflate(Resource.Layout.entry_edit_section, null);
((TextView)ees.FindViewById(Resource.Id.title)).Text = pair.Key;
((TextView)ees.FindViewById(Resource.Id.title)).TextChanged += (sender, e) => State.EntryModified = true;
((TextView)ees.FindViewById(Resource.Id.value)).Text = pair.Value.ReadString();
@ -896,7 +913,7 @@ namespace keepass2android
private void FillData() {
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(currIconButton, Resources, App.Kp2a.GetDb().KpDatabase, State.Entry.IconId, State.Entry.CustomIconUuid);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(currIconButton, Resources, App.Kp2a.GetDb().KpDatabase, State.Entry.IconId, State.Entry.CustomIconUuid, false);
PopulateText(Resource.Id.entry_title, State.Entry.Strings.ReadSafe (PwDefs.TitleField));
PopulateText(Resource.Id.entry_user_name, State.Entry.Strings.ReadSafe (PwDefs.UserNameField));
@ -928,8 +945,7 @@ namespace keepass2android
}
else
{
FindViewById(Resource.Id.entry_override_url_label).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.entry_override_url).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.entry_override_url_container).Visibility = ViewStates.Gone;
}
if (App.Kp2a.GetDb().DatabaseFormat.SupportsTags)
@ -938,7 +954,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;
}
@ -1016,6 +1034,11 @@ namespace keepass2android
private void PopulateText(int viewId, String text) {
TextView tv = (TextView) FindViewById(viewId);
if (tv == null)
{
Kp2aLog.Log("Invalid viewId " + viewId);
return;
}
tv.Text = text;
tv.TextChanged += (sender, e) => {State.EntryModified = true;};
}

View File

@ -16,7 +16,7 @@ namespace keepass2android
[Activity(Label = "@string/app_name",
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
Theme = "@style/Base")]
Theme = "@style/MyTheme_ActionBar")]
[IntentFilter(new[] {"kp2a.action.ExportDatabaseActivity"}, Categories = new[] {Intent.CategoryDefault})]
public class ExportDatabaseActivity : LockCloseActivity
{
@ -62,7 +62,7 @@ namespace keepass2android
}
else
{
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
OnActivityResult,
defaultPath =>
{

View File

@ -1,18 +1,27 @@
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Content.Res;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Support.V4.Content;
using Android.Support.V7.App;
using Android.Text;
using Android.Util;
using Android.Views;
using Android.Widget;
using keepass2android.Io;
using keepass2android.view;
using AlertDialog = Android.App.AlertDialog;
using Object = Java.Lang.Object;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden , Theme="@style/NoTitleBar")]
public class FileStorageSelectionActivity : ListActivity
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_Blue")]
public class FileStorageSelectionActivity : AppCompatActivity
{
private readonly ActivityDesign _design;
@ -78,8 +87,59 @@ namespace keepass2android
return position;
}
public static float convertDpToPixel(float dp, Context context)
{
Resources resources = context.Resources;
DisplayMetrics metrics = resources.DisplayMetrics;
float px = dp * metrics.Density;
return px;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
Button btn;
if (convertView == null)
{ // if it's not recycled, initialize some attributes
btn = new Button(_context);
btn.LayoutParameters = new GridView.LayoutParams((int)convertDpToPixel(90, _context), (int)convertDpToPixel(110, _context));
btn.SetBackgroundResource(Resource.Drawable.storagetype_button_bg);
btn.SetPadding((int)convertDpToPixel(4, _context),
(int)convertDpToPixel(20, _context),
(int)convertDpToPixel(4, _context),
(int)convertDpToPixel(4, _context));
btn.SetTextSize(ComplexUnitType.Sp, 11);
btn.SetTextColor(new Color(115, 115, 115));
btn.SetSingleLine(false);
btn.Gravity = GravityFlags.Center;
btn.Click += (sender, args) => _context.OnItemSelected( (string) ((Button)sender).Tag);
}
else
{
btn = (Button)convertView;
}
var protocolId = _protocolIds[position];
btn.Tag = protocolId;
Drawable drawable = App.Kp2a.GetResourceDrawable("ic_storage_" + protocolId);
String title = App.Kp2a.GetResourceString("filestoragename_" + protocolId);
var str = new SpannableString(title);
btn.TextFormatted = str;
//var drawable = ContextCompat.GetDrawable(context, Resource.Drawable.Icon);
btn.SetCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
return btn;
#if NoNet
TODO: kp2a button
#endif
/*
if (_protocolIds[position] == "kp2a")
{
return new FileStorageViewKp2a(_context);
@ -89,7 +149,7 @@ namespace keepass2android
var view = new FileStorageView(_context, _protocolIds[position], position);
return view;
}
*/
}
@ -145,16 +205,32 @@ namespace keepass2android
SetContentView(Resource.Layout.filestorage_selection);
_fileStorageAdapter = new FileStorageAdapter(this);
ListAdapter = _fileStorageAdapter;
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);
ListView listView = FindViewById<ListView>(Android.Resource.Id.List);
listView.ItemClick +=
SupportActionBar.Title = RemoveTrailingColon(GetString(Resource.String.select_storage_type));
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetDisplayShowHomeEnabled(true);
toolbar.NavigationClick += (sender, args) => OnBackPressed();
_fileStorageAdapter = new FileStorageAdapter(this);
var gridView = FindViewById<GridView>(Resource.Id.gridview);
gridView.ItemClick +=
(sender, args) => OnItemSelected((string)_fileStorageAdapter.GetItem(args.Position));
//listView.ItemsCanFocus = true;
gridView.Adapter = _fileStorageAdapter;
}
protected override void OnResume()
private string RemoveTrailingColon(string str)
{
if (str.EndsWith(":"))
return str.Substring(0, str.Length - 1);
return str;
}
protected override void OnResume()
{
base.OnResume();
_design.ReapplyTheme();

View File

@ -0,0 +1,88 @@
using System;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Util;
namespace keepass2android
{
public class FixedDrawerLayout : Android.Support.V4.Widget.DrawerLayout
{
private bool _fitsSystemWindows;
protected FixedDrawerLayout(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public FixedDrawerLayout(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
}
public FixedDrawerLayout(Context context, IAttributeSet attrs)
: base(context, attrs)
{
}
public FixedDrawerLayout(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;
}
public struct MeasureArgs
{
public int ActualHeight;
public int ProposedHeight;
}
public event EventHandler<MeasureArgs> MeasureEvent;
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
MeasureArgs args;
args.ProposedHeight = MeasureSpec.GetSize(heightMeasureSpec);
args.ActualHeight = Height;
OnMeasureEvent(args);
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
}
protected virtual void OnMeasureEvent(MeasureArgs args)
{
var handler = MeasureEvent;
if (handler != null) handler(this, args);
}
}
}

View File

@ -26,8 +26,8 @@ using Android.Widget;
namespace keepass2android
{
[Activity (Label = "@string/app_name", Theme="@style/NoTitleBar")]
public class GeneratePasswordActivity : LockCloseActivity {
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme_ActionBar", WindowSoftInputMode = SoftInput.StateHidden)]
public class GeneratePasswordActivity : LockCloseActivity {
private readonly int[] _buttonIds = new[] {Resource.Id.btn_length6, Resource.Id.btn_length8, Resource.Id.btn_length12, Resource.Id.btn_length16};
public static void Launch(Activity act) {
@ -78,7 +78,7 @@ namespace keepass2android
genPassButton.Click += (sender, e) => {
String password = GeneratePassword();
EditText txtPassword = (EditText) FindViewById(Resource.Id.password);
EditText txtPassword = (EditText) FindViewById(Resource.Id.password_edit);
txtPassword.Text = password;
};
@ -86,7 +86,7 @@ namespace keepass2android
View acceptButton = FindViewById(Resource.Id.accept_button);
acceptButton.Click += (sender, e) => {
EditText password = (EditText) FindViewById(Resource.Id.password);
EditText password = (EditText) FindViewById(Resource.Id.password_edit);
Intent intent = new Intent();
intent.PutExtra("keepass2android.password.generated_password", password.Text);
@ -106,9 +106,12 @@ namespace keepass2android
};
EditText txtPasswordToSet = (EditText) FindViewById(Resource.Id.password);
EditText txtPasswordToSet = (EditText) FindViewById(Resource.Id.password_edit);
txtPasswordToSet.Text = GeneratePassword();
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
}
public String GeneratePassword() {
@ -157,6 +160,18 @@ namespace keepass2android
return password;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Android.Resource.Id.Home:
OnBackPressed();
return true;
}
return false;
}
}
}

View File

@ -26,11 +26,24 @@ using Android.Util;
using KeePassLib.Utility;
using keepass2android.view;
using Android.Content.PM;
using Android.Runtime;
using Android.Support.V4.View;
using Android.Support.V7.App;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden , Theme="@style/NoTitleBar")]
[MetaData("android.app.default_searchable",Value="keepass2android.search.SearchResults")]
//[IntentFilter(new[] { "android.intent.action.SEARCH" })]
//[MetaData("android.app.default_searchable", Value = "MaterialTest2.EntryEditActivity")]
//[MetaData("android.app.searchable", Resource = "@xml/searchable_mattest")]
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_ActionBar")]
//[MetaData("android.app.searchable", Resource = "@xml/searchable_mattest")]
//[MetaData("android.app.default_searchable",Value="keepass2android.search.SearchResults")]
[IntentFilter(new[] { "android.intent.action.SEARCH" })]
[MetaData("android.app.default_searchable", Value = "MaterialTest2.EntryEditActivity")]
[MetaData("android.app.searchable", Resource = "@xml/searchable_mattest")]
[IntentFilter(new string[]{"android.intent.action.SEARCH"})]
[MetaData("android.app.searchable",Resource=AppNames.Searchable)]
public class GroupActivity : GroupBaseActivity {
@ -77,21 +90,15 @@ namespace keepass2android
public override void SetupNormalButtons()
{
GroupView.SetNormalButtonVisibility(AddGroupEnabled, AddEntryEnabled);
GroupView.Invalidate();
SetNormalButtonVisibility(AddGroupEnabled, AddEntryEnabled);
}
private bool AddGroupEnabled
{
get { return App.Kp2a.GetDb().CanWrite; }
}
private bool AddEntryEnabled
protected override bool AddEntryEnabled
{
get { return App.Kp2a.GetDb().CanWrite && ((this.Group.ParentGroup != null) || App.Kp2a.GetDb().DatabaseFormat.CanHaveEntriesInRootGroup); }
}
protected override void OnCreate (Bundle savedInstanceState)
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
@ -123,26 +130,24 @@ namespace keepass2android
if (AddGroupEnabled) {
// Add Group button
View addGroup = FindViewById (Resource.Id.add_group);
View addGroup = FindViewById (Resource.Id.fabAddNewGroup);
addGroup.Click += (sender, e) => {
GroupEditActivity.Launch (this, Group);
};
}
if (AddEntryEnabled) {
// Add Entry button
View addEntry = FindViewById (Resource.Id.add_entry);
addEntry.Click += (sender, e) => {
EntryEditActivity.Launch (this, Group, AppTask);
};
if (AddEntryEnabled)
{
View addEntry = FindViewById (Resource.Id.fabAddNewEntry);
addEntry.Click += (sender, e) => { EntryEditActivity.Launch (this, Group, AppTask); };
}
SetGroupTitle();
SetGroupIcon();
ListAdapter = new PwGroupListAdapter(this, Group);
RegisterForContextMenu(ListView);
FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter = new PwGroupListAdapter(this, Group);
Log.Warn(Tag, "Finished creating group");
}
@ -158,8 +163,8 @@ namespace keepass2android
public override void OnBackPressed()
{
base.OnBackPressed();
if ((Group != null) && (Group.ParentGroup != null))
OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
//if ((Group != null) && (Group.ParentGroup != null))
//OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
}
public override bool OnContextItemSelected(IMenuItem item) {

View File

@ -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;
@ -33,11 +34,14 @@ using keepass2android.Io;
using keepass2android.database.edit;
using keepass2android.view;
using Android.Graphics.Drawables;
using Android.Support.V4.View;
using CursorAdapter = Android.Support.V4.Widget.CursorAdapter;
using Object = Java.Lang.Object;
namespace keepass2android
{
public abstract class GroupBaseActivity : LockCloseListActivity {
public abstract class GroupBaseActivity : LockCloseActivity {
public const String KeyEntry = "entry";
public const String KeyMode = "mode";
@ -65,9 +69,47 @@ namespace keepass2android
public virtual void SetupNormalButtons()
{
GroupView.SetNormalButtonVisibility(App.Kp2a.GetDb().CanWrite, App.Kp2a.GetDb().CanWrite);
SetNormalButtonVisibility(AddGroupEnabled, AddEntryEnabled);
}
protected virtual bool AddGroupEnabled
{
get { return App.Kp2a.GetDb().CanWrite; }
}
protected virtual bool AddEntryEnabled
{
get { return App.Kp2a.GetDb().CanWrite; }
}
public void SetNormalButtonVisibility(bool showAddGroup, bool showAddEntry)
{
//check for null in the following because the "empty" layouts may not have all views
if (FindViewById(Resource.Id.bottom_bar) != null)
FindViewById(Resource.Id.bottom_bar).Visibility = BottomBarAlwaysVisible ? ViewStates.Visible : ViewStates.Gone;
if (FindViewById(Resource.Id.divider2) != null)
FindViewById(Resource.Id.divider2).Visibility = BottomBarAlwaysVisible ? ViewStates.Visible : ViewStates.Gone;
if (FindViewById(Resource.Id.fabCancelAddNew) != null)
{
FindViewById(Resource.Id.fabCancelAddNew).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewGroup).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNew).Visibility = (showAddGroup || showAddEntry) ? ViewStates.Visible : ViewStates.Gone;
}
}
public virtual bool BottomBarAlwaysVisible
{
get { return false; }
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
@ -122,10 +164,12 @@ namespace keepass2android
protected PwGroup Group;
internal AppTask AppTask;
protected GroupView GroupView;
private String strCachedGroupUuid = null;
public String UuidGroup {
public String UuidGroup {
get {
if (strCachedGroupUuid == null) {
strCachedGroupUuid = MemUtil.ByteArrayToHexString (Group.Uuid.UuidBytes);
@ -155,24 +199,26 @@ namespace keepass2android
Database db = App.Kp2a.GetDb();
if ( db.Dirty.Contains(Group) ) {
db.Dirty.Remove(Group);
BaseAdapter adapter = (BaseAdapter) ListAdapter;
adapter.NotifyDataSetChanged();
ListAdapter.NotifyDataSetChanged();
}
}
protected override void OnListItemClick(ListView l, View v, int position, long id) {
base.OnListItemClick(l, v, position, id);
IListAdapter adapt = ListAdapter;
ClickView cv = (ClickView) adapt.GetView(position, null, null);
cv.OnClick();
}
protected override void OnCreate(Bundle savedInstanceState) {
public BaseAdapter ListAdapter
{
get { return (BaseAdapter) FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter; }
}
public virtual bool IsSearchResult
{
get { return false; }
}
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
@ -183,36 +229,63 @@ namespace keepass2android
_prefs = PreferenceManager.GetDefaultSharedPreferences(this);
GroupView = new GroupView(this);
SetContentView(GroupView);
FindViewById(Resource.Id.cancel_insert_element).Click += (sender, args) => StopMovingElement();
FindViewById(Resource.Id.insert_element).Click += (sender, args) => InsertElement();
SetResult(KeePass.ExitNormal);
StyleScrollBars();
SetContentView(ContentResourceId);
if (FindViewById(Resource.Id.fabCancelAddNew) != null)
{
FindViewById(Resource.Id.fabAddNew).Click += (sender, args) =>
{
FindViewById(Resource.Id.fabCancelAddNew).Visibility = ViewStates.Visible;
FindViewById(Resource.Id.fabAddNewGroup).Visibility = AddGroupEnabled ? ViewStates.Visible : ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewEntry).Visibility = AddEntryEnabled ? ViewStates.Visible : ViewStates.Gone;
FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Gone;
};
FindViewById(Resource.Id.fabCancelAddNew).Click += (sender, args) =>
{
FindViewById(Resource.Id.fabCancelAddNew).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewGroup).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Visible;
};
}
if (FindViewById(Resource.Id.cancel_insert_element) != null)
{
FindViewById(Resource.Id.cancel_insert_element).Click += (sender, args) => StopMovingElements();
FindViewById(Resource.Id.insert_element).Click += (sender, args) => InsertElements();
}
SetResult(KeePass.ExitNormal);
}
private void InsertElement()
protected virtual int ContentResourceId
{
MoveElementTask moveElementTask = (MoveElementTask)AppTask;
IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(moveElementTask.Uuid, true, null);
get { return Resource.Layout.group; }
}
private void InsertElements()
{
MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask;
IEnumerable<IStructureItem> 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();
}
protected void StyleScrollBars() {
ListView lv = ListView;
lv.ScrollBarStyle =ScrollbarStyles.InsideInset;
lv.TextFilterEnabled = true;
}
protected void SetGroupTitle()
@ -228,31 +301,33 @@ namespace keepass2android
titleText = GetText(Resource.String.root);
}
ActionBar.Title = titleText;
if (clickable)
ActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.Title = titleText;
if (clickable)
{
SupportActionBar.SetHomeButtonEnabled(true);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetDisplayShowHomeEnabled(true);
}
}
protected void SetGroupIcon() {
if (Group != null) {
Drawable drawable = App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(Resources, App.Kp2a.GetDb().KpDatabase, Group.IconId, Group.CustomIconUuid);
ImageView iv = (ImageView) FindViewById(Resource.Id.icon);
if (iv != null)
iv.SetImageDrawable(drawable);
if (Util.HasActionBar(this))
ActionBar.SetIcon(drawable);
Drawable drawable = App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(Resources, App.Kp2a.GetDb().KpDatabase, Group.IconId, Group.CustomIconUuid, true);
SupportActionBar.SetDisplayShowHomeEnabled(true);
//SupportActionBar.SetIcon(drawable);
}
}
class SuggestionListener: Java.Lang.Object, SearchView.IOnSuggestionListener
class SuggestionListener: Java.Lang.Object, SearchView.IOnSuggestionListener, Android.Support.V7.Widget.SearchView.IOnSuggestionListener
{
private readonly CursorAdapter _suggestionsAdapter;
private readonly GroupBaseActivity _activity;
private readonly IMenuItem _searchItem;
public SuggestionListener(CursorAdapter suggestionsAdapter, GroupBaseActivity activity, IMenuItem searchItem)
public SuggestionListener(Android.Support.V4.Widget.CursorAdapter suggestionsAdapter, GroupBaseActivity activity, IMenuItem searchItem)
{
_suggestionsAdapter = suggestionsAdapter;
_activity = activity;
@ -265,7 +340,6 @@ namespace keepass2android
cursor.MoveToPosition(position);
string entryIdAsHexString = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
EntryActivity.Launch(_activity, App.Kp2a.GetDb().Entries[new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString))],-1,_activity.AppTask);
((SearchView) _searchItem.ActionView).Iconified = true;
return true;
}
@ -275,7 +349,7 @@ namespace keepass2android
}
}
class OnQueryTextListener: Java.Lang.Object, SearchView.IOnQueryTextListener
class OnQueryTextListener: Java.Lang.Object, Android.Support.V7.Widget.SearchView.IOnQueryTextListener
{
private readonly GroupBaseActivity _activity;
@ -305,35 +379,37 @@ namespace keepass2android
return true;
}
}
public override bool OnCreateOptionsMenu(IMenu menu) {
base.OnCreateOptionsMenu(menu);
MenuInflater inflater = MenuInflater;
inflater.Inflate(Resource.Menu.group, menu);
if (Util.HasActionBar(this))
{
public override bool OnCreateOptionsMenu(IMenu menu) {
MenuInflater inflater = MenuInflater;
inflater.Inflate(Resource.Menu.group, menu);
var searchManager = (SearchManager)GetSystemService (Context.SearchService);
IMenuItem searchItem = menu.FindItem(Resource.Id.menu_search);
var searchView = (SearchView) searchItem.ActionView;
var view = MenuItemCompat.GetActionView(searchItem);
var searchView = view.JavaCast<Android.Support.V7.Widget.SearchView>();
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);
}
return base.OnCreateOptionsMenu(menu);
}
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;
}
public override bool OnPrepareOptionsMenu(IMenu menu) {
if ( ! base.OnPrepareOptionsMenu(menu) ) {
@ -376,7 +452,7 @@ namespace keepass2android
//http://developer.android.com/training/implementing-navigation/ancestral.html
AppTask.SetActivityResult(this, KeePass.ExitNormal);
Finish();
OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
//OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
return true;
}
@ -425,11 +501,11 @@ namespace keepass2android
if (!String.IsNullOrEmpty(message))
Toast.MakeText(this, message, ToastLength.Long).Show();
// Tell the adapter to refresh it's list
// Tell the adapter to refresh it's list
BaseAdapter adapter = (BaseAdapter)ListAdapter;
adapter.NotifyDataSetChanged();
if (App.Kp2a.GetDb().OtpAuxFileIoc != null)
if (App.Kp2a.GetDb().OtpAuxFileIoc != null)
{
var task2 = new SyncOtpAuxFile(App.Kp2a.GetDb().OtpAuxFileIoc);
new ProgressTask(App.Kp2a, this, task2).Run();
@ -486,6 +562,7 @@ namespace keepass2android
db.Dirty.Remove(Group);
// Tell the adapter to refresh it's list
BaseAdapter adapter = (BaseAdapter)ListAdapter;
adapter.NotifyDataSetChanged();
@ -537,10 +614,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;
@ -553,27 +630,36 @@ namespace keepass2android
}
public void StartMovingElement()
public void StartMovingElements()
{
ShowInsertElementButtons();
GroupView.ListView.InvalidateViews();
BaseAdapter adapter = (BaseAdapter)ListAdapter;
adapter.NotifyDataSetChanged();
ShowInsertElementsButtons();
BaseAdapter adapter = (BaseAdapter)ListAdapter;
adapter.NotifyDataSetChanged();
}
public void ShowInsertElementButtons()
public void ShowInsertElementsButtons()
{
GroupView.ShowInsertButtons();
FindViewById(Resource.Id.fabCancelAddNew).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewGroup).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.bottom_bar).Visibility = ViewStates.Visible;
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)
{
@ -583,7 +669,6 @@ namespace keepass2android
AppTask = new NullTask();
AppTask.SetupGroupBaseActivityButtons(this);
GroupView.ListView.InvalidateViews();
BaseAdapter adapter = (BaseAdapter)ListAdapter;
adapter.NotifyDataSetChanged();
}
@ -594,5 +679,186 @@ namespace keepass2android
GroupEditActivity.Launch(this, pwGroup.ParentGroup, pwGroup);
}
}
public class GroupListFragment : ListFragment, AbsListView.IMultiChoiceModeListener
{
private ActionMode _mode;
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
if (App.Kp2a.GetDb().CanWrite)
{
ListView.ChoiceMode = ChoiceMode.MultipleModal;
ListView.SetMultiChoiceModeListener(this);
ListView.ItemLongClick += delegate(object sender, AdapterView.ItemLongClickEventArgs args)
{
ListView.SetItemChecked(args.Position, true);
};
}
ListView.ItemClick += (sender, args) => ((GroupListItemView) args.View).OnClick();
StyleListView();
}
protected void StyleListView()
{
ListView lv = ListView;
lv.ScrollBarStyle =ScrollbarStyles.InsideInset;
lv.TextFilterEnabled = true;
lv.Divider = null;
}
public bool OnActionItemClicked(ActionMode mode, IMenuItem item)
{
var listView = FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListView;
var checkedItemPositions = listView.CheckedItemPositions;
List<IStructureItem> checkedItems = new List<IStructureItem>();
for (int i = 0; i < checkedItemPositions.Size(); i++)
{
if (checkedItemPositions.ValueAt(i))
{
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();
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:
var navMove = new NavigateToFolderAndLaunchMoveElementTask(checkedItems.First().ParentGroup, checkedItems.Select(i => i.Uuid).ToList(), ((GroupBaseActivity)Activity).IsSearchResult);
((GroupBaseActivity)Activity).StartTask(navMove);
break;
case Resource.Id.menu_navigate:
NavigateToFolder navNavigate = new NavigateToFolder(checkedItems.First().ParentGroup, true);
((GroupBaseActivity)Activity).StartTask(navNavigate);
break;
case Resource.Id.menu_edit:
GroupEditActivity.Launch(Activity, checkedItems.First().ParentGroup, (PwGroup) checkedItems.First());
break;
default:
return false;
}
listView.ClearChoices();
((BaseAdapter)ListAdapter).NotifyDataSetChanged();
if (_mode != null)
mode.Finish();
return true;
}
public bool OnCreateActionMode(ActionMode mode, IMenu menu)
{
MenuInflater inflater = Activity.MenuInflater;
inflater.Inflate(Resource.Menu.group_entriesselected, menu);
//mode.Title = "Select Items";
Android.Util.Log.Debug("KP2A", "Create action mode" + mode);
((PwGroupListAdapter) ListView.Adapter).InActionMode = true;
((PwGroupListAdapter)ListView.Adapter).NotifyDataSetChanged();
_mode = mode;
return true;
}
public void OnDestroyActionMode(ActionMode mode)
{
Android.Util.Log.Debug("KP2A", "Destroy action mode" + mode);
((PwGroupListAdapter)ListView.Adapter).InActionMode = true;
((PwGroupListAdapter)ListView.Adapter).NotifyDataSetChanged();
_mode = null;
}
public bool OnPrepareActionMode(ActionMode mode, IMenu menu)
{
Android.Util.Log.Debug("KP2A", "Prepare action mode" + mode);
((PwGroupListAdapter)ListView.Adapter).InActionMode = mode != null;
((PwGroupListAdapter)ListView.Adapter).NotifyDataSetChanged();
return true;
}
public void OnItemCheckedStateChanged(ActionMode mode, int position, long id, bool @checked)
{
var menuItem = mode.Menu.FindItem(Resource.Id.menu_edit);
if (menuItem != null)
{
menuItem.SetVisible(IsOnlyOneGroupChecked());
}
menuItem = mode.Menu.FindItem(Resource.Id.menu_navigate);
if (menuItem != null)
{
menuItem.SetVisible(((GroupBaseActivity)Activity).IsSearchResult && IsOnlyOneItemChecked());
}
}
private bool IsOnlyOneGroupChecked()
{
var checkedItems = ListView.CheckedItemPositions;
bool hadCheckedGroup = false;
if (checkedItems != null)
{
for (int i = 0; i < checkedItems.Size(); i++)
{
if (checkedItems.ValueAt(i))
{
if (hadCheckedGroup)
{
return false;
}
if (((PwGroupListAdapter) ListAdapter).IsGroupAtPosition(checkedItems.KeyAt(i)))
{
hadCheckedGroup = true;
}
else
{
return false;
}
}
}
}
return hadCheckedGroup;
}
private bool IsOnlyOneItemChecked()
{
var checkedItems = ListView.CheckedItemPositions;
bool hadCheckedItem = false;
if (checkedItems != null)
{
for (int i = 0; i < checkedItems.Size(); i++)
{
if (checkedItems.ValueAt(i))
{
if (hadCheckedItem)
{
return false;
}
hadCheckedItem = true;
}
}
}
return hadCheckedItem;
}
}
}

View File

@ -73,12 +73,13 @@ namespace keepass2android
SetContentView (Resource.Layout.group_edit);
ImageButton iconButton = (ImageButton)FindViewById (Resource.Id.icon_button);
iconButton.SetScaleType(ImageView.ScaleType.FitXy);
iconButton.Click += (sender, e) =>
{
IconPickerActivity.Launch (this);
};
_selectedIconId = (int) PwIcon.FolderOpen;
iconButton.SetImageResource(Icons.IconToResId((PwIcon)_selectedIconId));
iconButton.SetImageResource(Icons.IconToResId((PwIcon)_selectedIconId, true));
Button okButton = (Button)FindViewById (Resource.Id.ok);
okButton.Click += (sender, e) => {
@ -110,7 +111,7 @@ namespace keepass2android
_selectedCustomIconId = _groupToEdit.CustomIconUuid;
TextView nameField = (TextView)FindViewById(Resource.Id.group_name);
nameField.Text = _groupToEdit.Name;
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iconButton, Resources, App.Kp2a.GetDb().KpDatabase, _groupToEdit.IconId, _groupToEdit.CustomIconUuid);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iconButton, Resources, App.Kp2a.GetDb().KpDatabase, _groupToEdit.IconId, _groupToEdit.CustomIconUuid, false);
SetTitle(Resource.String.edit_group_title);
}
else
@ -137,7 +138,7 @@ namespace keepass2android
_selectedIconId = data.Extras.GetInt(IconPickerActivity.KeyIconId);
_selectedCustomIconId = PwUuid.Zero;
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
currIconButton.SetImageResource(Icons.IconToResId((PwIcon)_selectedIconId));
currIconButton.SetImageResource(Icons.IconToResId((PwIcon)_selectedIconId, false));
break;
}
}

View File

@ -18,13 +18,14 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
[Activity (Label = "@string/app_name", Theme="@style/NoTitleBar")]
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme_ActionBar")]
public class IconPickerActivity : LockCloseActivity
{
public const String KeyIconId = "icon_id";
@ -100,8 +101,10 @@ namespace keepass2android
TextView tv = (TextView) currView.FindViewById(Resource.Id.icon_text);
tv.Text = "" + position;
ImageView iv = (ImageView) currView.FindViewById(Resource.Id.icon_image);
iv.SetImageResource(Icons.IconToResId((KeePassLib.PwIcon)position));
iv.SetImageResource(Icons.IconToResId((KeePassLib.PwIcon)position, false));
Android.Graphics.PorterDuff.Mode mMode = Android.Graphics.PorterDuff.Mode.SrcAtop;
Color color = new Color(189, 189, 189);
iv.SetColorFilter(color, mMode);
return currView;
}
}

View File

@ -71,7 +71,7 @@ namespace keepass2android
/// <summary>
/// Launcher activity of Keepass2Android. This activity usually forwards to FileSelect but may show the revision dialog after installation or updates.
/// </summary>
[Activity (Label = AppNames.AppName, MainLauncher = true, Theme="@style/Base")]
[Activity(Label = AppNames.AppName, MainLauncher = true, Theme = "@style/MyTheme_Blue")]
public class KeePass : LifecycleDebugActivity
{
public const Result ExitNormal = Result.FirstUser;
@ -167,6 +167,9 @@ namespace keepass2android
{
}
#if DEBUG
showChangeLog = false;
#endif
if (showChangeLog)
{

View File

@ -19,11 +19,12 @@ using System;
using Android.App;
using Android.OS;
using Android.Runtime;
using Android.Support.V7.App;
namespace keepass2android
{
public abstract class LifecycleDebugActivity : Activity
public abstract class LifecycleDebugActivity : AppCompatActivity
{
protected LifecycleDebugActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)

View File

@ -16,14 +16,119 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using Android.Content.Res;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Preferences;
using Android.Support.V7.App;
using Android.Views;
using Java.Lang;
using keepass2android;
namespace keepass2android
{
public class AppCompatPreferenceActivity: PreferenceActivity
{
public AppCompatPreferenceActivity(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public AppCompatPreferenceActivity()
{
}
private AppCompatDelegate _appCompatDelegate;
AppCompatDelegate Delegate
{
get
{
if (_appCompatDelegate == null)
_appCompatDelegate = AppCompatDelegate.Create(this, null);
return _appCompatDelegate;
}
}
protected override void OnCreate(Bundle savedInstanceState)
{
Delegate.InstallViewFactory();
Delegate.OnCreate(savedInstanceState);
base.OnCreate(savedInstanceState);
}
public override MenuInflater MenuInflater
{
get { return Delegate.MenuInflater; }
}
public override void SetContentView(int layoutResId)
{
Delegate.SetContentView(layoutResId);
}
public override void SetContentView(View view) {
Delegate.SetContentView(view);
}
public override void SetContentView(View view, ViewGroup.LayoutParams @params) {
Delegate.SetContentView(view, @params);
}
public override void AddContentView(View view, ViewGroup.LayoutParams @params) {
Delegate.AddContentView(view, @params);
}
protected override void OnPostResume()
{
base.OnPostResume();
Delegate.OnPostResume();
}
protected override void OnTitleChanged(ICharSequence title, Color color)
{
base.OnTitleChanged(title, color);
Delegate.SetTitle(title);
}
public override void OnConfigurationChanged(Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
Delegate.OnConfigurationChanged(newConfig);
}
protected override void OnStop()
{
base.OnStop();
Delegate.OnStop();
}
protected override void OnDestroy()
{
base.OnDestroy();
Delegate.OnDestroy();
}
public override void InvalidateOptionsMenu()
{
Delegate.InvalidateOptionsMenu();
}
}
public class LockingPreferenceActivity : PreferenceActivity {
public class LockingPreferenceActivity : AppCompatPreferenceActivity {
public LockingPreferenceActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)

View File

@ -0,0 +1,64 @@
using System;
using Android.Content;
using Android.Runtime;
using Android.Util;
using Android.Widget;
namespace keepass2android
{
public class MeasuringRelativeLayout : RelativeLayout
{
protected MeasuringRelativeLayout(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public MeasuringRelativeLayout(Context context)
: base(context)
{
}
public MeasuringRelativeLayout(Context context, IAttributeSet attrs)
: base(context, attrs)
{
}
public MeasuringRelativeLayout(Context context, IAttributeSet attrs, int defStyleAttr)
: base(context, attrs, defStyleAttr)
{
}
public MeasuringRelativeLayout(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes)
: base(context, attrs, defStyleAttr, defStyleRes)
{
}
public class MeasureArgs
{
public int ActualHeight;
public int ProposedHeight;
}
public event EventHandler<MeasureArgs> MeasureEvent;
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
MeasureArgs args = new MeasureArgs();
args.ProposedHeight = MeasureSpec.GetSize(heightMeasureSpec);
args.ActualHeight = Height;
OnMeasureEvent(args);
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
}
protected virtual void OnMeasureEvent(MeasureArgs args)
{
var handler = MeasureEvent;
if (handler != null) handler(this, args);
}
}
}

View File

@ -34,6 +34,11 @@ using Java.Net;
using Android.Preferences;
using Android.Text;
using Android.Content.PM;
using Android.Graphics;
using Android.Support.Design.Widget;
using Android.Support.V4.Widget;
using Android.Support.V7.App;
using keepass2android;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using KeePassLib.Utility;
@ -41,22 +46,25 @@ using Keepass2android.Pluginsdk;
using OtpKeyProv;
using keepass2android.Io;
using keepass2android.Utils;
using Exception = System.Exception;
using File = Java.IO.File;
using FileNotFoundException = Java.IO.FileNotFoundException;
using MemoryStream = System.IO.MemoryStream;
using Object = Java.Lang.Object;
using Process = Android.OS.Process;
using String = System.String;
using KeeChallenge;
using AlertDialog = Android.App.AlertDialog;
using Toolbar = Android.Support.V7.Widget.Toolbar;
namespace keepass2android
{
[Activity(Label = "@string/app_name",
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
ConfigurationChanges = ConfigChanges.Orientation,
LaunchMode = LaunchMode.SingleInstance,
Theme = "@style/Base")]
public class PasswordActivity : LockingActivity {
WindowSoftInputMode = SoftInput.AdjustResize,
Theme = "@style/MyTheme_Blue")] /*caution: also contained in AndroidManifest.xml*/
public class PasswordActivity : LockingActivity {
enum KeyProviders
{
@ -141,20 +149,23 @@ namespace keepass2android
private const string KeyFileOrProviderKey = "KeyFileOrProviderKey";
private ActivityDesign _design;
private bool _performingLoad;
private bool _keepPasswordInOnResume;
private Typeface _passwordFont;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout _drawerLayout;
public PasswordActivity (IntPtr javaReference, JniHandleOwnership transfer)
public PasswordActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
_design = new ActivityDesign(this);
}
public PasswordActivity()
{
_design = new ActivityDesign(this);
}
@ -300,6 +311,8 @@ namespace keepass2android
{
if (KeyProviderType == KeyProviders.KeyFile)
{
//TODO: if the user has not yet selected a keyfile, _keyFileOrProvider is empty which
//gives an (unhandled) exception here
var iocKeyfile = IOConnectionInfo.UnserializeFromString(_keyFileOrProvider);
App.Kp2a.GetFileStorage(iocKeyfile)
@ -666,11 +679,68 @@ namespace keepass2android
}
}
int count = 1;
private DrawerLayout mDrawerLayout;
//private RecyclerView mDrawerList;
private string mDrawerTitle;
private MeasuringRelativeLayout.MeasureArgs _measureArgs;
internal class MyActionBarDrawerToggle : ActionBarDrawerToggle
{
PasswordActivity owner;
public MyActionBarDrawerToggle(PasswordActivity activity, DrawerLayout layout, int imgRes, int openRes, int closeRes)
: base(activity, layout, openRes, closeRes)
{
owner = activity;
}
public override void OnDrawerClosed(View drawerView)
{
owner.SupportActionBar.Title = owner.Title;
owner.InvalidateOptionsMenu();
}
public override void OnDrawerOpened(View drawerView)
{
owner.SupportActionBar.Title = owner.mDrawerTitle;
owner.InvalidateOptionsMenu();
}
}
private void UncollapseToolbar()
{
AppBarLayout appbarLayout = FindViewById<AppBarLayout>(Resource.Id.appbar);
var tmp = appbarLayout.LayoutParameters;
CoordinatorLayout.LayoutParams p = tmp.JavaCast<CoordinatorLayout.LayoutParams>();
var tmp2 = p.Behavior;
var behavior = tmp2.JavaCast<AppBarLayout.Behavior>();
if (behavior == null)
{
p.Behavior = behavior = new AppBarLayout.Behavior();
}
behavior.OnNestedFling(FindViewById<CoordinatorLayout>(Resource.Id.main_content), appbarLayout, null, 0, -10000, false);
}
private void CollapseToolbar()
{
AppBarLayout appbarLayout = FindViewById<AppBarLayout>(Resource.Id.appbar);
ViewGroup.LayoutParams tmp = appbarLayout.LayoutParameters;
CoordinatorLayout.LayoutParams p = tmp.JavaCast<CoordinatorLayout.LayoutParams>();
var tmp2 = p.Behavior;
var behavior = tmp2.JavaCast<AppBarLayout.Behavior>();
if (behavior == null)
{
p.Behavior = behavior = new AppBarLayout.Behavior();
}
behavior.OnNestedFling(FindViewById<CoordinatorLayout>(Resource.Id.main_content), appbarLayout, null, 0, 200, true);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_design.ApplyTheme();
//use FlagSecure to make sure the last (revealed) character of the master password is not visible in recent apps
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
GetString(Resource.String.ViewDatabaseSecure_key), true))
@ -678,8 +748,6 @@ namespace keepass2android
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
}
Intent i = Intent;
//only load the AppTask if this is the "first" OnCreate (not because of kill/resume, i.e. savedInstanceState==null)
@ -692,12 +760,12 @@ namespace keepass2android
}
else
{
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
}
String action = i.Action;
_prefs = PreferenceManager.GetDefaultSharedPreferences(this);
_rememberKeyfile = _prefs.GetBoolean(GetString(Resource.String.keyfile_key), Resources.GetBoolean(Resource.Boolean.keyfile_default));
@ -707,7 +775,7 @@ namespace keepass2android
if (action != null && action.Equals(ViewIntent))
{
if (!GetIocFromViewIntent(i)) return;
}
}
else if ((action != null) && (action.Equals(Intents.StartWithOtp)))
{
if (!GetIocFromOtpIntent(savedInstanceState, i)) return;
@ -745,46 +813,49 @@ namespace keepass2android
App.Kp2a.LockDatabase(false);
}
SetContentView(Resource.Layout.password);
InitializeToolbar();
InitializeFilenameView();
if (KeyProviderType == KeyProviders.KeyFile)
{
UpdateKeyfileIocView();
}
FindViewById<EditText>(Resource.Id.password).TextChanged +=
var passwordEdit = FindViewById<EditText>(Resource.Id.password_edit);
passwordEdit.TextChanged +=
(sender, args) =>
{
_password = FindViewById<EditText>(Resource.Id.password).Text;
_password = passwordEdit.Text;
UpdateOkButtonState();
};
FindViewById<EditText>(Resource.Id.password).EditorAction += (sender, args) =>
{
if ((args.ActionId == ImeAction.Done) || ((args.ActionId == ImeAction.ImeNull) && (args.Event.Action == KeyEventActions.Down)))
OnOk();
};
passwordEdit.EditorAction += (sender, args) =>
{
if ((args.ActionId == ImeAction.Done) || ((args.ActionId == ImeAction.ImeNull) && (args.Event.Action == KeyEventActions.Down)))
OnOk();
};
FindViewById<EditText>(Resource.Id.pass_otpsecret).TextChanged += (sender, args) => UpdateOkButtonState();
EditText passwordEdit = FindViewById<EditText>(Resource.Id.password);
passwordEdit.Text = _password;
passwordEdit.RequestFocus();
Window.SetSoftInputMode(SoftInput.StateVisible);
InitializeOkButton();
var passwordFont = Typeface.CreateFromAsset(Assets, "SourceCodePro-Regular.ttf");
passwordEdit.Typeface = passwordFont;
InitializeBottomBarButtons();
InitializePasswordModeSpinner();
InitializeOtpSecretSpinner();
InitializeNavDrawerButtons();
UpdateOkButtonState();
InitializeTogglePasswordButton();
InitializeKeyfileBrowseButton();
@ -798,9 +869,91 @@ namespace keepass2android
.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult, null), _ioConnection,
RequestCodePrepareDbFile, false);
}
mDrawerTitle = this.Title;
mDrawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
var rootview = FindViewById<MeasuringRelativeLayout>(Resource.Id.relative_layout);
rootview.ViewTreeObserver.GlobalLayout += (sender, args2) =>
{
Android.Util.Log.Debug("KP2A", "GlobalLayout");
var args = _measureArgs;
if (args == null)
return;
Android.Util.Log.Debug("KP2A", "ActualHeight=" + args.ActualHeight);
Android.Util.Log.Debug("KP2A", "ProposedHeight=" + args.ProposedHeight);
if (args.ActualHeight < args.ProposedHeight)
UncollapseToolbar();
if (args.ActualHeight > args.ProposedHeight)
CollapseToolbar();
};
rootview.MeasureEvent += (sender, args) =>
{
//Snackbar.Make(rootview, "height="+args.ActualHeight, Snackbar.LengthLong).Show();
this._measureArgs = args;
};
}
private void InitializeOtpSecretSpinner()
private void InitializeNavDrawerButtons()
{
FindViewById(Resource.Id.btn_nav_change_db).Click += (sender, args) =>
{
GoToFileSelectActivity();
};
FindViewById(Resource.Id.btn_nav_donate).Click += (sender, args) =>
{
Util.GotoDonateUrl(this);
};
FindViewById(Resource.Id.btn_nav_about).Click += (sender, args) =>
{
AboutDialog dialog = new AboutDialog(this);
dialog.Show();
};
FindViewById(Resource.Id.btn_nav_settings).Click += (sender, args) =>
{
AppSettingsActivity.Launch(this);
};
}
private void InitializeToolbar()
{
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);
var collapsingToolbar = FindViewById<CollapsingToolbarLayout>(Resource.Id.collapsing_toolbar);
collapsingToolbar.SetTitle(GetString(Resource.String.unlock_database_title));
_drawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, _drawerLayout,
Resource.String.menu_open,
Resource.String.menu_close);
_drawerLayout.SetDrawerListener(mDrawerToggle);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
mDrawerToggle.SyncState();
}
public override void OnBackPressed()
{
if (_drawerLayout.IsDrawerOpen((int) GravityFlags.Start))
{
_drawerLayout.CloseDrawer((int)GravityFlags.Start);
return;
}
base.OnBackPressed();
}
private void InitializeOtpSecretSpinner()
{
Spinner spinner = FindViewById<Spinner>(Resource.Id.otpsecret_format_spinner);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this, Android.Resource.Layout.SimpleSpinnerDropDownItem, EncodingUtil.Formats);
@ -892,13 +1045,15 @@ namespace keepass2android
return true;
}
private void InitializeOkButton()
private void InitializeBottomBarButtons()
{
Button confirmButton = (Button) FindViewById(Resource.Id.pass_ok);
confirmButton.Click += (sender, e) =>
{
OnOk();
};
FindViewById(Resource.Id.change_db).Click += (sender, args) => GoToFileSelectActivity();
}
private void OnOk()
@ -916,6 +1071,9 @@ namespace keepass2android
_showPassword = !_showPassword;
MakePasswordMaskedOrVisible();
};
Android.Graphics.PorterDuff.Mode mMode = Android.Graphics.PorterDuff.Mode.SrcAtop;
Color color = new Color (224, 224, 224);
btnTogglePassword.SetColorFilter (color, mMode);
}
private void InitializeKeyfileBrowseButton()
@ -974,11 +1132,7 @@ namespace keepass2android
RequestCodePrepareOtpAuxFile, false);
};
}
else
{
//android 2.x
//TODO test
}
}
private void RestoreState(Bundle savedInstanceState)
@ -989,7 +1143,7 @@ namespace keepass2android
MakePasswordMaskedOrVisible();
_keyFileOrProvider = savedInstanceState.GetString(KeyFileOrProviderKey);
_password = FindViewById<EditText>(Resource.Id.password).Text = savedInstanceState.GetString(PasswordKey);
_password = FindViewById<EditText>(Resource.Id.password_edit).Text = savedInstanceState.GetString(PasswordKey);
_pendingOtps = new List<string>(savedInstanceState.GetStringArrayList(PendingOtpsKey));
@ -1012,17 +1166,18 @@ namespace keepass2android
private void UpdateOkButtonState()
{
bool enabled = false;
switch (KeyProviderType)
{
case KeyProviders.None:
FindViewById(Resource.Id.pass_ok).Enabled = true;
enabled = true;
break;
case KeyProviders.KeyFile:
FindViewById(Resource.Id.pass_ok).Enabled = _keyFileOrProvider != "" || _password != "";
enabled = _keyFileOrProvider != "" || _password != "";
break;
case KeyProviders.Otp:
bool enabled = true;
enabled = true;
if (_otpInfo == null)
enabled = false;
else
@ -1040,18 +1195,20 @@ namespace keepass2android
}
}
FindViewById(Resource.Id.pass_ok).Enabled = enabled;
break;
case KeyProviders.OtpRecovery:
case KeyProviders.ChalRecovery:
FindViewById(Resource.Id.pass_ok).Enabled = FindViewById<EditText>(Resource.Id.pass_otpsecret).Text != "";
enabled = FindViewById<EditText>(Resource.Id.pass_otpsecret).Text != "";
break;
case KeyProviders.Challenge:
FindViewById(Resource.Id.pass_ok).Enabled = _challengeSecret != null;
enabled = _challengeSecret != null;
break;
default:
throw new ArgumentOutOfRangeException();
}
FindViewById(Resource.Id.pass_ok).Enabled = enabled;
}
private void UpdateKeyProviderUiState()
@ -1212,18 +1369,29 @@ namespace keepass2android
private void MakePasswordMaskedOrVisible()
{
TextView password = (TextView) FindViewById(Resource.Id.password);
TextView password = (TextView) FindViewById(Resource.Id.password_edit);
if (_showPassword)
{
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
SetPasswordTypeface(password);
}
else
{
password.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
}
}
private void SetNewDefaultFile()
private void SetPasswordTypeface(TextView textView)
{
if (_passwordFont == null)
{
_passwordFont = Typeface.CreateFromAsset(Assets, "SourceCodePro-Regular.ttf");
}
textView.Typeface = _passwordFont;
}
private void SetNewDefaultFile()
{
//Don't allow the current file to be the default if we don't have stored credentials
bool makeFileDefault;
@ -1331,7 +1499,7 @@ namespace keepass2android
outState.PutString(OtpInfoKey, sw.ToString());
}
//more OTP TODO:
// * Caching of aux file
// * -> implement IFileStorage in JavaFileStorage based on ListFiles
@ -1390,7 +1558,7 @@ namespace keepass2android
else
{
//assume the key should be used as static password
FindViewById<EditText>(Resource.Id.password).Text += otp;
FindViewById<EditText>(Resource.Id.password_edit).Text += otp;
}
@ -1402,7 +1570,12 @@ namespace keepass2android
{
base.OnResume();
_design.ReapplyTheme();
EditText pwd = FindViewById<EditText>(Resource.Id.password_edit);
pwd.PostDelayed(() =>
{
InputMethodManager keyboard = (InputMethodManager)GetSystemService(Context.InputMethodService);
keyboard.ShowSoftInput(pwd, 0);
}, 50);
View killButton = FindViewById(Resource.Id.kill_app);
if (PreferenceManager.GetDefaultSharedPreferences(this)
@ -1421,7 +1594,7 @@ namespace keepass2android
{
killButton.Visibility = ViewStates.Gone;
}
if (!_keepPasswordInOnResume)
{
if (
@ -1514,15 +1687,7 @@ namespace keepass2android
private void InitializeFilenameView() {
SetEditText(Resource.Id.filename, App.Kp2a.GetFileStorage(_ioConnection).GetDisplayName(_ioConnection));
if (App.Kp2a.FileDbHelper.NumberOfRecentFiles() < 2)
{
FindViewById(Resource.Id.filename_group).Visibility = ViewStates.Gone;
}
else
{
FindViewById(Resource.Id.filename_group).Visibility = ViewStates.Visible;
}
}
protected override void OnDestroy()
@ -1547,30 +1712,13 @@ namespace keepass2android
te.Text = str;
}
}
public override bool OnCreateOptionsMenu(IMenu menu) {
base.OnCreateOptionsMenu(menu);
MenuInflater inflate = MenuInflater;
inflate.Inflate(Resource.Menu.password, menu);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item) {
switch ( item.ItemId ) {
case Resource.Id.menu_about:
AboutDialog dialog = new AboutDialog(this);
dialog.Show();
return true;
case Resource.Id.menu_app_settings:
AppSettingsActivity.Launch(this);
return true;
case Resource.Id.menu_change_db:
GoToFileSelectActivity();
return true;
case Android.Resource.Id.Home:
_drawerLayout.OpenDrawer(Android.Support.V4.View.GravityCompat.Start);
return true;
}
return base.OnOptionsItemSelected(item);
@ -1643,7 +1791,7 @@ namespace keepass2android
private void ClearEnteredPassword()
{
SetEditText(Resource.Id.password, "");
SetEditText(Resource.Id.password_edit, "");
SetEditText(Resource.Id.pass_otpsecret, "");
foreach (int otpId in _otpTextViewIds)
{

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="46" android:versionName="0.9.3-release-3" package="keepass2android.keepass2android_debug" android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<permission android:description="@string/permission_desc" android:icon="@drawable/ic_launcher" android:label="KP2A internal file browsing" android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" android:protectionLevel="signature" />
<application android:label="keepass2android" android:icon="@drawable/ic_launcher">
@ -54,7 +54,7 @@
</intent-filter>
</activity>
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/Base" android:name="keepass2android.PasswordActivity">
<activity android:configChanges="orientation" android:label="@string/app_name" android:theme="@style/MyTheme_Blue" android:name="keepass2android.PasswordActivity" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />

View File

@ -11,7 +11,7 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/Base" android:name="keepass2android.PasswordActivity">
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/MyTheme" android:name="keepass2android.PasswordActivity">
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="59"
android:versionName="0.9.8b"
android:versionCode="57"
android:versionName="0.9.8 preview 2 (alpha)"
package="keepass2android.keepass2android"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
@ -57,7 +57,7 @@
</intent-filter>
</activity>
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/Base" android:name="keepass2android.PasswordActivity">
<activity android:configChanges="orientation" android:label="@string/app_name" android:theme="@style/MyTheme_Blue" android:name="keepass2android.PasswordActivity" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />

View File

@ -40,7 +40,7 @@
</intent-filter>
</activity>
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/Base" android:name="keepass2android.PasswordActivity">
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/MyTheme" android:name="keepass2android.PasswordActivity" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />

View File

@ -24,6 +24,7 @@ using Android.Widget;
using Android.Preferences;
using KeePassLib;
using keepass2android.view;
using KeePassLib.Interfaces;
namespace keepass2android
{
@ -212,6 +213,7 @@ namespace keepass2android
private List<PwGroup> _groupsForViewing;
private List<PwEntry> _entriesForViewing;
public bool InActionMode { get; set; }
public PwGroupListAdapter(GroupBaseActivity act, PwGroup group) {
@ -275,6 +277,11 @@ namespace keepass2android
public override Java.Lang.Object GetItem(int position) {
return position;
}
public bool IsGroupAtPosition(int position)
{
return position < _groupsForViewing.Count;
}
public override long GetItemId(int position) {
return position;
@ -282,15 +289,18 @@ namespace keepass2android
public override View GetView(int position, View convertView, ViewGroup parent) {
int size = _groupsForViewing.Count;
GroupListItemView view;
if ( position < size ) {
return CreateGroupView(position, convertView);
view = CreateGroupView(position, convertView);
} else {
return CreateEntryView(position - size, convertView);
view = CreateEntryView(position - size, convertView);
}
view.SetRightArrowVisibility(!InActionMode);
return view;
}
private View CreateGroupView(int position, View convertView) {
private PwGroupView CreateGroupView(int position, View convertView) {
PwGroup g = _groupsForViewing[position];
PwGroupView gv;
@ -321,7 +331,18 @@ namespace keepass2android
return ev;
}
public IStructureItem GetItemAtPosition(int keyAt)
{
if (keyAt < _groupsForViewing.Count)
{
return _groupsForViewing[keyAt];
}
else
{
return _entriesForViewing[keyAt - _groupsForViewing.Count];
}
}
}
}

View File

@ -16,7 +16,7 @@ namespace keepass2android
{
[Activity(Label = "@string/app_name",
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
Theme = "@style/Base")]
Theme = "@style/MyTheme_ActionBar")]
[IntentFilter(new[] { Strings.ActionQueryCredentials},
Categories = new[] { Intent.CategoryDefault })]
[IntentFilter(new[] { Strings.ActionQueryCredentialsForOwnPackage },

View File

@ -24,30 +24,31 @@ using Android.Widget;
using Android.Content.PM;
using KeePassLib.Keys;
using Android.Preferences;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Views.InputMethods;
using KeePassLib.Serialization;
namespace keepass2android
{
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
Theme = "@style/Base")]
[Activity(Label = "@string/app_name",
ConfigurationChanges = ConfigChanges.Orientation,
WindowSoftInputMode = SoftInput.AdjustResize,
MainLauncher = false,
Theme = "@style/MyTheme_Blue")]
public class QuickUnlock : LifecycleDebugActivity
{
private IOConnectionInfo _ioc;
private QuickUnlockBroadcastReceiver _intentReceiver;
private ActivityDesign _design;
public QuickUnlock()
{
_design = new ActivityDesign(this);
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
_design.ApplyTheme();
//use FlagSecure to make sure the last (revealed) character of the password is not visible in recent apps
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
GetString(Resource.String.ViewDatabaseSecure_key), true))
@ -63,13 +64,12 @@ namespace keepass2android
return;
}
SetContentView(Resource.Layout.QuickUnlock);
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 = "*****";
}
}
@ -104,6 +104,8 @@ namespace keepass2android
OnUnlock(quickUnlockLength, pwd);
};
Button btnLock = (Button) FindViewById(Resource.Id.QuickUnlock_buttonLock);
btnLock.Click += (object sender, EventArgs e) =>
{
@ -120,8 +122,10 @@ namespace keepass2android
IntentFilter filter = new IntentFilter();
filter.AddAction(Intents.DatabaseLocked);
RegisterReceiver(_intentReceiver, filter);
}
private void OnUnlock(int quickUnlockLength, EditText pwd)
{
KcpPassword kcpPassword = (KcpPassword) App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof (KcpPassword));
@ -148,9 +152,7 @@ namespace keepass2android
protected override void OnResume()
{
base.OnResume();
_design.ReapplyTheme();
CheckIfUnloaded();
EditText pwd = (EditText) FindViewById(Resource.Id.QuickUnlock_password);

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="0%" android:toXDelta="-100%"
<translate android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="400"/>
</set>

View File

@ -2,7 +2,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="250" />
</set>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Some files were not shown because too many files have changed in this diff Show More