Improved editing of advanced fields,

display and toggle protected fields like password
This commit is contained in:
Philipp Crocoll 2013-07-12 14:17:20 +02:00
parent 43ea197fd5
commit 3218d2f907
8 changed files with 609 additions and 635 deletions

View File

@ -63,6 +63,7 @@ namespace keepass2android
private int _pos; private int _pos;
AppTask _appTask; AppTask _appTask;
private List<TextView> _protectedTextViews;
protected void SetEntryView() { protected void SetEntryView() {
@ -180,16 +181,15 @@ namespace keepass2android
} }
bool hasExtraFields = false; bool hasExtraFields = false;
foreach (var view in from pair in Entry.Strings where !PwDefs.IsStandardField(pair.Key) orderby pair.Key foreach (var view in from pair in Entry.Strings where !PwDefs.IsStandardField(pair.Key) orderby pair.Key
select CreateEditSection(pair.Key, pair.Value.ReadString())) select CreateEditSection(pair.Key, pair.Value.ReadString(), pair.Value.IsProtected))
{ {
//View view = new EntrySection(this, null, key, pair.Value.ReadString());
extraGroup.AddView(view); extraGroup.AddView(view);
hasExtraFields = true; hasExtraFields = true;
} }
FindViewById(Resource.Id.entry_extra_strings_label).Visibility = hasExtraFields ? ViewStates.Visible : ViewStates.Gone; FindViewById(Resource.Id.entry_extra_strings_label).Visibility = hasExtraFields ? ViewStates.Visible : ViewStates.Gone;
} }
View CreateEditSection(string key, string value) View CreateEditSection(string key, string value, bool isProtected)
{ {
LinearLayout layout = new LinearLayout(this, null) {Orientation = Orientation.Vertical}; LinearLayout layout = new LinearLayout(this, null) {Orientation = Orientation.Vertical};
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
@ -205,6 +205,9 @@ namespace keepass2android
if (value != null) if (value != null)
valueView.Text = value; valueView.Text = value;
valueView.Typeface = Typeface.Monospace; valueView.Typeface = Typeface.Monospace;
if (isProtected)
RegisterProtectedTextView(valueView);
if ((int)Build.VERSION.SdkInt >= 11) if ((int)Build.VERSION.SdkInt >= 11)
valueView.SetTextIsSelectable(true); valueView.SetTextIsSelectable(true);
@ -212,6 +215,11 @@ namespace keepass2android
return layout; return layout;
} }
private void RegisterProtectedTextView(TextView protectedTextView)
{
_protectedTextViews.Add(protectedTextView);
}
Android.Net.Uri WriteBinaryToFile(string key, bool writeToCacheDirectory) Android.Net.Uri WriteBinaryToFile(string key, bool writeToCacheDirectory)
{ {
ProtectedBinary pb = Entry.Binaries.Get(key); ProtectedBinary pb = Entry.Binaries.Get(key);
@ -365,6 +373,7 @@ namespace keepass2android
protected void FillData(bool trimList) protected void FillData(bool trimList)
{ {
_protectedTextViews = new List<TextView>();
ImageView iv = (ImageView)FindViewById(Resource.Id.entry_icon); ImageView iv = (ImageView)FindViewById(Resource.Id.entry_icon);
if (iv != null) if (iv != null)
{ {
@ -388,7 +397,7 @@ namespace keepass2android
PopulateText(Resource.Id.entry_url, Resource.Id.entry_url_label, Entry.Strings.ReadSafe(PwDefs.UrlField)); PopulateText(Resource.Id.entry_url, Resource.Id.entry_url_label, Entry.Strings.ReadSafe(PwDefs.UrlField));
PopulateText(Resource.Id.entry_password, Resource.Id.entry_password_label, Entry.Strings.ReadSafe(PwDefs.PasswordField)); PopulateText(Resource.Id.entry_password, Resource.Id.entry_password_label, Entry.Strings.ReadSafe(PwDefs.PasswordField));
SetPasswordStyle(); RegisterProtectedTextView(FindViewById<TextView>(Resource.Id.entry_password));
PopulateText(Resource.Id.entry_created, Resource.Id.entry_created_label, getDateTime(Entry.CreationTime)); PopulateText(Resource.Id.entry_created, Resource.Id.entry_created_label, getDateTime(Entry.CreationTime));
PopulateText(Resource.Id.entry_modified, Resource.Id.entry_modified_label, getDateTime(Entry.LastModificationTime)); PopulateText(Resource.Id.entry_modified, Resource.Id.entry_modified_label, getDateTime(Entry.LastModificationTime));
@ -411,7 +420,7 @@ namespace keepass2android
PopulateBinaries(trimList); PopulateBinaries(trimList);
SetPasswordStyle();
} }
private void PopulateText(int viewId, int headerViewId,int resId) { private void PopulateText(int viewId, int headerViewId,int resId) {
@ -498,14 +507,19 @@ namespace keepass2android
} }
private void SetPasswordStyle() { private void SetPasswordStyle() {
TextView password = (TextView) FindViewById(Resource.Id.entry_password); foreach (TextView password in _protectedTextViews)
{
if ( _showPassword ) { if (_showPassword)
{
password.TransformationMethod = null; password.TransformationMethod = null;
} else { }
else
{
password.TransformationMethod = PasswordTransformationMethod.Instance; password.TransformationMethod = PasswordTransformationMethod.Instance;
} }
} }
}
protected override void OnResume() protected override void OnResume()
{ {
ClearCache(); ClearCache();

View File

@ -17,6 +17,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Android.App; using Android.App;
using Android.Content; using Android.Content;
using Android.OS; using Android.OS;
@ -446,10 +447,7 @@ namespace keepass2android
String value = valueView.Text; String value = valueView.Text;
bool protect = true; bool protect = ((CheckBox) view.FindViewById(Resource.Id.protection)).Checked;
ProtectedString initialString = State.EntryInDatabase.Strings.Get(key);
if (initialString != null)
protect = initialString.IsProtected;
entry.Strings.Set(key, new ProtectedString(protect, value)); entry.Strings.Set(key, new ProtectedString(protect, value));
} }
@ -648,7 +646,7 @@ namespace keepass2android
ViewGroup binariesGroup = (ViewGroup)FindViewById(Resource.Id.binaries); ViewGroup binariesGroup = (ViewGroup)FindViewById(Resource.Id.binaries);
binariesGroup.RemoveAllViews(); binariesGroup.RemoveAllViews();
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
foreach (KeyValuePair<string, ProtectedBinary> pair in State.Entry.Binaries) foreach (KeyValuePair<string, ProtectedBinary> pair in State.Entry.Binaries.OrderBy(p => p.Key) )
{ {
String key = pair.Key; String key = pair.Key;
Button binaryButton = new Button(this) {Text = key}; Button binaryButton = new Button(this) {Text = key};
@ -790,10 +788,68 @@ namespace keepass2android
((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();
((TextView)ees.FindViewById(Resource.Id.value)).TextChanged += (sender, e) => State.EntryModified = true; ((TextView)ees.FindViewById(Resource.Id.value)).TextChanged += (sender, e) => State.EntryModified = true;
ees.FindViewById(Resource.Id.delete).Click += (sender, e) => DeleteAdvancedString((View)sender);
((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((View)sender);
return ees; return ees;
} }
private void EditAdvancedString(View sender)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
View dlgView = LayoutInflater.Inflate(Resource.Layout.edit_extra_string_dialog, null);
builder.SetView(dlgView);
builder.SetNegativeButton(Android.Resource.String.Cancel, (o, args) => { });
builder.SetPositiveButton(Android.Resource.String.Ok, (o, args) =>
{
CopyFieldFromExtraDialog(sender, o, Resource.Id.title);
CopyFieldFromExtraDialog(sender, o, Resource.Id.value);
CopyCheckboxFromExtraDialog(sender, o, Resource.Id.protection);
});
Dialog dialog = builder.Create();
//setup delete button:
var deleteButton = dlgView.FindViewById<Button>(Resource.Id.delete_extra);
deleteButton.SetCompoundDrawablesWithIntrinsicBounds(Resources.GetDrawable(Android.Resource.Drawable.IcMenuDelete), null, null, null);
deleteButton.Click += (o, args) =>
{
DeleteAdvancedString(sender);
dialog.Dismiss();
};
//copy values:
View ees = (View) sender.Parent;
dlgView.FindViewById<EditText>(Resource.Id.title).Text = ees.FindViewById<EditText>(Resource.Id.title).Text;
dlgView.FindViewById<EditText>(Resource.Id.value).Text = ees.FindViewById<EditText>(Resource.Id.value).Text;
dlgView.FindViewById<CheckBox>(Resource.Id.protection).Checked = ees.FindViewById<CheckBox>(Resource.Id.protection).Checked;
dialog.Show();
}
private void CopyFieldFromExtraDialog(View eesButton, object dialog, int fieldId)
{
var sourceField = ((Dialog)dialog).FindViewById<EditText>(fieldId);
var targetField = ((TextView)((View)eesButton.Parent).FindViewById(fieldId));
if (sourceField.Text != targetField.Text)
{
targetField.Text = sourceField.Text;
State.EntryModified = true;
}
}
private void CopyCheckboxFromExtraDialog(View eesButton, object dialog, int fieldId)
{
var sourceField = ((Dialog)dialog).FindViewById<CheckBox>(fieldId);
var targetField = ((CheckBox)((View)eesButton.Parent).FindViewById(fieldId));
if (sourceField.Checked != targetField.Checked)
{
targetField.Checked = sourceField.Checked;
State.EntryModified = true;
}
}
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);

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:paddingTop="1dip"
android:gravity="center_vertical"
android:layout_height="wrap_content">
<EditText
android:id="@+id/title"
android:singleLine="true"
android:inputType="text"
android:hint="@string/field_name"
style="@style/TextAppearance_EditEntry_Value"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="top|left"
android:layout_marginRight="0dip" />
<EditText
android:id="@+id/value"
android:hint="@string/field_value"
android:inputType="textMultiLine"
style="@style/TextAppearance_EditEntry_Value"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="3"
android:gravity="top|left"
android:layout_marginRight="0dip" />
<ImageButton
android:id="@+id/delete"
style="@style/MinusButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical" />
</LinearLayout>

View File

@ -26,10 +26,17 @@
android:layout_weight="3" android:layout_weight="3"
android:gravity="top|left" android:gravity="top|left"
android:layout_marginRight="0dip" /> android:layout_marginRight="0dip" />
<ImageButton <CheckBox
android:id="@+id/delete" android:id="@+id/protection"
style="@style/MinusButton" android:layout_width="0dip"
android:layout_height="0dip"
android:visibility="gone"
android:text="@string/protection"/>
<Button
android:id="@+id/edit_extra"
android:text="…"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" /> android:gravity="center_vertical"
android:layout_marginRight="8dip" />
</LinearLayout> </LinearLayout>

View File

@ -211,9 +211,10 @@
<string name="error_string_key">A field name is required for each string.</string> <string name="error_string_key">A field name is required for each string.</string>
<string name="field_name">Field Name</string> <string name="field_name">Field Name</string>
<string name="field_value">Field value</string> <string name="field_value">Field value</string>
<string name="protection">Memory Protection</string> <string name="protection">Protected field</string>
<string name="add_binary">Add file attachment...</string> <string name="add_binary">Add file attachment...</string>
<string name="add_extra_string">Add additional string</string> <string name="add_extra_string">Add additional string</string>
<string name="delete_extra_string">Delete additional string</string>
<string name="database_loaded_quickunlock_enabled">Database loaded, QuickUnlock enabled.</string> <string name="database_loaded_quickunlock_enabled">Database loaded, QuickUnlock enabled.</string>
<string name="credentials_dialog_title">Enter server credentials</string> <string name="credentials_dialog_title">Enter server credentials</string>
<string name="UseFileTransactions_title">File transactions</string> <string name="UseFileTransactions_title">File transactions</string>
@ -264,11 +265,9 @@
* External changes are detected and merged when saving\n * External changes are detected and merged when saving\n
* Improved loading performance\n * Improved loading performance\n
* Improved search toolbar with suggestions\n * Improved search toolbar with suggestions\n
? New app logo!\n * Added support for .kdbp format for faster loading/saving\n
? Added support for .kdbp format for faster loading/saving\n * Improved editing of extra strings and hidden display when protected\n
? Improved editing of extra strings and hidden display when protected\n
Thanks to Alex Vallat for his code contributions!\n Thanks to Alex Vallat for his code contributions!\n
Thanks to Niki Hüttner (www.close-cut.de) for the new logo!\n
</string> </string>
<string name="ChangeLog_0_8_3"><b>Version 0.8.3</b>\n <string name="ChangeLog_0_8_3"><b>Version 0.8.3</b>\n
* Username/TAN index displayed in entry list (see settings)\n * Username/TAN index displayed in entry list (see settings)\n

View File

@ -131,7 +131,6 @@
<Compile Include="services\CopyToClipboardService.cs" /> <Compile Include="services\CopyToClipboardService.cs" />
<Compile Include="search\SearchActivity.cs" /> <Compile Include="search\SearchActivity.cs" />
<Compile Include="QuickUnlock.cs" /> <Compile Include="QuickUnlock.cs" />
<Compile Include="views\EntryEditSection.cs" />
<Compile Include="LifecycleDebugActivity.cs" /> <Compile Include="LifecycleDebugActivity.cs" />
<Compile Include="services\QuickUnlockForegroundService.cs" /> <Compile Include="services\QuickUnlockForegroundService.cs" />
<Compile Include="AssemblyInfo.cs" /> <Compile Include="AssemblyInfo.cs" />
@ -172,6 +171,9 @@
<None Include="Resources\drawable-xhdpi\2_action_about.png"> <None Include="Resources\drawable-xhdpi\2_action_about.png">
<Visible>False</Visible> <Visible>False</Visible>
</None> </None>
<AndroidResource Include="Resources\layout\edit_extra_string_dialog.xml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<None Include="settings\RoundsPreference %28Kopie%29.cs"> <None Include="settings\RoundsPreference %28Kopie%29.cs">
<Visible>False</Visible> <Visible>False</Visible>
</None> </None>
@ -565,7 +567,9 @@
<AndroidResource Include="Resources\layout\url_credentials.xml" /> <AndroidResource Include="Resources\layout\url_credentials.xml" />
<AndroidResource Include="Resources\drawable\section_header.xml" /> <AndroidResource Include="Resources\drawable\section_header.xml" />
<AndroidResource Include="Resources\drawable\extra_string_header.xml" /> <AndroidResource Include="Resources\drawable\extra_string_header.xml" />
<AndroidResource Include="Resources\layout\entry_edit_section.xml" /> <AndroidResource Include="Resources\layout\entry_edit_section.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\values-de\strings.xml" /> <AndroidResource Include="Resources\values-de\strings.xml" />
<AndroidResource Include="Resources\values-ca\strings.xml" /> <AndroidResource Include="Resources\values-ca\strings.xml" />
<AndroidResource Include="Resources\values-cs\strings.xml" /> <AndroidResource Include="Resources\values-cs\strings.xml" />
@ -597,7 +601,6 @@
<AndroidResource Include="Resources\layout-v14\entry_view.xml" /> <AndroidResource Include="Resources\layout-v14\entry_view.xml" />
<AndroidResource Include="Resources\layout-v14\entry_edit.xml" /> <AndroidResource Include="Resources\layout-v14\entry_edit.xml" />
<AndroidResource Include="Resources\layout-v14\SaveButton.xml" /> <AndroidResource Include="Resources\layout-v14\SaveButton.xml" />
<AndroidResource Include="Resources\layout-v14\entry_edit_section.xml" />
<AndroidResource Include="Resources\layout-v14\generate_password.xml" /> <AndroidResource Include="Resources\layout-v14\generate_password.xml" />
<AndroidResource Include="Resources\layout-v14\icon_picker.xml" /> <AndroidResource Include="Resources\layout-v14\icon_picker.xml" />
<AndroidResource Include="Resources\layout-v14\password.xml" /> <AndroidResource Include="Resources\layout-v14\password.xml" />

View File

@ -1,82 +0,0 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using Android.Content;
using Android.Runtime;
using Android.Util;
using Android.Widget;
using KeePassLib.Security;
namespace keepass2android.view
{
public class EntryEditSection : LinearLayout
{
public event EventHandler ContentChanged;
public EntryEditSection (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public EntryEditSection(Context context, IAttributeSet attrs) :
base (context, attrs)
{
Initialize();
}
public EntryEditSection(Context context, IAttributeSet attrs, int defStyle) :
base (context, attrs, defStyle)
{
Initialize();
}
private void Initialize()
{
}
public void SetData(String title, ProtectedString value)
{
SetText(Resource.Id.title, title);
SetText(Resource.Id.value, value.ReadString());
}
public ImageButton GetDeleteButton()
{
return (ImageButton)FindViewById(Resource.Id.delete);
}
private void SetText(int resId, String str)
{
if (str != null)
{
TextView tv = (TextView)FindViewById(resId);
tv.Text = str;
tv.TextChanged += (sender, e) => {
if (ContentChanged != null)
ContentChanged(this, new EventArgs());
};
}
}
}
}