Added support for Entry templates

This commit is contained in:
Philipp Crocoll 2016-01-07 05:13:04 +01:00
parent b1dcc4f7a9
commit 5d8aa8afe0
12 changed files with 477 additions and 98 deletions

View File

@ -438,11 +438,18 @@ namespace keepass2android
{
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))
IEditMode editMode = new DefaultEdit();
if (KpEntryTemplatedEdit.IsTemplated(App.Kp2a.GetDb(), this.Entry))
editMode = new KpEntryTemplatedEdit(App.Kp2a.GetDb(), this.Entry);
foreach (var key in editMode.SortExtraFieldKeys(Entry.Strings.GetKeys().Where(key=> !PwDefs.IsStandardField(key))))
{
hasExtras = true;
var stringView = CreateExtraSection(pair.Key, pair.Value.ReadString(), pair.Value.IsProtected);
extraGroup.AddView(stringView.View);
if (editMode.IsVisible(key))
{
hasExtras = true;
var value = Entry.Strings.Get(key);
var stringView = CreateExtraSection(key, value.ReadString(), value.IsProtected);
extraGroup.AddView(stringView.View);
}
}
FindViewById(Resource.Id.extra_strings_container).Visibility = hasExtras ? ViewStates.Visible : ViewStates.Gone;
}

View File

