Merge branch 'MaterialDesign'
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2012
|
# 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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "keepass2android", "keepass2android\keepass2android.csproj", "{A6CF8A86-37C1-4197-80FE-519DE2C842F5}"
|
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
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\ZlibAndroid.csproj", "{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\ZlibAndroid.csproj", "{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialTest2", "MaterialTest2\MaterialTest2.csproj", "{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -333,6 +337,7 @@ Global
|
|||||||
{A5F8FB02-00E0-4335-91EF-AEAA2C2F3C48}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
|
{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.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.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.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.Build.0 = Debug|Any CPU
|
||||||
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.Deploy.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|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|x64.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
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
||||||
|
@ -111,7 +111,7 @@ namespace KeePassLib
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default number of master key encryption/transformation rounds (making dictionary attacks harder).
|
/// Default number of master key encryption/transformation rounds (making dictionary attacks harder).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const ulong DefaultKeyEncryptionRounds = 6000;
|
public const ulong DefaultKeyEncryptionRounds = 500000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default identifier string for the title field. Should not contain
|
/// Default identifier string for the title field. Should not contain
|
||||||
|
@ -7,9 +7,9 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
public interface IDrawableFactory
|
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();
|
void Clear();
|
||||||
|
@ -55,8 +55,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="database\CheckDatabaseForChanges.cs" />
|
<Compile Include="database\CheckDatabaseForChanges.cs" />
|
||||||
|
<Compile Include="database\edit\DeleteMultipleItems.cs" />
|
||||||
<Compile Include="database\edit\EditGroup.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\KdbDatabaseFormat.cs" />
|
||||||
<Compile Include="database\KdbxDatabaseFormat.cs" />
|
<Compile Include="database\KdbxDatabaseFormat.cs" />
|
||||||
<Compile Include="database\PwEntryOutput.cs" />
|
<Compile Include="database\PwEntryOutput.cs" />
|
||||||
|
@ -21,10 +21,10 @@ namespace keepass2android
|
|||||||
WriteDemanded = 2
|
WriteDemanded = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
protected const int RequestCodeFileStorageSelectionForPrimarySelect = 983713;
|
protected const int RequestCodeFileStorageSelectionForPrimarySelect = 33713;
|
||||||
private const int RequestCodeFileStorageSelectionForCopyToWritableLocation = 983714;
|
private const int RequestCodeFileStorageSelectionForCopyToWritableLocation = 33714;
|
||||||
private const int RequestCodeFileFileBrowseForWritableLocation = 983715;
|
private const int RequestCodeFileFileBrowseForWritableLocation = 33715;
|
||||||
private const int RequestCodeFileBrowseForOpen = 983716;
|
private const int RequestCodeFileBrowseForOpen = 33716;
|
||||||
|
|
||||||
|
|
||||||
protected IOConnectionInfo _selectedIoc;
|
protected IOConnectionInfo _selectedIoc;
|
||||||
|
@ -57,6 +57,8 @@ namespace keepass2android
|
|||||||
CopyFileRequiredForEditing,
|
CopyFileRequiredForEditing,
|
||||||
DuplicateUuidsError,
|
DuplicateUuidsError,
|
||||||
DuplicateUuidsErrorAdditional,
|
DuplicateUuidsErrorAdditional,
|
||||||
KdbBetaWarning
|
KdbBetaWarning,
|
||||||
|
DeletingItems,
|
||||||
|
AskDeletePermanentlyItems
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,17 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
|
using KeePassLib.Interfaces;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
public class DeleteEntry : DeleteRunnable {
|
public class DeleteEntry : DeleteRunnable {
|
||||||
|
|
||||||
private readonly PwEntry _entry;
|
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;
|
Ctx = ctx;
|
||||||
@ -48,77 +51,16 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Run()
|
protected override void PerformDelete(List<PwGroup> touchedGroups, List<PwGroup> permanentlyDeletedGroups)
|
||||||
{
|
{
|
||||||
StatusLogger.UpdateMessage(UiStringKey.DeletingEntry);
|
DoDeleteEntry(_entry, touchedGroups);
|
||||||
PwDatabase pd = Db.KpDatabase;
|
|
||||||
|
|
||||||
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);
|
public override UiStringKey StatusMessage
|
||||||
|
{
|
||||||
|
get { return UiStringKey.DeletingEntry; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit database
|
|
||||||
SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, false);
|
|
||||||
save.SetStatusLogger(StatusLogger);
|
|
||||||
save.Run();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
|
|
||||||
@ -68,95 +69,14 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void PerformDelete(List<PwGroup> touchedGroups, List<PwGroup> permanentlyDeletedGroups)
|
||||||
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);
|
DoDeleteGroup(_group, touchedGroups, permanentlyDeletedGroups);
|
||||||
|
|
||||||
PwDeletedObject pdo = new PwDeletedObject(pg.Uuid, DateTime.Now);
|
|
||||||
pd.DeletedObjects.Add(pdo);
|
|
||||||
_onFinishToRun = new AfterDeletePermanently(OnFinishToRun, App, _group);
|
|
||||||
}
|
}
|
||||||
else // Recycle
|
|
||||||
|
public override UiStringKey StatusMessage
|
||||||
{
|
{
|
||||||
bool groupListUpdateRequired = false;
|
get { return UiStringKey.DeletingGroup; }
|
||||||
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);
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
79
src/Kp2aBusinessLogic/database/edit/DeleteMultipleItems.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
|
|
||||||
@ -5,7 +7,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
public abstract class DeleteRunnable : RunnableOnFinish
|
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;
|
||||||
}
|
}
|
||||||
@ -44,24 +47,33 @@ namespace keepass2android
|
|||||||
|
|
||||||
protected bool CanRecycleGroup(PwGroup pgParent)
|
protected bool CanRecycleGroup(PwGroup pgParent)
|
||||||
{
|
{
|
||||||
bool bShiftPressed = false;
|
|
||||||
PwDatabase pd = Db.KpDatabase;
|
PwDatabase pd = Db.KpDatabase;
|
||||||
PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
|
PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
|
||||||
bool bPermanent = false;
|
bool bPermanent = false;
|
||||||
if (pgParent != null)
|
if (pgParent != null)
|
||||||
{
|
{
|
||||||
if (pd.RecycleBinEnabled == false)
|
if (pd.RecycleBinEnabled == false)
|
||||||
|
{
|
||||||
|
Android.Util.Log.Debug("KP2A", "CanRecycle? No, RecycleBinIsNotEnabled");
|
||||||
bPermanent = true;
|
bPermanent = true;
|
||||||
else if (bShiftPressed)
|
}
|
||||||
bPermanent = true;
|
|
||||||
else if (pgRecycleBin == null)
|
else if (pgRecycleBin == null)
|
||||||
{
|
{
|
||||||
} // Recycle
|
} // Recycle
|
||||||
else if (pgParent == pgRecycleBin)
|
else if (pgParent == pgRecycleBin)
|
||||||
|
{
|
||||||
|
Android.Util.Log.Debug("KP2A", "CanRecycle? No, Can't recycle RecycleBin");
|
||||||
bPermanent = true;
|
bPermanent = true;
|
||||||
|
}
|
||||||
|
|
||||||
else if (pgParent.IsContainedIn(pgRecycleBin))
|
else if (pgParent.IsContainedIn(pgRecycleBin))
|
||||||
|
{
|
||||||
|
Android.Util.Log.Debug("KP2A", "CanRecycle? No, "+pgParent.Name+" is in RecycleBin");
|
||||||
bPermanent = true;
|
bPermanent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return !bPermanent;
|
return !bPermanent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,12 +83,12 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
if ((Db == null) || (Db.KpDatabase == null)) { return; }
|
if ((Db == null) || (Db.KpDatabase == null)) { return; }
|
||||||
|
|
||||||
if(pgRecycleBin == Db.KpDatabase.RootGroup)
|
if (pgRecycleBin == Db.KpDatabase.RootGroup)
|
||||||
{
|
{
|
||||||
pgRecycleBin = null;
|
pgRecycleBin = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pgRecycleBin == null)
|
if (pgRecycleBin == null)
|
||||||
{
|
{
|
||||||
pgRecycleBin = new PwGroup(true, true, App.GetResourceString(UiStringKey.RecycleBin),
|
pgRecycleBin = new PwGroup(true, true, App.GetResourceString(UiStringKey.RecycleBin),
|
||||||
PwIcon.TrashBin)
|
PwIcon.TrashBin)
|
||||||
@ -112,23 +124,142 @@ namespace keepass2android
|
|||||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
},
|
},
|
||||||
(dlgSender, dlgEvt) => {
|
(dlgSender, dlgEvt) =>
|
||||||
|
{
|
||||||
DeletePermanently = false;
|
DeletePermanently = false;
|
||||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
},
|
},
|
||||||
(dlgSender, dlgEvt) => {},
|
(dlgSender, dlgEvt) => { },
|
||||||
Ctx);
|
Ctx);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
99
src/Kp2aBusinessLogic/database/edit/MoveElements.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,12 +9,12 @@ namespace Kp2aUnitTests
|
|||||||
{
|
{
|
||||||
internal class TestDrawableFactory : IDrawableFactory
|
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);
|
return res.GetDrawable(Resource.Drawable.Icon);
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,10 @@ namespace MasterKeePlugin
|
|||||||
_showPassword = !_showPassword;
|
_showPassword = !_showPassword;
|
||||||
MakePasswordMaskedOrVisible();
|
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)
|
FindViewById(Resource.Id.button_ok).Click += delegate(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
|
10
src/MaterialTest/Resources/layout/toolbar.xml
Normal 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" />
|
10
src/MaterialTest/Resources/layout/toolbar2.xml
Normal 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" />
|
14
src/MaterialTest/Resources/values-v21/styles.xml
Normal 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>
|
22
src/MaterialTest/Resources/values/styles.xml
Normal 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>
|
||||||
|
|
7
src/MaterialTest/packages.config
Normal 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>
|
19
src/MaterialTest2/Assets/AboutAssets.txt
Normal 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");
|
214
src/MaterialTest2/MainActivity.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
267
src/MaterialTest2/MaterialTest2.csproj
Normal 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>
|
5
src/MaterialTest2/Properties/AndroidManifest.xml
Normal 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>
|
28
src/MaterialTest2/Properties/AssemblyInfo.cs
Normal 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("")]
|
||||||
|
|
44
src/MaterialTest2/Resources/AboutResources.txt
Normal 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.
|
BIN
src/MaterialTest2/Resources/drawable-xhdpi/ic_dashboard.png
Normal file
After Width: | Height: | Size: 132 B |
BIN
src/MaterialTest2/Resources/drawable-xhdpi/ic_discuss.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
src/MaterialTest2/Resources/drawable-xhdpi/ic_done.png
Normal file
After Width: | Height: | Size: 297 B |
BIN
src/MaterialTest2/Resources/drawable-xhdpi/ic_event.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
src/MaterialTest2/Resources/drawable-xhdpi/ic_forum.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
src/MaterialTest2/Resources/drawable-xhdpi/ic_headset.png
Normal file
After Width: | Height: | Size: 488 B |
BIN
src/MaterialTest2/Resources/drawable-xhdpi/ic_menu.png
Normal file
After Width: | Height: | Size: 135 B |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
@ -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>
|
69
src/MaterialTest2/Resources/layout/Mainold.axml
Normal 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>
|
33
src/MaterialTest2/Resources/layout/nav_header.xml
Normal 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>
|
14
src/MaterialTest2/Resources/layout/toolbar2.xml
Normal 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>
|
31
src/MaterialTest2/Resources/values-v21/styles.xml
Normal 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>
|
14
src/MaterialTest2/Resources/values/Strings.xml
Normal 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>
|
5
src/MaterialTest2/Resources/values/dimens.xml
Normal 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>
|
188
src/MaterialTest2/Resources/values/styles.xml
Normal 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>
|
||||||
|
|
6
src/MaterialTest2/packages.config
Normal 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>
|
@ -10,8 +10,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
[Activity(Label = "@string/app_name",
|
[Activity(Label = "@string/app_name",
|
||||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
||||||
Theme = "@style/NoTitleBar")]
|
Theme = "@style/MyTheme_ActionBar")]
|
||||||
[IntentFilter(new[] { "kp2a.action.AboutActivity" }, Categories = new[] { Intent.CategoryDefault })]
|
[IntentFilter(new[] { "keepass2android.AboutActivity" }, Categories = new[] { Intent.CategoryDefault })]
|
||||||
public class AboutActivity: Activity, IDialogInterfaceOnDismissListener
|
public class AboutActivity: Activity, IDialogInterfaceOnDismissListener
|
||||||
{
|
{
|
||||||
private AboutDialog _dialog;
|
private AboutDialog _dialog;
|
||||||
|
@ -5,6 +5,7 @@ using Android.Content.PM;
|
|||||||
using Android.Graphics.Drawables;
|
using Android.Graphics.Drawables;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Preferences;
|
using Android.Preferences;
|
||||||
|
using Android.Support.V7.App;
|
||||||
using Android.Text;
|
using Android.Text;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
@ -19,8 +20,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
[Activity(Label = "@string/app_name",
|
[Activity(Label = "@string/app_name",
|
||||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
||||||
Theme = "@style/Base")]
|
Theme = "@style/MyTheme_ActionBar")]
|
||||||
public class CreateDatabaseActivity : Activity
|
public class CreateDatabaseActivity : AppCompatActivity
|
||||||
{
|
{
|
||||||
private IOConnectionInfo _ioc;
|
private IOConnectionInfo _ioc;
|
||||||
private string _keyfileFilename;
|
private string _keyfileFilename;
|
||||||
@ -57,6 +58,9 @@ namespace keepass2android
|
|||||||
base.OnCreate(bundle);
|
base.OnCreate(bundle);
|
||||||
_design.ApplyTheme();
|
_design.ApplyTheme();
|
||||||
|
|
||||||
|
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||||
|
SupportActionBar.SetHomeButtonEnabled(true);
|
||||||
|
|
||||||
SetContentView(Resource.Layout.create_database);
|
SetContentView(Resource.Layout.create_database);
|
||||||
_appTask = AppTask.GetTaskInOnCreate(bundle, Intent);
|
_appTask = AppTask.GetTaskInOnCreate(bundle, Intent);
|
||||||
|
|
||||||
@ -140,6 +144,9 @@ namespace keepass2android
|
|||||||
_showPassword = !_showPassword;
|
_showPassword = !_showPassword;
|
||||||
MakePasswordMaskedOrVisible();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,7 +14,7 @@ using KeePassLib.Utility;
|
|||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
[Activity(Label = AppNames.AppName, Theme = "@style/Base")]
|
[Activity(Label = AppNames.AppName, Theme = "@style/MyTheme_ActionBar")]
|
||||||
public class DonateReminder : Activity
|
public class DonateReminder : Activity
|
||||||
{
|
{
|
||||||
class Reminder
|
class Reminder
|
||||||
@ -59,16 +59,16 @@ namespace keepass2android
|
|||||||
};
|
};
|
||||||
yield return new Reminder
|
yield return new Reminder
|
||||||
{
|
{
|
||||||
From = new DateTime(2015, 09, 16),
|
From = new DateTime(2017, 09, 16),
|
||||||
To = new DateTime(2015, 10, 04),
|
To = new DateTime(2017, 10, 04),
|
||||||
Key = "DonationOktoberfest2017"
|
Key = "DonationOktoberfest2017b"//b because year was incorrectly set to 2015 in 0.9.8b
|
||||||
,ResourceToShow = Resource.Layout.donate
|
,ResourceToShow = Resource.Layout.donate
|
||||||
};
|
};
|
||||||
yield return new Reminder
|
yield return new Reminder
|
||||||
{
|
{
|
||||||
From = new DateTime(2015, 09, 22),
|
From = new DateTime(2018, 09, 22),
|
||||||
To = new DateTime(2015, 10, 08),
|
To = new DateTime(2018, 10, 08),
|
||||||
Key = "DonationOktoberfest2018"
|
Key = "DonationOktoberfest2018b"//b because year was incorrectly set to 2015 in 0.9.8b
|
||||||
,ResourceToShow = Resource.Layout.donate
|
,ResourceToShow = Resource.Layout.donate
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,7 +44,8 @@ using Uri = Android.Net.Uri;
|
|||||||
namespace keepass2android
|
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 class EntryActivity : LockCloseActivity
|
||||||
{
|
{
|
||||||
public const String KeyEntry = "entry";
|
public const String KeyEntry = "entry";
|
||||||
@ -125,28 +126,6 @@ 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 class PluginActionReceiver : BroadcastReceiver
|
||||||
{
|
{
|
||||||
@ -329,8 +308,9 @@ namespace keepass2android
|
|||||||
_showPassword =
|
_showPassword =
|
||||||
!prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
|
!prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
|
||||||
|
|
||||||
base.OnCreate(savedInstanceState);
|
|
||||||
RequestWindowFeature(WindowFeatures.IndeterminateProgress);
|
RequestWindowFeature(WindowFeatures.IndeterminateProgress);
|
||||||
|
base.OnCreate(savedInstanceState);
|
||||||
|
|
||||||
|
|
||||||
new ActivityDesign(this).ApplyTheme();
|
new ActivityDesign(this).ApplyTheme();
|
||||||
|
|
||||||
@ -375,7 +355,6 @@ namespace keepass2android
|
|||||||
FillData();
|
FillData();
|
||||||
|
|
||||||
SetupEditButtons();
|
SetupEditButtons();
|
||||||
SetupMoveButtons ();
|
|
||||||
|
|
||||||
App.Kp2a.GetDb().LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.GetDb().KpDatabase);
|
App.Kp2a.GetDb().LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.GetDb().KpDatabase);
|
||||||
|
|
||||||
@ -455,12 +434,14 @@ namespace keepass2android
|
|||||||
private void PopulateExtraStrings()
|
private void PopulateExtraStrings()
|
||||||
{
|
{
|
||||||
ViewGroup extraGroup = (ViewGroup) FindViewById(Resource.Id.extra_strings);
|
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))
|
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);
|
var stringView = CreateExtraSection(pair.Key, pair.Value.ReadString(), pair.Value.IsProtected);
|
||||||
extraGroup.AddView(stringView.View);
|
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)
|
private ExtraStringView CreateExtraSection(string key, string value, bool isProtected)
|
||||||
@ -676,7 +657,7 @@ namespace keepass2android
|
|||||||
if (extension != null)
|
if (extension != null)
|
||||||
{
|
{
|
||||||
MimeTypeMap mime = MimeTypeMap.Singleton;
|
MimeTypeMap mime = MimeTypeMap.Singleton;
|
||||||
type = mime.GetMimeTypeFromExtension(extension);
|
type = mime.GetMimeTypeFromExtension(extension.ToLowerInvariant());
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@ -684,13 +665,13 @@ namespace keepass2android
|
|||||||
public override void OnBackPressed()
|
public override void OnBackPressed()
|
||||||
{
|
{
|
||||||
base.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()
|
protected void FillData()
|
||||||
{
|
{
|
||||||
_protectedTextViews = new List<TextView>();
|
_protectedTextViews = new List<TextView>();
|
||||||
ImageView iv = (ImageView) FindViewById(Resource.Id.entry_icon);
|
ImageView iv = (ImageView) FindViewById(Resource.Id.icon);
|
||||||
if (iv != null)
|
if (iv != null)
|
||||||
{
|
{
|
||||||
iv.SetImageDrawable(Resources.GetDrawable(Resource.Drawable.ic00));
|
iv.SetImageDrawable(Resources.GetDrawable(Resource.Drawable.ic00));
|
||||||
@ -698,8 +679,9 @@ namespace keepass2android
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
ActionBar.Title = Entry.Strings.ReadSafe(PwDefs.TitleField);
|
SupportActionBar.Title = Entry.Strings.ReadSafe(PwDefs.TitleField);
|
||||||
ActionBar.SetDisplayHomeAsUpEnabled(true);
|
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||||
|
SupportActionBar.SetHomeButtonEnabled(true);
|
||||||
|
|
||||||
PopulateGroupText (Resource.Id.entry_group_name, Resource.Id.entryfield_group_container, KeyGroupFullPath);
|
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);
|
PopulateStandardText(Resource.Id.entry_comment, Resource.Id.entryfield_container_comment, PwDefs.NotesField);
|
||||||
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.comment_container),
|
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_tags, Resource.Id.entryfield_container_tags, concatTags(Entry.Tags));
|
||||||
PopulateText(Resource.Id.entry_override_url, Resource.Id.entryfield_container_overrideurl, Entry.OverrideUrl);
|
PopulateText(Resource.Id.entry_override_url, Resource.Id.entryfield_container_overrideurl, Entry.OverrideUrl);
|
||||||
@ -914,6 +896,8 @@ namespace keepass2android
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void UpdateTogglePasswordMenu()
|
private void UpdateTogglePasswordMenu()
|
||||||
{
|
{
|
||||||
IMenuItem togglePassword = _menu.FindItem(Resource.Id.menu_toggle_pass);
|
IMenuItem togglePassword = _menu.FindItem(Resource.Id.menu_toggle_pass);
|
||||||
@ -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:
|
//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
|
//http://developer.android.com/training/implementing-navigation/ancestral.html
|
||||||
Finish();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace keepass2android
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
//return new TextDrawable("\uF06E", _activity);
|
//return new TextDrawable("\uF06E", _activity);
|
||||||
return _activity.Resources.GetDrawable(Resource.Drawable.ic_action_eye_open);
|
return _activity.Resources.GetDrawable(Resource.Drawable.ic_menu_view);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,13 @@ using KeePassLib.Security;
|
|||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using Android.Util;
|
||||||
using File = System.IO.File;
|
using File = System.IO.File;
|
||||||
using Uri = Android.Net.Uri;
|
using Uri = Android.Net.Uri;
|
||||||
|
|
||||||
namespace keepass2android
|
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 class EntryEditActivity : LockCloseActivity {
|
||||||
public const String KeyEntry = "entry";
|
public const String KeyEntry = "entry";
|
||||||
public const String KeyParent = "parent";
|
public const String KeyParent = "parent";
|
||||||
@ -206,7 +207,7 @@ namespace keepass2android
|
|||||||
if (State.SelectedIcon)
|
if (State.SelectedIcon)
|
||||||
{
|
{
|
||||||
//TODO: custom image
|
//TODO: custom image
|
||||||
iconButton.SetImageResource(Icons.IconToResId(State.SelectedIconId));
|
iconButton.SetImageResource(Icons.IconToResId(State.SelectedIconId, false));
|
||||||
}
|
}
|
||||||
iconButton.Click += (sender, evt) => {
|
iconButton.Click += (sender, evt) => {
|
||||||
UpdateEntryFromUi(State.Entry);
|
UpdateEntryFromUi(State.Entry);
|
||||||
@ -215,8 +216,8 @@ namespace keepass2android
|
|||||||
|
|
||||||
|
|
||||||
// Generate password button
|
// Generate password button
|
||||||
Button generatePassword = (Button)FindViewById(Resource.Id.generate_button);
|
FindViewById(Resource.Id.generate_button).Click += (sender, e) =>
|
||||||
generatePassword.Click += (sender, e) => {
|
{
|
||||||
UpdateEntryFromUi(State.Entry);
|
UpdateEntryFromUi(State.Entry);
|
||||||
GeneratePasswordActivity.Launch(this);
|
GeneratePasswordActivity.Launch(this);
|
||||||
};
|
};
|
||||||
@ -225,20 +226,19 @@ namespace keepass2android
|
|||||||
|
|
||||||
|
|
||||||
// Save button
|
// Save button
|
||||||
ActionBar.SetCustomView(Resource.Layout.SaveButton);
|
//SupportActionBar.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();
|
|
||||||
};
|
|
||||||
|
|
||||||
FindViewById(Resource.Id.entry_save_cancel).Click += (sender, args) => Finish();
|
if (State.IsNew)
|
||||||
|
{
|
||||||
|
SupportActionBar.Title = GetString(Resource.String.add_entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SupportActionBar.Title = GetString(Resource.String.edit_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||||
|
SupportActionBar.SetHomeButtonEnabled(true);
|
||||||
|
|
||||||
// Respect mask password setting
|
// Respect mask password setting
|
||||||
MakePasswordVisibleOrHidden();
|
MakePasswordVisibleOrHidden();
|
||||||
@ -249,6 +249,9 @@ namespace keepass2android
|
|||||||
State.ShowPassword = !State.ShowPassword;
|
State.ShowPassword = !State.ShowPassword;
|
||||||
MakePasswordVisibleOrHidden();
|
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);
|
Button addButton = (Button) FindViewById(Resource.Id.add_advanced);
|
||||||
@ -258,7 +261,7 @@ namespace keepass2android
|
|||||||
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
|
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
|
||||||
|
|
||||||
KeyValuePair<string, ProtectedString> pair = new KeyValuePair<string, ProtectedString>("" , new ProtectedString(true, ""));
|
KeyValuePair<string, ProtectedString> pair = new KeyValuePair<string, ProtectedString>("" , new ProtectedString(true, ""));
|
||||||
LinearLayout ees = CreateExtraStringView(pair);
|
View ees = CreateExtraStringView(pair);
|
||||||
container.AddView(ees);
|
container.AddView(ees);
|
||||||
|
|
||||||
State.EntryModified = true;
|
State.EntryModified = true;
|
||||||
@ -669,13 +672,13 @@ namespace keepass2android
|
|||||||
//somehow after re-creating the activity. Maybe a Mono for Android bug?
|
//somehow after re-creating the activity. Maybe a Mono for Android bug?
|
||||||
Intent intent = Intent;
|
Intent intent = Intent;
|
||||||
intent.PutExtra(IntentContinueWithEditing, true);
|
intent.PutExtra(IntentContinueWithEditing, true);
|
||||||
OverridePendingTransition(0, 0);
|
//OverridePendingTransition(0, 0);
|
||||||
intent.AddFlags(ActivityFlags.NoAnimation | ActivityFlags.ForwardResult);
|
intent.AddFlags(ActivityFlags.NoAnimation | ActivityFlags.ForwardResult);
|
||||||
_closeForReload = true;
|
_closeForReload = true;
|
||||||
SetResult(KeePass.ExitRefreshTitle); //probably the entry will be modified -> let the EditActivity refresh to be safe
|
SetResult(KeePass.ExitRefreshTitle); //probably the entry will be modified -> let the EditActivity refresh to be safe
|
||||||
Finish();
|
Finish();
|
||||||
|
|
||||||
OverridePendingTransition(0, 0);
|
//OverridePendingTransition(0, 0);
|
||||||
StartActivity(intent);
|
StartActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,9 +748,11 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
label = "<attachment>";
|
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) =>
|
binaryButton.Click += (sender, e) =>
|
||||||
{
|
{
|
||||||
State.EntryModified = true;
|
State.EntryModified = true;
|
||||||
@ -760,9 +765,13 @@ namespace keepass2android
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button addBinaryButton = new Button(this) {Text = GetString(Resource.String.add_binary)};
|
//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);
|
//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);
|
||||||
|
|
||||||
addBinaryButton.Enabled = true;
|
addBinaryButton.Enabled = true;
|
||||||
|
|
||||||
if (!App.Kp2a.GetDb().DatabaseFormat.CanHaveMultipleAttachments)
|
if (!App.Kp2a.GetDb().DatabaseFormat.CanHaveMultipleAttachments)
|
||||||
addBinaryButton.Enabled = !State.Entry.Binaries.Any();
|
addBinaryButton.Enabled = !State.Entry.Binaries.Any();
|
||||||
addBinaryButton.Click += (sender, e) =>
|
addBinaryButton.Click += (sender, e) =>
|
||||||
@ -795,14 +804,19 @@ namespace keepass2android
|
|||||||
|
|
||||||
public override bool OnOptionsItemSelected(IMenuItem item) {
|
public override bool OnOptionsItemSelected(IMenuItem item) {
|
||||||
switch ( item.ItemId ) {
|
switch ( item.ItemId ) {
|
||||||
case Resource.Id.menu_donate:
|
case Resource.Id.menu_save:
|
||||||
return Util.GotoDonateUrl(this);
|
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void UpdateExpires()
|
void UpdateExpires()
|
||||||
@ -819,15 +833,18 @@ namespace keepass2android
|
|||||||
FindViewById(Resource.Id.entry_expires).Enabled = State.Entry.Expires;
|
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);
|
UpdateEntryFromUi(State.Entry);
|
||||||
return this;
|
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)).Text = pair.Key;
|
||||||
((TextView)ees.FindViewById(Resource.Id.title)).TextChanged += (sender, e) => State.EntryModified = true;
|
((TextView)ees.FindViewById(Resource.Id.title)).TextChanged += (sender, e) => State.EntryModified = true;
|
||||||
((TextView)ees.FindViewById(Resource.Id.value)).Text = pair.Value.ReadString();
|
((TextView)ees.FindViewById(Resource.Id.value)).Text = pair.Value.ReadString();
|
||||||
@ -896,7 +913,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
private void FillData() {
|
private void FillData() {
|
||||||
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
|
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_title, State.Entry.Strings.ReadSafe (PwDefs.TitleField));
|
||||||
PopulateText(Resource.Id.entry_user_name, State.Entry.Strings.ReadSafe (PwDefs.UserNameField));
|
PopulateText(Resource.Id.entry_user_name, State.Entry.Strings.ReadSafe (PwDefs.UserNameField));
|
||||||
@ -928,8 +945,7 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FindViewById(Resource.Id.entry_override_url_label).Visibility = ViewStates.Gone;
|
FindViewById(Resource.Id.entry_override_url_container).Visibility = ViewStates.Gone;
|
||||||
FindViewById(Resource.Id.entry_override_url).Visibility = ViewStates.Gone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (App.Kp2a.GetDb().DatabaseFormat.SupportsTags)
|
if (App.Kp2a.GetDb().DatabaseFormat.SupportsTags)
|
||||||
@ -938,7 +954,9 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
else
|
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;
|
FindViewById(Resource.Id.entry_tags).Visibility = ViewStates.Gone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,6 +1034,11 @@ namespace keepass2android
|
|||||||
|
|
||||||
private void PopulateText(int viewId, String text) {
|
private void PopulateText(int viewId, String text) {
|
||||||
TextView tv = (TextView) FindViewById(viewId);
|
TextView tv = (TextView) FindViewById(viewId);
|
||||||
|
if (tv == null)
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("Invalid viewId " + viewId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
tv.Text = text;
|
tv.Text = text;
|
||||||
tv.TextChanged += (sender, e) => {State.EntryModified = true;};
|
tv.TextChanged += (sender, e) => {State.EntryModified = true;};
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
[Activity(Label = "@string/app_name",
|
[Activity(Label = "@string/app_name",
|
||||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
||||||
Theme = "@style/Base")]
|
Theme = "@style/MyTheme_ActionBar")]
|
||||||
[IntentFilter(new[] {"kp2a.action.ExportDatabaseActivity"}, Categories = new[] {Intent.CategoryDefault})]
|
[IntentFilter(new[] {"kp2a.action.ExportDatabaseActivity"}, Categories = new[] {Intent.CategoryDefault})]
|
||||||
public class ExportDatabaseActivity : LockCloseActivity
|
public class ExportDatabaseActivity : LockCloseActivity
|
||||||
{
|
{
|
||||||
|
@ -1,18 +1,27 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
|
using Android.Content.Res;
|
||||||
|
using Android.Graphics;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
|
using Android.Support.V4.Content;
|
||||||
|
using Android.Support.V7.App;
|
||||||
|
using Android.Text;
|
||||||
|
using Android.Util;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using keepass2android.Io;
|
using keepass2android.Io;
|
||||||
using keepass2android.view;
|
using keepass2android.view;
|
||||||
|
using AlertDialog = Android.App.AlertDialog;
|
||||||
using Object = Java.Lang.Object;
|
using Object = Java.Lang.Object;
|
||||||
|
|
||||||
namespace keepass2android
|
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_Blue")]
|
||||||
public class FileStorageSelectionActivity : ListActivity
|
public class FileStorageSelectionActivity : AppCompatActivity
|
||||||
{
|
{
|
||||||
private readonly ActivityDesign _design;
|
private readonly ActivityDesign _design;
|
||||||
|
|
||||||
@ -78,8 +87,59 @@ namespace keepass2android
|
|||||||
return position;
|
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)
|
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")
|
if (_protocolIds[position] == "kp2a")
|
||||||
{
|
{
|
||||||
return new FileStorageViewKp2a(_context);
|
return new FileStorageViewKp2a(_context);
|
||||||
@ -89,7 +149,7 @@ namespace keepass2android
|
|||||||
var view = new FileStorageView(_context, _protocolIds[position], position);
|
var view = new FileStorageView(_context, _protocolIds[position], position);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,13 +205,29 @@ namespace keepass2android
|
|||||||
|
|
||||||
SetContentView(Resource.Layout.filestorage_selection);
|
SetContentView(Resource.Layout.filestorage_selection);
|
||||||
|
|
||||||
_fileStorageAdapter = new FileStorageAdapter(this);
|
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
|
||||||
ListAdapter = _fileStorageAdapter;
|
|
||||||
|
|
||||||
ListView listView = FindViewById<ListView>(Android.Resource.Id.List);
|
SetSupportActionBar(toolbar);
|
||||||
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));
|
(sender, args) => OnItemSelected((string)_fileStorageAdapter.GetItem(args.Position));
|
||||||
//listView.ItemsCanFocus = true;
|
gridView.Adapter = _fileStorageAdapter;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private string RemoveTrailingColon(string str)
|
||||||
|
{
|
||||||
|
if (str.EndsWith(":"))
|
||||||
|
return str.Substring(0, str.Length - 1);
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnResume()
|
protected override void OnResume()
|
||||||
|
88
src/keepass2android/FixedDrawerLayout.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ using Android.Widget;
|
|||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
[Activity (Label = "@string/app_name", Theme="@style/NoTitleBar")]
|
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme_ActionBar", WindowSoftInputMode = SoftInput.StateHidden)]
|
||||||
public class GeneratePasswordActivity : LockCloseActivity {
|
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};
|
private readonly int[] _buttonIds = new[] {Resource.Id.btn_length6, Resource.Id.btn_length8, Resource.Id.btn_length12, Resource.Id.btn_length16};
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ namespace keepass2android
|
|||||||
genPassButton.Click += (sender, e) => {
|
genPassButton.Click += (sender, e) => {
|
||||||
String password = GeneratePassword();
|
String password = GeneratePassword();
|
||||||
|
|
||||||
EditText txtPassword = (EditText) FindViewById(Resource.Id.password);
|
EditText txtPassword = (EditText) FindViewById(Resource.Id.password_edit);
|
||||||
txtPassword.Text = password;
|
txtPassword.Text = password;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
View acceptButton = FindViewById(Resource.Id.accept_button);
|
View acceptButton = FindViewById(Resource.Id.accept_button);
|
||||||
acceptButton.Click += (sender, e) => {
|
acceptButton.Click += (sender, e) => {
|
||||||
EditText password = (EditText) FindViewById(Resource.Id.password);
|
EditText password = (EditText) FindViewById(Resource.Id.password_edit);
|
||||||
|
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.PutExtra("keepass2android.password.generated_password", password.Text);
|
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();
|
txtPasswordToSet.Text = GeneratePassword();
|
||||||
|
|
||||||
|
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||||
|
SupportActionBar.SetHomeButtonEnabled(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String GeneratePassword() {
|
public String GeneratePassword() {
|
||||||
@ -157,6 +160,18 @@ namespace keepass2android
|
|||||||
|
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override bool OnOptionsItemSelected(IMenuItem item)
|
||||||
|
{
|
||||||
|
switch (item.ItemId)
|
||||||
|
{
|
||||||
|
case Android.Resource.Id.Home:
|
||||||
|
OnBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,24 @@ using Android.Util;
|
|||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
using keepass2android.view;
|
using keepass2android.view;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Support.V4.View;
|
||||||
|
using Android.Support.V7.App;
|
||||||
|
|
||||||
namespace keepass2android
|
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"})]
|
[IntentFilter(new string[]{"android.intent.action.SEARCH"})]
|
||||||
[MetaData("android.app.searchable",Resource=AppNames.Searchable)]
|
[MetaData("android.app.searchable",Resource=AppNames.Searchable)]
|
||||||
public class GroupActivity : GroupBaseActivity {
|
public class GroupActivity : GroupBaseActivity {
|
||||||
@ -77,20 +90,14 @@ namespace keepass2android
|
|||||||
|
|
||||||
public override void SetupNormalButtons()
|
public override void SetupNormalButtons()
|
||||||
{
|
{
|
||||||
GroupView.SetNormalButtonVisibility(AddGroupEnabled, AddEntryEnabled);
|
SetNormalButtonVisibility(AddGroupEnabled, AddEntryEnabled);
|
||||||
GroupView.Invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AddGroupEnabled
|
protected override bool AddEntryEnabled
|
||||||
{
|
|
||||||
get { return App.Kp2a.GetDb().CanWrite; }
|
|
||||||
}
|
|
||||||
private bool AddEntryEnabled
|
|
||||||
{
|
{
|
||||||
get { return App.Kp2a.GetDb().CanWrite && ((this.Group.ParentGroup != null) || App.Kp2a.GetDb().DatabaseFormat.CanHaveEntriesInRootGroup); }
|
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);
|
base.OnCreate (savedInstanceState);
|
||||||
@ -123,26 +130,24 @@ namespace keepass2android
|
|||||||
|
|
||||||
if (AddGroupEnabled) {
|
if (AddGroupEnabled) {
|
||||||
// Add Group button
|
// Add Group button
|
||||||
View addGroup = FindViewById (Resource.Id.add_group);
|
View addGroup = FindViewById (Resource.Id.fabAddNewGroup);
|
||||||
addGroup.Click += (sender, e) => {
|
addGroup.Click += (sender, e) => {
|
||||||
GroupEditActivity.Launch (this, Group);
|
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();
|
SetGroupTitle();
|
||||||
SetGroupIcon();
|
SetGroupIcon();
|
||||||
|
|
||||||
ListAdapter = new PwGroupListAdapter(this, Group);
|
FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter = new PwGroupListAdapter(this, Group);
|
||||||
RegisterForContextMenu(ListView);
|
|
||||||
Log.Warn(Tag, "Finished creating group");
|
Log.Warn(Tag, "Finished creating group");
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -158,8 +163,8 @@ namespace keepass2android
|
|||||||
public override void OnBackPressed()
|
public override void OnBackPressed()
|
||||||
{
|
{
|
||||||
base.OnBackPressed();
|
base.OnBackPressed();
|
||||||
if ((Group != null) && (Group.ParentGroup != null))
|
//if ((Group != null) && (Group.ParentGroup != null))
|
||||||
OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
|
//OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnContextItemSelected(IMenuItem item) {
|
public override bool OnContextItemSelected(IMenuItem item) {
|
||||||
|
@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
@ -33,11 +34,14 @@ using keepass2android.Io;
|
|||||||
using keepass2android.database.edit;
|
using keepass2android.database.edit;
|
||||||
using keepass2android.view;
|
using keepass2android.view;
|
||||||
using Android.Graphics.Drawables;
|
using Android.Graphics.Drawables;
|
||||||
|
using Android.Support.V4.View;
|
||||||
|
using CursorAdapter = Android.Support.V4.Widget.CursorAdapter;
|
||||||
|
using Object = Java.Lang.Object;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
|
|
||||||
public abstract class GroupBaseActivity : LockCloseListActivity {
|
public abstract class GroupBaseActivity : LockCloseActivity {
|
||||||
public const String KeyEntry = "entry";
|
public const String KeyEntry = "entry";
|
||||||
public const String KeyMode = "mode";
|
public const String KeyMode = "mode";
|
||||||
|
|
||||||
@ -65,9 +69,47 @@ namespace keepass2android
|
|||||||
|
|
||||||
public virtual void SetupNormalButtons()
|
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)
|
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||||
{
|
{
|
||||||
base.OnActivityResult(requestCode, resultCode, data);
|
base.OnActivityResult(requestCode, resultCode, data);
|
||||||
@ -122,9 +164,11 @@ namespace keepass2android
|
|||||||
protected PwGroup Group;
|
protected PwGroup Group;
|
||||||
|
|
||||||
internal AppTask AppTask;
|
internal AppTask AppTask;
|
||||||
protected GroupView GroupView;
|
|
||||||
|
|
||||||
private String strCachedGroupUuid = null;
|
private String strCachedGroupUuid = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public String UuidGroup {
|
public String UuidGroup {
|
||||||
get {
|
get {
|
||||||
if (strCachedGroupUuid == null) {
|
if (strCachedGroupUuid == null) {
|
||||||
@ -155,24 +199,26 @@ namespace keepass2android
|
|||||||
Database db = App.Kp2a.GetDb();
|
Database db = App.Kp2a.GetDb();
|
||||||
if ( db.Dirty.Contains(Group) ) {
|
if ( db.Dirty.Contains(Group) ) {
|
||||||
db.Dirty.Remove(Group);
|
db.Dirty.Remove(Group);
|
||||||
BaseAdapter adapter = (BaseAdapter) ListAdapter;
|
ListAdapter.NotifyDataSetChanged();
|
||||||
adapter.NotifyDataSetChanged();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnListItemClick(ListView l, View v, int position, long id) {
|
public BaseAdapter ListAdapter
|
||||||
base.OnListItemClick(l, v, position, id);
|
{
|
||||||
|
get { return (BaseAdapter) FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter; }
|
||||||
IListAdapter adapt = ListAdapter;
|
}
|
||||||
ClickView cv = (ClickView) adapt.GetView(position, null, null);
|
|
||||||
cv.OnClick();
|
|
||||||
|
|
||||||
|
public virtual bool IsSearchResult
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnCreate(Bundle savedInstanceState) {
|
protected override void OnCreate(Bundle savedInstanceState) {
|
||||||
base.OnCreate(savedInstanceState);
|
base.OnCreate(savedInstanceState);
|
||||||
|
|
||||||
|
Android.Util.Log.Debug("KP2A", "Creating GBA");
|
||||||
|
|
||||||
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
|
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
|
||||||
|
|
||||||
// Likely the app has been killed exit the activity
|
// Likely the app has been killed exit the activity
|
||||||
@ -183,36 +229,63 @@ namespace keepass2android
|
|||||||
|
|
||||||
_prefs = PreferenceManager.GetDefaultSharedPreferences(this);
|
_prefs = PreferenceManager.GetDefaultSharedPreferences(this);
|
||||||
|
|
||||||
GroupView = new GroupView(this);
|
|
||||||
SetContentView(GroupView);
|
|
||||||
|
|
||||||
FindViewById(Resource.Id.cancel_insert_element).Click += (sender, args) => StopMovingElement();
|
SetContentView(ContentResourceId);
|
||||||
FindViewById(Resource.Id.insert_element).Click += (sender, args) => InsertElement();
|
|
||||||
|
|
||||||
SetResult(KeePass.ExitNormal);
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
StyleScrollBars();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InsertElement()
|
|
||||||
|
if (FindViewById(Resource.Id.cancel_insert_element) != null)
|
||||||
{
|
{
|
||||||
MoveElementTask moveElementTask = (MoveElementTask)AppTask;
|
FindViewById(Resource.Id.cancel_insert_element).Click += (sender, args) => StopMovingElements();
|
||||||
IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(moveElementTask.Uuid, true, null);
|
FindViewById(Resource.Id.insert_element).Click += (sender, args) => InsertElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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();}));
|
SetResult(KeePass.ExitNormal);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual int ContentResourceId
|
||||||
|
{
|
||||||
|
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 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);
|
var progressTask = new ProgressTask(App.Kp2a, this, moveElement);
|
||||||
progressTask.Run();
|
progressTask.Run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void StyleScrollBars() {
|
|
||||||
ListView lv = ListView;
|
|
||||||
lv.ScrollBarStyle =ScrollbarStyles.InsideInset;
|
|
||||||
lv.TextFilterEnabled = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void SetGroupTitle()
|
protected void SetGroupTitle()
|
||||||
@ -228,31 +301,33 @@ namespace keepass2android
|
|||||||
titleText = GetText(Resource.String.root);
|
titleText = GetText(Resource.String.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionBar.Title = titleText;
|
SupportActionBar.Title = titleText;
|
||||||
if (clickable)
|
if (clickable)
|
||||||
ActionBar.SetDisplayHomeAsUpEnabled(true);
|
{
|
||||||
|
SupportActionBar.SetHomeButtonEnabled(true);
|
||||||
|
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||||
|
SupportActionBar.SetDisplayShowHomeEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void SetGroupIcon() {
|
protected void SetGroupIcon() {
|
||||||
if (Group != null) {
|
if (Group != null) {
|
||||||
Drawable drawable = App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(Resources, App.Kp2a.GetDb().KpDatabase, Group.IconId, Group.CustomIconUuid);
|
Drawable drawable = App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(Resources, App.Kp2a.GetDb().KpDatabase, Group.IconId, Group.CustomIconUuid, true);
|
||||||
ImageView iv = (ImageView) FindViewById(Resource.Id.icon);
|
SupportActionBar.SetDisplayShowHomeEnabled(true);
|
||||||
if (iv != null)
|
//SupportActionBar.SetIcon(drawable);
|
||||||
iv.SetImageDrawable(drawable);
|
|
||||||
if (Util.HasActionBar(this))
|
|
||||||
ActionBar.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 CursorAdapter _suggestionsAdapter;
|
||||||
private readonly GroupBaseActivity _activity;
|
private readonly GroupBaseActivity _activity;
|
||||||
private readonly IMenuItem _searchItem;
|
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;
|
_suggestionsAdapter = suggestionsAdapter;
|
||||||
_activity = activity;
|
_activity = activity;
|
||||||
@ -265,7 +340,6 @@ namespace keepass2android
|
|||||||
cursor.MoveToPosition(position);
|
cursor.MoveToPosition(position);
|
||||||
string entryIdAsHexString = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
|
string entryIdAsHexString = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
|
||||||
EntryActivity.Launch(_activity, App.Kp2a.GetDb().Entries[new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString))],-1,_activity.AppTask);
|
EntryActivity.Launch(_activity, App.Kp2a.GetDb().Entries[new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString))],-1,_activity.AppTask);
|
||||||
((SearchView) _searchItem.ActionView).Iconified = true;
|
|
||||||
return 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;
|
private readonly GroupBaseActivity _activity;
|
||||||
|
|
||||||
@ -307,20 +381,19 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnCreateOptionsMenu(IMenu menu) {
|
public override bool OnCreateOptionsMenu(IMenu menu) {
|
||||||
base.OnCreateOptionsMenu(menu);
|
|
||||||
|
|
||||||
MenuInflater inflater = MenuInflater;
|
MenuInflater inflater = MenuInflater;
|
||||||
inflater.Inflate(Resource.Menu.group, menu);
|
inflater.Inflate(Resource.Menu.group, menu);
|
||||||
if (Util.HasActionBar(this))
|
|
||||||
{
|
|
||||||
var searchManager = (SearchManager)GetSystemService (Context.SearchService);
|
var searchManager = (SearchManager)GetSystemService (Context.SearchService);
|
||||||
IMenuItem searchItem = menu.FindItem(Resource.Id.menu_search);
|
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.SetSearchableInfo (searchManager.GetSearchableInfo (ComponentName));
|
||||||
searchView.SetOnSuggestionListener(new SuggestionListener(searchView.SuggestionsAdapter, this, searchItem));
|
searchView.SetOnSuggestionListener(new SuggestionListener(searchView.SuggestionsAdapter, this, searchItem));
|
||||||
searchView.SetOnQueryTextListener(new OnQueryTextListener(this));
|
searchView.SetOnQueryTextListener(new OnQueryTextListener(this));
|
||||||
}
|
|
||||||
|
|
||||||
var item = menu.FindItem(Resource.Id.menu_sync);
|
var item = menu.FindItem(Resource.Id.menu_sync);
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
@ -330,11 +403,14 @@ namespace keepass2android
|
|||||||
item.SetVisible(true);
|
item.SetVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
|
return base.OnCreateOptionsMenu(menu);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public override bool OnPrepareOptionsMenu(IMenu menu) {
|
public override bool OnPrepareOptionsMenu(IMenu menu) {
|
||||||
if ( ! base.OnPrepareOptionsMenu(menu) ) {
|
if ( ! base.OnPrepareOptionsMenu(menu) ) {
|
||||||
return false;
|
return false;
|
||||||
@ -376,7 +452,7 @@ namespace keepass2android
|
|||||||
//http://developer.android.com/training/implementing-navigation/ancestral.html
|
//http://developer.android.com/training/implementing-navigation/ancestral.html
|
||||||
AppTask.SetActivityResult(this, KeePass.ExitNormal);
|
AppTask.SetActivityResult(this, KeePass.ExitNormal);
|
||||||
Finish();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -486,6 +562,7 @@ namespace keepass2android
|
|||||||
db.Dirty.Remove(Group);
|
db.Dirty.Remove(Group);
|
||||||
|
|
||||||
// Tell the adapter to refresh it's list
|
// Tell the adapter to refresh it's list
|
||||||
|
|
||||||
BaseAdapter adapter = (BaseAdapter)ListAdapter;
|
BaseAdapter adapter = (BaseAdapter)ListAdapter;
|
||||||
adapter.NotifyDataSetChanged();
|
adapter.NotifyDataSetChanged();
|
||||||
|
|
||||||
@ -537,10 +614,10 @@ namespace keepass2android
|
|||||||
|
|
||||||
public bool IsBeingMoved(PwUuid uuid)
|
public bool IsBeingMoved(PwUuid uuid)
|
||||||
{
|
{
|
||||||
MoveElementTask moveElementTask = AppTask as MoveElementTask;
|
MoveElementsTask moveElementsTask = AppTask as MoveElementsTask;
|
||||||
if (moveElementTask != null)
|
if (moveElementsTask != null)
|
||||||
{
|
{
|
||||||
if (moveElementTask.Uuid.Equals(uuid))
|
if (moveElementsTask.Uuids.Any(uuidMoved => uuidMoved.Equals(uuid)))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -553,28 +630,37 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void StartMovingElement()
|
public void StartMovingElements()
|
||||||
{
|
{
|
||||||
ShowInsertElementButtons();
|
|
||||||
GroupView.ListView.InvalidateViews();
|
ShowInsertElementsButtons();
|
||||||
BaseAdapter adapter = (BaseAdapter)ListAdapter;
|
BaseAdapter adapter = (BaseAdapter)ListAdapter;
|
||||||
adapter.NotifyDataSetChanged();
|
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
|
try
|
||||||
{
|
{
|
||||||
MoveElementTask moveElementTask = (MoveElementTask)AppTask;
|
MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask;
|
||||||
IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(moveElementTask.Uuid, true, null);
|
foreach (var uuid in moveElementsTask.Uuids)
|
||||||
|
{
|
||||||
|
IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(uuid, true, null);
|
||||||
if (elementToMove.ParentGroup != Group)
|
if (elementToMove.ParentGroup != Group)
|
||||||
App.Kp2a.GetDb().Dirty.Add(elementToMove.ParentGroup);
|
App.Kp2a.GetDb().Dirty.Add(elementToMove.ParentGroup);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
//don't crash if adding to dirty fails but log the exception:
|
//don't crash if adding to dirty fails but log the exception:
|
||||||
@ -583,7 +669,6 @@ namespace keepass2android
|
|||||||
|
|
||||||
AppTask = new NullTask();
|
AppTask = new NullTask();
|
||||||
AppTask.SetupGroupBaseActivityButtons(this);
|
AppTask.SetupGroupBaseActivityButtons(this);
|
||||||
GroupView.ListView.InvalidateViews();
|
|
||||||
BaseAdapter adapter = (BaseAdapter)ListAdapter;
|
BaseAdapter adapter = (BaseAdapter)ListAdapter;
|
||||||
adapter.NotifyDataSetChanged();
|
adapter.NotifyDataSetChanged();
|
||||||
}
|
}
|
||||||
@ -594,5 +679,186 @@ namespace keepass2android
|
|||||||
GroupEditActivity.Launch(this, pwGroup.ParentGroup, pwGroup);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,12 +73,13 @@ namespace keepass2android
|
|||||||
SetContentView (Resource.Layout.group_edit);
|
SetContentView (Resource.Layout.group_edit);
|
||||||
|
|
||||||
ImageButton iconButton = (ImageButton)FindViewById (Resource.Id.icon_button);
|
ImageButton iconButton = (ImageButton)FindViewById (Resource.Id.icon_button);
|
||||||
|
iconButton.SetScaleType(ImageView.ScaleType.FitXy);
|
||||||
iconButton.Click += (sender, e) =>
|
iconButton.Click += (sender, e) =>
|
||||||
{
|
{
|
||||||
IconPickerActivity.Launch (this);
|
IconPickerActivity.Launch (this);
|
||||||
};
|
};
|
||||||
_selectedIconId = (int) PwIcon.FolderOpen;
|
_selectedIconId = (int) PwIcon.FolderOpen;
|
||||||
iconButton.SetImageResource(Icons.IconToResId((PwIcon)_selectedIconId));
|
iconButton.SetImageResource(Icons.IconToResId((PwIcon)_selectedIconId, true));
|
||||||
|
|
||||||
Button okButton = (Button)FindViewById (Resource.Id.ok);
|
Button okButton = (Button)FindViewById (Resource.Id.ok);
|
||||||
okButton.Click += (sender, e) => {
|
okButton.Click += (sender, e) => {
|
||||||
@ -110,7 +111,7 @@ namespace keepass2android
|
|||||||
_selectedCustomIconId = _groupToEdit.CustomIconUuid;
|
_selectedCustomIconId = _groupToEdit.CustomIconUuid;
|
||||||
TextView nameField = (TextView)FindViewById(Resource.Id.group_name);
|
TextView nameField = (TextView)FindViewById(Resource.Id.group_name);
|
||||||
nameField.Text = _groupToEdit.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);
|
SetTitle(Resource.String.edit_group_title);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -137,7 +138,7 @@ namespace keepass2android
|
|||||||
_selectedIconId = data.Extras.GetInt(IconPickerActivity.KeyIconId);
|
_selectedIconId = data.Extras.GetInt(IconPickerActivity.KeyIconId);
|
||||||
_selectedCustomIconId = PwUuid.Zero;
|
_selectedCustomIconId = PwUuid.Zero;
|
||||||
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
|
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
|
||||||
currIconButton.SetImageResource(Icons.IconToResId((PwIcon)_selectedIconId));
|
currIconButton.SetImageResource(Icons.IconToResId((PwIcon)_selectedIconId, false));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,14 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
using System;
|
using System;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
|
using Android.Graphics;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
[Activity (Label = "@string/app_name", Theme="@style/NoTitleBar")]
|
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme_ActionBar")]
|
||||||
public class IconPickerActivity : LockCloseActivity
|
public class IconPickerActivity : LockCloseActivity
|
||||||
{
|
{
|
||||||
public const String KeyIconId = "icon_id";
|
public const String KeyIconId = "icon_id";
|
||||||
@ -100,8 +101,10 @@ namespace keepass2android
|
|||||||
TextView tv = (TextView) currView.FindViewById(Resource.Id.icon_text);
|
TextView tv = (TextView) currView.FindViewById(Resource.Id.icon_text);
|
||||||
tv.Text = "" + position;
|
tv.Text = "" + position;
|
||||||
ImageView iv = (ImageView) currView.FindViewById(Resource.Id.icon_image);
|
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;
|
return currView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ namespace keepass2android
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Launcher activity of Keepass2Android. This activity usually forwards to FileSelect but may show the revision dialog after installation or updates.
|
/// Launcher activity of Keepass2Android. This activity usually forwards to FileSelect but may show the revision dialog after installation or updates.
|
||||||
/// </summary>
|
/// </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 class KeePass : LifecycleDebugActivity
|
||||||
{
|
{
|
||||||
public const Result ExitNormal = Result.FirstUser;
|
public const Result ExitNormal = Result.FirstUser;
|
||||||
@ -167,6 +167,9 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#if DEBUG
|
||||||
|
showChangeLog = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (showChangeLog)
|
if (showChangeLog)
|
||||||
{
|
{
|
||||||
|
@ -19,11 +19,12 @@ using System;
|
|||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
|
using Android.Support.V7.App;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
|
|
||||||
public abstract class LifecycleDebugActivity : Activity
|
public abstract class LifecycleDebugActivity : AppCompatActivity
|
||||||
{
|
{
|
||||||
protected LifecycleDebugActivity (IntPtr javaReference, JniHandleOwnership transfer)
|
protected LifecycleDebugActivity (IntPtr javaReference, JniHandleOwnership transfer)
|
||||||
: base(javaReference, transfer)
|
: base(javaReference, transfer)
|
||||||
|
@ -16,14 +16,119 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using Android.Content.Res;
|
||||||
|
using Android.Graphics;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
using Android.Preferences;
|
using Android.Preferences;
|
||||||
|
using Android.Support.V7.App;
|
||||||
|
using Android.Views;
|
||||||
|
using Java.Lang;
|
||||||
|
using keepass2android;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
|
|
||||||
public class LockingPreferenceActivity : PreferenceActivity {
|
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 : AppCompatPreferenceActivity {
|
||||||
|
|
||||||
public LockingPreferenceActivity (IntPtr javaReference, JniHandleOwnership transfer)
|
public LockingPreferenceActivity (IntPtr javaReference, JniHandleOwnership transfer)
|
||||||
: base(javaReference, transfer)
|
: base(javaReference, transfer)
|
||||||
|
64
src/keepass2android/MeasuringRelativeLayout.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,11 @@ using Java.Net;
|
|||||||
using Android.Preferences;
|
using Android.Preferences;
|
||||||
using Android.Text;
|
using Android.Text;
|
||||||
using Android.Content.PM;
|
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.Keys;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
@ -41,21 +46,24 @@ using Keepass2android.Pluginsdk;
|
|||||||
using OtpKeyProv;
|
using OtpKeyProv;
|
||||||
using keepass2android.Io;
|
using keepass2android.Io;
|
||||||
using keepass2android.Utils;
|
using keepass2android.Utils;
|
||||||
using Exception = System.Exception;
|
|
||||||
using File = Java.IO.File;
|
using File = Java.IO.File;
|
||||||
using FileNotFoundException = Java.IO.FileNotFoundException;
|
using FileNotFoundException = Java.IO.FileNotFoundException;
|
||||||
using MemoryStream = System.IO.MemoryStream;
|
|
||||||
using Object = Java.Lang.Object;
|
using Object = Java.Lang.Object;
|
||||||
using Process = Android.OS.Process;
|
using Process = Android.OS.Process;
|
||||||
using String = System.String;
|
|
||||||
using KeeChallenge;
|
using KeeChallenge;
|
||||||
|
using AlertDialog = Android.App.AlertDialog;
|
||||||
|
using Toolbar = Android.Support.V7.Widget.Toolbar;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
[Activity(Label = "@string/app_name",
|
[Activity(Label = "@string/app_name",
|
||||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
ConfigurationChanges = ConfigChanges.Orientation,
|
||||||
LaunchMode = LaunchMode.SingleInstance,
|
LaunchMode = LaunchMode.SingleInstance,
|
||||||
Theme = "@style/Base")]
|
WindowSoftInputMode = SoftInput.AdjustResize,
|
||||||
|
Theme = "@style/MyTheme_Blue")] /*caution: also contained in AndroidManifest.xml*/
|
||||||
public class PasswordActivity : LockingActivity {
|
public class PasswordActivity : LockingActivity {
|
||||||
|
|
||||||
enum KeyProviders
|
enum KeyProviders
|
||||||
@ -141,20 +149,23 @@ namespace keepass2android
|
|||||||
private const string KeyFileOrProviderKey = "KeyFileOrProviderKey";
|
private const string KeyFileOrProviderKey = "KeyFileOrProviderKey";
|
||||||
|
|
||||||
|
|
||||||
private ActivityDesign _design;
|
|
||||||
private bool _performingLoad;
|
private bool _performingLoad;
|
||||||
private bool _keepPasswordInOnResume;
|
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)
|
: base(javaReference, transfer)
|
||||||
{
|
{
|
||||||
_design = new ActivityDesign(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PasswordActivity()
|
public PasswordActivity()
|
||||||
{
|
{
|
||||||
_design = new ActivityDesign(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -300,6 +311,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
if (KeyProviderType == KeyProviders.KeyFile)
|
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);
|
var iocKeyfile = IOConnectionInfo.UnserializeFromString(_keyFileOrProvider);
|
||||||
|
|
||||||
App.Kp2a.GetFileStorage(iocKeyfile)
|
App.Kp2a.GetFileStorage(iocKeyfile)
|
||||||
@ -666,10 +679,67 @@ 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)
|
protected override void OnCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
base.OnCreate(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
|
//use FlagSecure to make sure the last (revealed) character of the master password is not visible in recent apps
|
||||||
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
|
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
|
||||||
@ -678,8 +748,6 @@ namespace keepass2android
|
|||||||
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
|
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Intent i = Intent;
|
Intent i = Intent;
|
||||||
|
|
||||||
//only load the AppTask if this is the "first" OnCreate (not because of kill/resume, i.e. savedInstanceState==null)
|
//only load the AppTask if this is the "first" OnCreate (not because of kill/resume, i.e. savedInstanceState==null)
|
||||||
@ -745,9 +813,10 @@ namespace keepass2android
|
|||||||
App.Kp2a.LockDatabase(false);
|
App.Kp2a.LockDatabase(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SetContentView(Resource.Layout.password);
|
SetContentView(Resource.Layout.password);
|
||||||
|
|
||||||
|
InitializeToolbar();
|
||||||
|
|
||||||
InitializeFilenameView();
|
InitializeFilenameView();
|
||||||
|
|
||||||
if (KeyProviderType == KeyProviders.KeyFile)
|
if (KeyProviderType == KeyProviders.KeyFile)
|
||||||
@ -755,34 +824,36 @@ namespace keepass2android
|
|||||||
UpdateKeyfileIocView();
|
UpdateKeyfileIocView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var passwordEdit = FindViewById<EditText>(Resource.Id.password_edit);
|
||||||
|
passwordEdit.TextChanged +=
|
||||||
FindViewById<EditText>(Resource.Id.password).TextChanged +=
|
|
||||||
(sender, args) =>
|
(sender, args) =>
|
||||||
{
|
{
|
||||||
_password = FindViewById<EditText>(Resource.Id.password).Text;
|
_password = passwordEdit.Text;
|
||||||
UpdateOkButtonState();
|
UpdateOkButtonState();
|
||||||
};
|
};
|
||||||
FindViewById<EditText>(Resource.Id.password).EditorAction += (sender, args) =>
|
passwordEdit.EditorAction += (sender, args) =>
|
||||||
{
|
{
|
||||||
if ((args.ActionId == ImeAction.Done) || ((args.ActionId == ImeAction.ImeNull) && (args.Event.Action == KeyEventActions.Down)))
|
if ((args.ActionId == ImeAction.Done) || ((args.ActionId == ImeAction.ImeNull) && (args.Event.Action == KeyEventActions.Down)))
|
||||||
OnOk();
|
OnOk();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
FindViewById<EditText>(Resource.Id.pass_otpsecret).TextChanged += (sender, args) => UpdateOkButtonState();
|
FindViewById<EditText>(Resource.Id.pass_otpsecret).TextChanged += (sender, args) => UpdateOkButtonState();
|
||||||
|
|
||||||
|
|
||||||
EditText passwordEdit = FindViewById<EditText>(Resource.Id.password);
|
|
||||||
passwordEdit.Text = _password;
|
passwordEdit.Text = _password;
|
||||||
passwordEdit.RequestFocus();
|
|
||||||
Window.SetSoftInputMode(SoftInput.StateVisible);
|
|
||||||
|
|
||||||
InitializeOkButton();
|
var passwordFont = Typeface.CreateFromAsset(Assets, "SourceCodePro-Regular.ttf");
|
||||||
|
passwordEdit.Typeface = passwordFont;
|
||||||
|
|
||||||
|
|
||||||
|
InitializeBottomBarButtons();
|
||||||
|
|
||||||
InitializePasswordModeSpinner();
|
InitializePasswordModeSpinner();
|
||||||
|
|
||||||
InitializeOtpSecretSpinner();
|
InitializeOtpSecretSpinner();
|
||||||
|
|
||||||
|
InitializeNavDrawerButtons();
|
||||||
|
|
||||||
UpdateOkButtonState();
|
UpdateOkButtonState();
|
||||||
|
|
||||||
InitializeTogglePasswordButton();
|
InitializeTogglePasswordButton();
|
||||||
@ -798,6 +869,88 @@ namespace keepass2android
|
|||||||
.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult, null), _ioConnection,
|
.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult, null), _ioConnection,
|
||||||
RequestCodePrepareDbFile, false);
|
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 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()
|
private void InitializeOtpSecretSpinner()
|
||||||
@ -892,13 +1045,15 @@ namespace keepass2android
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeOkButton()
|
private void InitializeBottomBarButtons()
|
||||||
{
|
{
|
||||||
Button confirmButton = (Button) FindViewById(Resource.Id.pass_ok);
|
Button confirmButton = (Button) FindViewById(Resource.Id.pass_ok);
|
||||||
confirmButton.Click += (sender, e) =>
|
confirmButton.Click += (sender, e) =>
|
||||||
{
|
{
|
||||||
OnOk();
|
OnOk();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FindViewById(Resource.Id.change_db).Click += (sender, args) => GoToFileSelectActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnOk()
|
private void OnOk()
|
||||||
@ -916,6 +1071,9 @@ namespace keepass2android
|
|||||||
_showPassword = !_showPassword;
|
_showPassword = !_showPassword;
|
||||||
MakePasswordMaskedOrVisible();
|
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()
|
private void InitializeKeyfileBrowseButton()
|
||||||
@ -974,11 +1132,7 @@ namespace keepass2android
|
|||||||
RequestCodePrepareOtpAuxFile, false);
|
RequestCodePrepareOtpAuxFile, false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
//android 2.x
|
|
||||||
//TODO test
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreState(Bundle savedInstanceState)
|
private void RestoreState(Bundle savedInstanceState)
|
||||||
@ -989,7 +1143,7 @@ namespace keepass2android
|
|||||||
MakePasswordMaskedOrVisible();
|
MakePasswordMaskedOrVisible();
|
||||||
|
|
||||||
_keyFileOrProvider = savedInstanceState.GetString(KeyFileOrProviderKey);
|
_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));
|
_pendingOtps = new List<string>(savedInstanceState.GetStringArrayList(PendingOtpsKey));
|
||||||
|
|
||||||
@ -1012,17 +1166,18 @@ namespace keepass2android
|
|||||||
|
|
||||||
private void UpdateOkButtonState()
|
private void UpdateOkButtonState()
|
||||||
{
|
{
|
||||||
|
bool enabled = false;
|
||||||
switch (KeyProviderType)
|
switch (KeyProviderType)
|
||||||
{
|
{
|
||||||
case KeyProviders.None:
|
case KeyProviders.None:
|
||||||
FindViewById(Resource.Id.pass_ok).Enabled = true;
|
enabled = true;
|
||||||
break;
|
break;
|
||||||
case KeyProviders.KeyFile:
|
case KeyProviders.KeyFile:
|
||||||
FindViewById(Resource.Id.pass_ok).Enabled = _keyFileOrProvider != "" || _password != "";
|
enabled = _keyFileOrProvider != "" || _password != "";
|
||||||
break;
|
break;
|
||||||
case KeyProviders.Otp:
|
case KeyProviders.Otp:
|
||||||
|
|
||||||
bool enabled = true;
|
enabled = true;
|
||||||
if (_otpInfo == null)
|
if (_otpInfo == null)
|
||||||
enabled = false;
|
enabled = false;
|
||||||
else
|
else
|
||||||
@ -1040,18 +1195,20 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FindViewById(Resource.Id.pass_ok).Enabled = enabled;
|
|
||||||
break;
|
break;
|
||||||
case KeyProviders.OtpRecovery:
|
case KeyProviders.OtpRecovery:
|
||||||
case KeyProviders.ChalRecovery:
|
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;
|
break;
|
||||||
case KeyProviders.Challenge:
|
case KeyProviders.Challenge:
|
||||||
FindViewById(Resource.Id.pass_ok).Enabled = _challengeSecret != null;
|
enabled = _challengeSecret != null;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
FindViewById(Resource.Id.pass_ok).Enabled = enabled;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateKeyProviderUiState()
|
private void UpdateKeyProviderUiState()
|
||||||
@ -1212,15 +1369,26 @@ namespace keepass2android
|
|||||||
|
|
||||||
private void MakePasswordMaskedOrVisible()
|
private void MakePasswordMaskedOrVisible()
|
||||||
{
|
{
|
||||||
TextView password = (TextView) FindViewById(Resource.Id.password);
|
TextView password = (TextView) FindViewById(Resource.Id.password_edit);
|
||||||
if (_showPassword)
|
if (_showPassword)
|
||||||
{
|
{
|
||||||
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
|
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
|
||||||
|
SetPasswordTypeface(password);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
password.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
|
password.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPasswordTypeface(TextView textView)
|
||||||
|
{
|
||||||
|
if (_passwordFont == null)
|
||||||
|
{
|
||||||
|
_passwordFont = Typeface.CreateFromAsset(Assets, "SourceCodePro-Regular.ttf");
|
||||||
|
}
|
||||||
|
textView.Typeface = _passwordFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetNewDefaultFile()
|
private void SetNewDefaultFile()
|
||||||
@ -1390,7 +1558,7 @@ namespace keepass2android
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//assume the key should be used as static password
|
//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();
|
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);
|
View killButton = FindViewById(Resource.Id.kill_app);
|
||||||
if (PreferenceManager.GetDefaultSharedPreferences(this)
|
if (PreferenceManager.GetDefaultSharedPreferences(this)
|
||||||
@ -1514,14 +1687,6 @@ namespace keepass2android
|
|||||||
|
|
||||||
private void InitializeFilenameView() {
|
private void InitializeFilenameView() {
|
||||||
SetEditText(Resource.Id.filename, App.Kp2a.GetFileStorage(_ioConnection).GetDisplayName(_ioConnection));
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1548,28 +1713,11 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
public override bool OnOptionsItemSelected(IMenuItem item) {
|
||||||
switch ( item.ItemId ) {
|
switch ( item.ItemId ) {
|
||||||
case Resource.Id.menu_about:
|
|
||||||
AboutDialog dialog = new AboutDialog(this);
|
|
||||||
dialog.Show();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Resource.Id.menu_app_settings:
|
case Android.Resource.Id.Home:
|
||||||
AppSettingsActivity.Launch(this);
|
_drawerLayout.OpenDrawer(Android.Support.V4.View.GravityCompat.Start);
|
||||||
return true;
|
|
||||||
|
|
||||||
case Resource.Id.menu_change_db:
|
|
||||||
GoToFileSelectActivity();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1643,7 +1791,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
private void ClearEnteredPassword()
|
private void ClearEnteredPassword()
|
||||||
{
|
{
|
||||||
SetEditText(Resource.Id.password, "");
|
SetEditText(Resource.Id.password_edit, "");
|
||||||
SetEditText(Resource.Id.pass_otpsecret, "");
|
SetEditText(Resource.Id.pass_otpsecret, "");
|
||||||
foreach (int otpId in _otpTextViewIds)
|
foreach (int otpId in _otpTextViewIds)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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">
|
<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" />
|
<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">
|
<application android:label="keepass2android" android:icon="@drawable/ic_launcher">
|
||||||
|
|
||||||
@ -54,7 +54,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</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">
|
<intent-filter android:label="@string/app_name">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</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">
|
<intent-filter android:label="@string/app_name">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:versionCode="59"
|
android:versionCode="57"
|
||||||
android:versionName="0.9.8b"
|
android:versionName="0.9.8 preview 2 (alpha)"
|
||||||
package="keepass2android.keepass2android"
|
package="keepass2android.keepass2android"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
||||||
@ -57,7 +57,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</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">
|
<intent-filter android:label="@string/app_name">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</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">
|
<intent-filter android:label="@string/app_name">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
@ -24,6 +24,7 @@ using Android.Widget;
|
|||||||
using Android.Preferences;
|
using Android.Preferences;
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
using keepass2android.view;
|
using keepass2android.view;
|
||||||
|
using KeePassLib.Interfaces;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
@ -212,6 +213,7 @@ namespace keepass2android
|
|||||||
private List<PwGroup> _groupsForViewing;
|
private List<PwGroup> _groupsForViewing;
|
||||||
private List<PwEntry> _entriesForViewing;
|
private List<PwEntry> _entriesForViewing;
|
||||||
|
|
||||||
|
public bool InActionMode { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public PwGroupListAdapter(GroupBaseActivity act, PwGroup group) {
|
public PwGroupListAdapter(GroupBaseActivity act, PwGroup group) {
|
||||||
@ -276,21 +278,29 @@ namespace keepass2android
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsGroupAtPosition(int position)
|
||||||
|
{
|
||||||
|
return position < _groupsForViewing.Count;
|
||||||
|
}
|
||||||
|
|
||||||
public override long GetItemId(int position) {
|
public override long GetItemId(int position) {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override View GetView(int position, View convertView, ViewGroup parent) {
|
public override View GetView(int position, View convertView, ViewGroup parent) {
|
||||||
int size = _groupsForViewing.Count;
|
int size = _groupsForViewing.Count;
|
||||||
|
GroupListItemView view;
|
||||||
if ( position < size ) {
|
if ( position < size ) {
|
||||||
return CreateGroupView(position, convertView);
|
view = CreateGroupView(position, convertView);
|
||||||
} else {
|
} 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];
|
PwGroup g = _groupsForViewing[position];
|
||||||
PwGroupView gv;
|
PwGroupView gv;
|
||||||
|
|
||||||
@ -322,6 +332,17 @@ namespace keepass2android
|
|||||||
return ev;
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IStructureItem GetItemAtPosition(int keyAt)
|
||||||
|
{
|
||||||
|
if (keyAt < _groupsForViewing.Count)
|
||||||
|
{
|
||||||
|
return _groupsForViewing[keyAt];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _entriesForViewing[keyAt - _groupsForViewing.Count];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
[Activity(Label = "@string/app_name",
|
[Activity(Label = "@string/app_name",
|
||||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
||||||
Theme = "@style/Base")]
|
Theme = "@style/MyTheme_ActionBar")]
|
||||||
[IntentFilter(new[] { Strings.ActionQueryCredentials},
|
[IntentFilter(new[] { Strings.ActionQueryCredentials},
|
||||||
Categories = new[] { Intent.CategoryDefault })]
|
Categories = new[] { Intent.CategoryDefault })]
|
||||||
[IntentFilter(new[] { Strings.ActionQueryCredentialsForOwnPackage },
|
[IntentFilter(new[] { Strings.ActionQueryCredentialsForOwnPackage },
|
||||||
|
@ -24,29 +24,30 @@ using Android.Widget;
|
|||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
using KeePassLib.Keys;
|
using KeePassLib.Keys;
|
||||||
using Android.Preferences;
|
using Android.Preferences;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Support.Design.Widget;
|
||||||
using Android.Views.InputMethods;
|
using Android.Views.InputMethods;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
[Activity(Label = "@string/app_name",
|
||||||
Theme = "@style/Base")]
|
ConfigurationChanges = ConfigChanges.Orientation,
|
||||||
|
WindowSoftInputMode = SoftInput.AdjustResize,
|
||||||
|
MainLauncher = false,
|
||||||
|
Theme = "@style/MyTheme_Blue")]
|
||||||
public class QuickUnlock : LifecycleDebugActivity
|
public class QuickUnlock : LifecycleDebugActivity
|
||||||
{
|
{
|
||||||
private IOConnectionInfo _ioc;
|
private IOConnectionInfo _ioc;
|
||||||
private QuickUnlockBroadcastReceiver _intentReceiver;
|
private QuickUnlockBroadcastReceiver _intentReceiver;
|
||||||
|
|
||||||
private ActivityDesign _design;
|
|
||||||
|
|
||||||
public QuickUnlock()
|
public QuickUnlock()
|
||||||
{
|
{
|
||||||
_design = new ActivityDesign(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnCreate(Bundle bundle)
|
protected override void OnCreate(Bundle bundle)
|
||||||
{
|
{
|
||||||
base.OnCreate(bundle);
|
base.OnCreate(bundle);
|
||||||
_design.ApplyTheme();
|
|
||||||
|
|
||||||
//use FlagSecure to make sure the last (revealed) character of the password is not visible in recent apps
|
//use FlagSecure to make sure the last (revealed) character of the password is not visible in recent apps
|
||||||
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
|
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
|
||||||
@ -63,13 +64,12 @@ namespace keepass2android
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SetContentView(Resource.Layout.QuickUnlock);
|
SetContentView(Resource.Layout.QuickUnlock);
|
||||||
|
|
||||||
if (App.Kp2a.GetDb().KpDatabase.Name != "")
|
if (App.Kp2a.GetDb().KpDatabase.Name != "")
|
||||||
{
|
{
|
||||||
FindViewById(Resource.Id.filename_label).Visibility = ViewStates.Invisible;
|
FindViewById(Resource.Id.filename_label).Visibility = ViewStates.Visible;
|
||||||
((TextView) FindViewById(Resource.Id.qu_filename)).Text = App.Kp2a.GetDb().KpDatabase.Name;
|
((TextView) FindViewById(Resource.Id.filename_label)).Text = App.Kp2a.GetDb().KpDatabase.Name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -78,11 +78,11 @@ namespace keepass2android
|
|||||||
.GetBoolean(GetString(Resource.String.RememberRecentFiles_key),
|
.GetBoolean(GetString(Resource.String.RememberRecentFiles_key),
|
||||||
Resources.GetBoolean(Resource.Boolean.RememberRecentFiles_default)))
|
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
|
else
|
||||||
{
|
{
|
||||||
((TextView) FindViewById(Resource.Id.qu_filename)).Text = "*****";
|
((TextView) FindViewById(Resource.Id.filename_label)).Text = "*****";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -104,6 +104,8 @@ namespace keepass2android
|
|||||||
OnUnlock(quickUnlockLength, pwd);
|
OnUnlock(quickUnlockLength, pwd);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Button btnLock = (Button) FindViewById(Resource.Id.QuickUnlock_buttonLock);
|
Button btnLock = (Button) FindViewById(Resource.Id.QuickUnlock_buttonLock);
|
||||||
btnLock.Click += (object sender, EventArgs e) =>
|
btnLock.Click += (object sender, EventArgs e) =>
|
||||||
{
|
{
|
||||||
@ -120,8 +122,10 @@ namespace keepass2android
|
|||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.AddAction(Intents.DatabaseLocked);
|
filter.AddAction(Intents.DatabaseLocked);
|
||||||
RegisterReceiver(_intentReceiver, filter);
|
RegisterReceiver(_intentReceiver, filter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnUnlock(int quickUnlockLength, EditText pwd)
|
private void OnUnlock(int quickUnlockLength, EditText pwd)
|
||||||
{
|
{
|
||||||
KcpPassword kcpPassword = (KcpPassword) App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof (KcpPassword));
|
KcpPassword kcpPassword = (KcpPassword) App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof (KcpPassword));
|
||||||
@ -149,8 +153,6 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
base.OnResume();
|
base.OnResume();
|
||||||
|
|
||||||
_design.ReapplyTheme();
|
|
||||||
|
|
||||||
CheckIfUnloaded();
|
CheckIfUnloaded();
|
||||||
|
|
||||||
EditText pwd = (EditText) FindViewById(Resource.Id.QuickUnlock_password);
|
EditText pwd = (EditText) FindViewById(Resource.Id.QuickUnlock_password);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shareInterpolator="false">
|
android:shareInterpolator="false">
|
||||||
<translate android:fromXDelta="0%" android:toXDelta="-100%"
|
<translate android:fromXDelta="0%" android:toXDelta="0%"
|
||||||
android:fromYDelta="0%" android:toYDelta="0%"
|
android:fromYDelta="0%" android:toYDelta="0%"
|
||||||
android:duration="400"/>
|
android:duration="400"/>
|
||||||
</set>
|
</set>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shareInterpolator="false">
|
android:shareInterpolator="false">
|
||||||
<translate
|
<translate
|
||||||
android:fromXDelta="0%" android:toXDelta="100%"
|
android:fromXDelta="0%" android:toXDelta="0%"
|
||||||
android:fromYDelta="0%" android:toYDelta="0%"
|
android:fromYDelta="0%" android:toYDelta="0%"
|
||||||
android:duration="250" />
|
android:duration="250" />
|
||||||
</set>
|
</set>
|
||||||
|
Before Width: | Height: | Size: 895 B |
Before Width: | Height: | Size: 961 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 4.2 KiB |