@ -33,16 +33,23 @@ using KeePassLib.Security;
using Android.Content.PM;
using System.IO;
using System.Globalization;
using Android.Graphics;
using Android.Util;
using Debug = System.Diagnostics.Debug;
using File = System.IO.File;
using Object = Java.Lang.Object;
using Uri = Android.Net.Uri;
namespace keepass2android
{
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_ActionBar")]
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_ActionBar")]
public class EntryEditActivity : LockCloseActivity {
public const String KeyEntry = "entry";
public const String KeyParent = "parent";
public const String KeyTemplateUuid = "KeyTemplateUuid";
public const int ResultOkIconPicker = (int)Result.FirstUser + 1000;
@ -64,11 +71,12 @@ namespace keepass2android
act.StartActivityForResult(i, 0);
}
public static void Launch(Activity act, PwGroup pw, AppTask appTask) {
public static void Launch(Activity act, PwGroup pw, PwUuid templateUuid, AppTask appTask) {
Intent i = new Intent(act, typeof(EntryEditActivity));
PwGroup parent = pw;
i.PutExtra(KeyParent, parent.Uuid.ToHexString());
i.PutExtra(KeyTemplateUuid, templateUuid.ToHexString());
appTask.ToIntent(i);
@ -127,62 +135,39 @@ namespace keepass2android
State.ParentGroup = null;
if (entryId.Equals(PwUuid.Zero))
{
//creating new entry
String groupId = i.GetStringExtra(KeyParent);
State.ParentGroup = db.KpDatabase.RootGroup.FindGroup(new PwUuid(MemUtil.HexStringToByteArray(groupId)), true);
State.EntryInDatabase = new PwEntry(true, true);
State.EntryInDatabase.Strings.Set(PwDefs.UserNameField, new ProtectedString(
db.KpDatabase.MemoryProtection.ProtectUserName, db.KpDatabase.DefaultUserName));
/*KPDesktop
* ProtectedString psAutoGen;
PwGenerator.Generate(out psAutoGen, Program.Config.PasswordGenerator.AutoGeneratedPasswordsProfile,
null, Program.PwGeneratorPool);
psAutoGen = psAutoGen.WithProtection(pwDb.MemoryProtection.ProtectPassword);
pwe.Strings.Set(PwDefs.PasswordField, psAutoGen);
int nExpireDays = Program.Config.Defaults.NewEntryExpiresInDays;
if(nExpireDays >= 0)
{
pwe.Expires = true;
pwe.ExpiryTime = DateTime.Now.AddDays(nExpireDays);
}*/
if ((State.ParentGroup.IconId != PwIcon.Folder) && (State.ParentGroup.IconId != PwIcon.FolderOpen) &&
(State.ParentGroup.IconId != PwIcon.FolderPackage))
PwUuid templateId = new PwUuid(MemUtil.HexStringToByteArray(i.GetStringExtra(KeyTemplateUuid)));
PwEntry templateEntry = null;
if (!PwUuid.Zero.Equals(templateId))
{
State.EntryInDatabase.IconId = State.ParentGroup.IconId; // Inherit icon from group
templateEntry = db.Entries[templateId];
}
if (KpEntryTemplatedEdit.IsTemplate(templateEntry))
{
CreateNewFromKpEntryTemplate(db, templateEntry);
}
else if (templateEntry != null)
{
CreateNewFromStandardTemplate(templateEntry);
}
else
State.EntryInDatabase.IconId = PwIcon.Key;
State.EntryInDatabase.CustomIconUuid = State.ParentGroup.CustomIconUuid;
/*
* KPDesktop
if(strDefaultSeq.Length == 0)
{
PwGroup pg = m_pwEntry.ParentGroup;
if(pg != null)
{
strDefaultSeq = pg.GetAutoTypeSequenceInherited();
if(strDefaultSeq.Length == 0)
{
if(PwDefs.IsTanEntry(m_pwEntry))
strDefaultSeq = PwDefs.DefaultAutoTypeSequenceTan;
else
strDefaultSeq = PwDefs.DefaultAutoTypeSequence;
CreateNewWithoutTemplate(db);
}
}
}*/
_appTask.PrepareNewEntry(State.EntryInDatabase);
State.IsNew = true;
State.EntryModified = true;
} else
}
else
{
System.Diagnostics.Debug.Assert(entryId != null);
Debug.Assert(entryId != null);
State.EntryInDatabase = db.Entries [entryId];
State.IsNew = false;
@ -191,6 +176,10 @@ namespace keepass2android
}
State.Entry = State.EntryInDatabase.CloneDeep();
if (KpEntryTemplatedEdit.IsTemplated(db, State.Entry))
State.EditMode = new KpEntryTemplatedEdit(db, State.Entry);
else
State.EditMode = new DefaultEdit();
}
@ -200,6 +189,7 @@ namespace keepass2android
SetResult(KeePass.ExitRefreshTitle);
FillData();
View scrollView = FindViewById(Resource.Id.entry_scroll);
scrollView.ScrollBarStyle = ScrollbarStyles.InsideInset;
@ -250,8 +240,8 @@ namespace keepass2android
State.ShowPassword = !State.ShowPassword;
MakePasswordVisibleOrHidden();
};
Android.Graphics.PorterDuff.Mode mMode = Android.Graphics.PorterDuff.Mode.SrcAtop;
Android.Graphics.Color color = new Android.Graphics.Color (189,189,189);
PorterDuff.Mode mMode = PorterDuff.Mode.SrcAtop;
Color color = new Color (189,189,189);
btnTogglePassword.SetColorFilter (color, mMode);
@ -288,6 +278,40 @@ namespace keepass2android
}
private void CreateNewFromKpEntryTemplate(Database db, PwEntry templateEntry)
{
var entry = new PwEntry(true, true);
KpEntryTemplatedEdit.InitializeEntry(entry, templateEntry);
State.EntryInDatabase = entry;
}
private void CreateNewFromStandardTemplate(PwEntry templateEntry)
{
var newEntry = templateEntry.CloneDeep();
newEntry.SetUuid(new PwUuid(true), true); // Create new UUID
newEntry.CreationTime = newEntry.LastModificationTime = newEntry.LastAccessTime = DateTime.Now;
State.EntryInDatabase = newEntry;
}
private void CreateNewWithoutTemplate(Database db)
{
State.EntryInDatabase = new PwEntry(true, true);
State.EntryInDatabase.Strings.Set(PwDefs.UserNameField, new ProtectedString(
db.KpDatabase.MemoryProtection.ProtectUserName, db.KpDatabase.DefaultUserName));
if ((State.ParentGroup.IconId != PwIcon.Folder) && (State.ParentGroup.IconId != PwIcon.FolderOpen) &&
(State.ParentGroup.IconId != PwIcon.FolderPackage))
{
State.EntryInDatabase.IconId = State.ParentGroup.IconId; // Inherit icon from group
}
else
State.EntryInDatabase.IconId = PwIcon.Key;
State.EntryInDatabase.CustomIconUuid = State.ParentGroup.CustomIconUuid;
}
private void SetAddExtraStringEnabled()
{
if (!App.Kp2a.GetDb().DatabaseFormat.CanHaveCustomFields)
@ -785,6 +809,7 @@ namespace keepass2android
public override bool OnPrepareOptionsMenu(IMenu menu)
{
Util.PrepareDonateOptionMenu(menu, this);
menu.FindItem(Resource.Id.menu_show_all).SetVisible(_editModeHiddenViews.Any());
return base.OnPrepareOptionsMenu(menu);
}
@ -806,6 +831,11 @@ namespace keepass2android
case Resource.Id.menu_cancel:
Finish();
return true;
case Resource.Id.menu_show_all:
item.SetVisible(false);
foreach (View v in _editModeHiddenViews)
v.Visibility = ViewStates.Visible;
return true;
case Android.Resource.Id.Home:
OnBackPressed();
return true;
@ -849,11 +879,12 @@ namespace keepass2android
((CheckBox)ees.FindViewById(Resource.Id.protection)).Checked = pair.Value.IsProtected;
//ees.FindViewById(Resource.Id.edit_extra).Click += (sender, e) => DeleteAdvancedString((View)sender);
ees.FindViewById(Resource.Id.edit_extra).Click += (sender, e) => EditAdvancedString(ees);
ees.FindViewById(Resource.Id.edit_extra).Click += (sender, e) => EditAdvancedString(ees.FindViewById(Resource.Id.edit_extra));
return ees;
}
private string[] _additionalKeys = null;
private List<View> _editModeHiddenViews;
public string[] AdditionalKeys
{
@ -864,6 +895,7 @@ namespace keepass2android
_additionalKeys = App.Kp2a.GetDb().Entries
.Select(kvp => kvp.Value)
.SelectMany(x => x.Strings.GetKeys().Where(k => !PwDefs.IsStandardField(k)))
.Where(k => (k != null) && !k.StartsWith("_etm_") )
.Distinct()
.ToArray();
}
@ -934,7 +966,9 @@ namespace keepass2android
}
}
private void FillData() {
private void FillData()
{
_editModeHiddenViews = new List<View>();
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.GetDb().KpDatabase, State.Entry.IconId, State.Entry.CustomIconUuid, false);
@ -950,12 +984,15 @@ namespace keepass2android
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
foreach (var pair in State.Entry.Strings)
foreach (var key in State.EditMode.SortExtraFieldKeys(State.Entry.Strings.Select(ps => ps.Key)))
{
String key = pair.Key;
if (!PwDefs.IsStandardField(key)) {
var ees = CreateExtraStringView(pair);
if (!PwDefs.IsStandardField(key))
{
RelativeLayout ees = CreateExtraStringView(new KeyValuePair<string, ProtectedString>(key, State.Entry.Strings.Get(key)));
var isVisible = State.EditMode.IsVisible(key);
ees.Visibility = isVisible ? ViewStates.Visible : ViewStates.Gone;
if (!isVisible)
_editModeHiddenViews.Add(ees);
container.AddView(ees);
}
}
@ -985,6 +1022,29 @@ namespace keepass2android
UpdateExpires();
List<KeyValuePair<string, int>> keyLayoutIds = new List<KeyValuePair<string, int>>()
{
new KeyValuePair<string, int>(PwDefs.TitleField, Resource.Id.title_section),
new KeyValuePair<string, int>(PwDefs.UserNameField, Resource.Id.user_section),
new KeyValuePair<string, int>(PwDefs.PasswordField, Resource.Id.password_section),
new KeyValuePair<string, int>(PwDefs.UrlField, Resource.Id.url_section),
new KeyValuePair<string, int>(PwDefs.NotesField, Resource.Id.comments_section),
new KeyValuePair<string, int>(KeePass.TagsKey, Resource.Id.tags_section),
new KeyValuePair<string, int>(KeePass.OverrideUrlKey, Resource.Id.entry_override_url_container),
new KeyValuePair<string, int>(KeePass.ExpDateKey, Resource.Id.expires_section),
};
foreach (var kvp in keyLayoutIds)
{
var isVisible = State.EditMode.IsVisible(kvp.Key);
var field = FindViewById(kvp.Value);
if (!isVisible)
_editModeHiddenViews.Add(field);
field.Visibility = isVisible ? ViewStates.Visible : ViewStates.Gone;
}
}
private String getDateTime(DateTime dt) {
return dt.ToString ("g", CultureInfo.CurrentUICulture);
@ -1052,7 +1112,7 @@ namespace keepass2android
if (allKeys.Contains(key))
{
Toast.MakeText(this, GetString(Resource.String.error_string_duplicate_key, new Java.Lang.Object[]{key}), ToastLength.Long).Show();
Toast.MakeText(this, GetString(Resource.String.error_string_duplicate_key, new Object[]{key}), ToastLength.Long).Show();
return false;
}
@ -1083,9 +1143,34 @@ namespace keepass2android
base.OnPause();
}
}
public class DefaultEdit : IEditMode
{
public DefaultEdit()
{
}
public bool IsVisible(string fieldKey)
{
return true;
}
public IEnumerable<string> SortExtraFieldKeys(IEnumerable<string> keys)
{
return keys;
}
public bool ShowAddAttachments
{
get { throw new NotImplementedException(); }
}
public bool ShowAddExtras
{
get { throw new NotImplementedException(); }
}
}
}

View File

@ -1,7 +1,16 @@
using System.Collections.Generic;
using KeePassLib;
namespace keepass2android
{
interface IEditMode
{
bool IsVisible(string fieldKey);
IEnumerable<string> SortExtraFieldKeys(IEnumerable<string> keys);
}
/// <summary>
/// Holds the state of the EntrryEditActivity. This is required to be able to keep a partially modified entry in memory
/// through the App variable. Serializing this state (especially the Entry/EntryInDatabase) can be a performance problem
@ -20,6 +29,7 @@ namespace keepass2android
internal bool EntryModified;
public IEditMode EditMode { get; set; }
}
}

View File

@ -16,6 +16,9 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Android.App;
using Android.Content;
using Android.OS;
@ -26,9 +29,15 @@ using Android.Util;
using KeePassLib.Utility;
using keepass2android.view;
using Android.Content.PM;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Preferences;
using Android.Runtime;
using Android.Support.V4.View;
using Android.Support.V7.App;
using KeePassLib.Security;
using AlertDialog = Android.App.AlertDialog;
using Object = Java.Lang.Object;
namespace keepass2android
{
@ -96,7 +105,77 @@ namespace keepass2android
{
get { return App.Kp2a.GetDb().CanWrite && ((this.Group.ParentGroup != null) || App.Kp2a.GetDb().DatabaseFormat.CanHaveEntriesInRootGroup); }
}
private class TemplateListAdapter : ArrayAdapter<PwEntry>
{
public TemplateListAdapter(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer)
{
}
public TemplateListAdapter(Context context, int textViewResourceId) : base(context, textViewResourceId)
{
}
public TemplateListAdapter(Context context, int resource, int textViewResourceId) : base(context, resource, textViewResourceId)
{
}
public TemplateListAdapter(Context context, int textViewResourceId, PwEntry[] objects) : base(context, textViewResourceId, objects)
{
}
public TemplateListAdapter(Context context, int resource, int textViewResourceId, PwEntry[] objects) : base(context, resource, textViewResourceId, objects)
{
}
public TemplateListAdapter(Context context, int textViewResourceId, IList<PwEntry> objects) : base(context, textViewResourceId, objects)
{
}
public TemplateListAdapter(Context context, int resource, int textViewResourceId, IList<PwEntry> objects) : base(context, resource, textViewResourceId, objects)
{
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View v = base.GetView(position, convertView, parent);
TextView tv = (TextView)v.FindViewById(Android.Resource.Id.Text1);
tv.SetPadding(tv.PaddingLeft,0,tv.PaddingRight,0);
PwEntry templateEntry = this.GetItem(position);
var bmp =
Bitmap.CreateScaledBitmap(
Util.DrawableToBitmap(App.Kp2a.GetDb()
.DrawableFactory.GetIconDrawable(Context, App.Kp2a.GetDb().KpDatabase, templateEntry.IconId, PwUuid.Zero, false)),
(int)Util.convertDpToPixel(80, Context),
(int)Util.convertDpToPixel(80, Context),
true);
Drawable icon = new BitmapDrawable(bmp);
if (
PreferenceManager.GetDefaultSharedPreferences(Context)
.GetString("IconSetKey", Context.PackageName) == Context.PackageName)
{
Android.Graphics.PorterDuff.Mode mMode = Android.Graphics.PorterDuff.Mode.SrcAtop;
Color color = new Color(189, 189, 189);
icon.SetColorFilter(color, mMode);
}
//Put the image on the TextView
tv.SetCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
tv.Text = templateEntry.Strings.ReadSafe(PwDefs.TitleField);
tv.SetTextSize(ComplexUnitType.Dip, 20);
tv.CompoundDrawablePadding = (int)Util.convertDpToPixel(8, Context);
return v;
}
};
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
@ -139,7 +218,29 @@ namespace keepass2android
if (AddEntryEnabled)
{
View addEntry = FindViewById (Resource.Id.fabAddNewEntry);
addEntry.Click += (sender, e) => { EntryEditActivity.Launch (this, Group, AppTask); };
addEntry.Click += (sender, e) =>
{
PwEntry defaultTemplate = new PwEntry(false, false);
defaultTemplate.IconId = PwIcon.Key;
defaultTemplate.Strings.Set(PwDefs.TitleField, new ProtectedString(false, GetString(Resource.String.DefaultTemplate)));
List<PwEntry> templates = new List<PwEntry>() { defaultTemplate };
if (!PwUuid.Zero.Equals(App.Kp2a.GetDb().KpDatabase.EntryTemplatesGroup))
{
templates.AddRange(App.Kp2a.GetDb().Groups[App.Kp2a.GetDb().KpDatabase.EntryTemplatesGroup].Entries.OrderBy(entr => entr.Strings.ReadSafe(PwDefs.TitleField)));
}
new AlertDialog.Builder(this)
.SetAdapter(new TemplateListAdapter(this, Android.Resource.Layout.SelectDialogItem,
Android.Resource.Id.Text1, templates), (o, args) =>
{
EntryEditActivity.Launch(this, Group, templates[args.Which].Uuid, AppTask);
})
.Show();
};
}

View File

@ -180,32 +180,6 @@ namespace keepass2android
return 0;
}
public static Bitmap DrawableToBitmap (Drawable drawable) {
Bitmap bitmap = null;
if (drawable is BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if(bitmapDrawable.Bitmap != null) {
return bitmapDrawable.Bitmap;
}
}
if(drawable.IntrinsicWidth <= 0 || drawable.IntrinsicHeight <= 0) {
bitmap = Bitmap.CreateBitmap(1, 1, Bitmap.Config.Argb8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.CreateBitmap(drawable.IntrinsicWidth, drawable.IntrinsicHeight, Bitmap.Config.Argb8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.SetBounds(0, 0, canvas.Width, canvas.Height);
drawable.Draw(canvas);
return bitmap;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View currView;
@ -226,7 +200,7 @@ public static Bitmap DrawableToBitmap (Drawable drawable) {
tv.Text = "" + position;
var drawable = App.Kp2a.GetDb()
.DrawableFactory.GetIconDrawable(_act, App.Kp2a.GetDb().KpDatabase, (KeePassLib.PwIcon) position, null, false);
drawable = new BitmapDrawable(DrawableToBitmap(drawable));
drawable = new BitmapDrawable(Util.DrawableToBitmap(drawable));
iv.SetImageDrawable(drawable);
//App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, _act, App.Kp2a.GetDb().KpDatabase, (KeePassLib.PwIcon) position, null, false);

View File

@ -86,6 +86,11 @@ namespace keepass2android
public const Result ExitFileStorageSelectionOk = Result.FirstUser + 8;
public const Result ResultOkPasswordGenerator = Result.FirstUser + 9;
public const string TagsKey = "@tags";
public const string OverrideUrlKey = "@override";
public const string ExpDateKey = "@exp_date";
AppTask _appTask;
private ActivityDesign _design;

View File

@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using KeePassLib;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace keepass2android
{
class KpEntryTemplatedEdit : IEditMode
{
internal class KeyOrderComparer : IComparer<string>
{
private readonly KpEntryTemplatedEdit _kpEntryTemplatedEdit;
public KeyOrderComparer(KpEntryTemplatedEdit kpEntryTemplatedEdit)
{
_kpEntryTemplatedEdit = kpEntryTemplatedEdit;
}
public int Compare(string x, string y)
{
int orderX = _kpEntryTemplatedEdit.GetPosition(x);
int orderY = _kpEntryTemplatedEdit.GetPosition(y);
if (orderX == orderY)
return String.Compare(x, y, StringComparison.CurrentCulture);
else
return orderX.CompareTo(orderY);
}
}
private int GetPosition(string key)
{
int res;
if (!Int32.TryParse(_templateEntry.Strings.ReadSafe("_etm_position_" + key), out res))
return Int32.MaxValue;
return res;
}
private const string EtmTemplateUuid = "_etm_template_uuid";
private const string EtmTitle = "_etm_title_";
private readonly Database _db;
private readonly PwEntry _entry;
private readonly PwEntry _templateEntry;
public static bool IsTemplated(Database db, PwEntry entry)
{
if (entry.Strings.Exists(EtmTemplateUuid))
{
PwUuid templateUuid = new PwUuid(MemUtil.HexStringToByteArray(entry.Strings.ReadSafe(EtmTemplateUuid)));
return db.Entries.ContainsKey(templateUuid);
}
else
return false;
}
public KpEntryTemplatedEdit(Database db, PwEntry entry)
{
_db = db;
_entry = entry;
PwUuid templateUuid = new PwUuid(MemUtil.HexStringToByteArray(entry.Strings.ReadSafe(EtmTemplateUuid)));
_templateEntry = db.Entries[templateUuid];
}
public static void InitializeEntry(PwEntry entry, PwEntry templateEntry)
{
entry.Strings.Set("_etm_template_uuid", new ProtectedString(false, templateEntry.Uuid.ToHexString()));
entry.IconId = templateEntry.IconId;
foreach (string name in templateEntry.Strings.GetKeys())
{
if (name.StartsWith(EtmTitle))
{
String fieldName = name.Substring(EtmTitle.Length);
if (fieldName.StartsWith("@"))
{
if (fieldName == KeePass.TagsKey) entry.Tags = templateEntry.Tags;
if (fieldName == KeePass.OverrideUrlKey) entry.OverrideUrl = templateEntry.OverrideUrl;
if (fieldName == KeePass.ExpDateKey)
{
entry.Expires = templateEntry.Expires;
if (entry.Expires)
entry.ExpiryTime = templateEntry.ExpiryTime;
}
continue;
}
String type = templateEntry.Strings.ReadSafe("_etm_type_" + fieldName);
if (type == "Divider")
continue;
bool protectedField = type.StartsWith("Protected");
entry.Strings.Set(fieldName, new ProtectedString(protectedField, templateEntry.Strings.ReadSafe(fieldName)));
}
}
}
public bool IsVisible(string fieldKey)
{
if (fieldKey == EtmTemplateUuid)
return false;
if (fieldKey == PwDefs.TitleField)
return true;
if ((fieldKey.StartsWith("@") || (PwDefs.IsStandardField(fieldKey))))
{
return !String.IsNullOrEmpty(GetFieldValue(fieldKey))
|| _templateEntry.Strings.Exists(EtmTitle+fieldKey);
}
return true;
}
private string GetFieldValue(string fieldKey)
{
if (fieldKey == KeePass.ExpDateKey)
return _entry.Expires ? _entry.ExpiryTime.ToString(CultureInfo.CurrentUICulture) : "";
if (fieldKey == KeePass.OverrideUrlKey)
return _entry.OverrideUrl;
if (fieldKey == KeePass.TagsKey)
return StrUtil.TagsToString(_entry.Tags, true);
return _entry.Strings.ReadSafe(fieldKey);
}
public IEnumerable<string> SortExtraFieldKeys(IEnumerable<string> keys)
{
var c = new KeyOrderComparer(this);
return keys.OrderBy(s => s, c);
}
public bool ShowAddAttachments
{
get { return false; }
}
public bool ShowAddExtras
{
get { return false; }
}
public static bool IsTemplate(PwEntry entry)
{
if (entry == null) return false;
return entry.Strings.Exists("_etm_template");
}
}
}

View File

@ -11,6 +11,7 @@
android:padding="16dp">
<!-- Title -->
<RelativeLayout
android:id="@+id/title_section"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageButton
@ -35,6 +36,7 @@
</RelativeLayout>
<!--User-->
<LinearLayout
android:id="@+id/user_section"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
@ -50,7 +52,8 @@
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<!-- password-->
<LinearLayout
<LinearLayout
android:id="@+id/password_section"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
@ -111,7 +114,8 @@
</LinearLayout>
</LinearLayout>
<!-- URL -->
<LinearLayout
<LinearLayout
android:id="@+id/url_section"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
@ -127,7 +131,8 @@
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<!-- Comments -->
<LinearLayout
<LinearLayout
android:id="@+id/comments_section"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
@ -141,8 +146,8 @@
android:inputType="textMultiLine" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/entry_extras_label"
<LinearLayout
android:id="@+id/entry_extras_container"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
@ -197,7 +202,8 @@
</LinearLayout>
</LinearLayout>
<!-- Tags -->
<LinearLayout
<LinearLayout
android:id="@+id/tags_section"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
@ -230,7 +236,8 @@
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<!--expires-->
<LinearLayout
<LinearLayout
android:id="@+id/expires_section"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"

View File

@ -27,4 +27,8 @@
android:icon="@drawable/ic_menu_close"
app:showAsAction="always"
/>
<item android:id="@+id/menu_show_all"
android:title="@string/menu_show_all"
app:showAsAction="never"
/>
</menu>

View File

@ -106,7 +106,7 @@
<string name="enter_filename">Enter database filename</string>
<string name="entry_accessed">Accessed</string>
<string name="entry_cancel">Cancel</string>
<string name="entry_comment">Comments</string>
<string name="entry_comment">Notes</string>
<string name="entry_tags">Tags</string>
<string name="entry_override_url">Override URL</string>
<string name="entry_confpassword">Confirm password</string>
@ -144,7 +144,7 @@
<string name="file_browser">File Browser</string>
<string name="generate_password">Generate Password</string>
<string name="group">Group</string>
<string name="hint_comment">comment</string>
<string name="hint_comment">notes</string>
<string name="hint_conf_pass">confirm password</string>
<string name="hint_generated_password">generated password</string>
<string name="hint_group_name">Group name</string>
@ -194,6 +194,7 @@
<string name="menu_search_advanced">Advanced Search</string>
<string name="menu_url">Go to URL</string>
<string name="menu_change_db">Change database</string>
<string name="menu_show_all">Show all fields</string>
<string name="minus">Minus</string>
<string name="never">Never</string>
<string name="yes">Yes</string>
@ -578,6 +579,8 @@
<string name="DuplicateTitle">Copy</string>
<string name="DefaultTemplate">Standard-Eintrag</string>
<string name="ChangeLog_title">Change log</string>

View File

@ -29,6 +29,8 @@ using Android.Views;
using Android.Widget;
using Android.Content.PM;
using Android.Content.Res;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Util;
using KeePassLib.Serialization;
using Uri = Android.Net.Uri;
@ -38,6 +40,35 @@ namespace keepass2android
public class Util {
public static Bitmap DrawableToBitmap(Drawable drawable)
{
Bitmap bitmap = null;
if (drawable is BitmapDrawable)
{
BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable;
if (bitmapDrawable.Bitmap != null)
{
return bitmapDrawable.Bitmap;
}
}
if (drawable.IntrinsicWidth <= 0 || drawable.IntrinsicHeight <= 0)
{
bitmap = Bitmap.CreateBitmap(1, 1, Bitmap.Config.Argb8888); // Single color bitmap will be created of 1x1 pixel
}
else
{
bitmap = Bitmap.CreateBitmap(drawable.IntrinsicWidth, drawable.IntrinsicHeight, Bitmap.Config.Argb8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.SetBounds(0, 0, canvas.Width, canvas.Height);
drawable.Draw(canvas);
return bitmap;
}
public static float convertDpToPixel(float dp, Context context)
{
Resources resources = context.Resources;

View File

@ -149,6 +149,7 @@
<Compile Include="icons\DrawableFactory.cs" />
<Compile Include="KeeChallenge.cs" />
<Compile Include="FixedDrawerLayout.cs" />
<Compile Include="KpEntryTemplatedEdit.cs" />
<Compile Include="MeasuringRelativeLayout.cs" />
<Compile Include="NfcOtpActivity.cs" />
<Compile Include="pluginhost\PluginArrayAdapter.cs" />