#52 Add strike-through for 0 and check setting by default

This commit is contained in:
J-Jamet
2018-03-21 14:17:44 +01:00
parent ae00fd5782
commit 1f7b86d34f
7 changed files with 251 additions and 106 deletions

View File

@@ -28,12 +28,11 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.keepassdroid.app.App;
@@ -88,12 +87,12 @@ public class EntryEditActivity extends LockingHideActivity
// Views
private ScrollView scrollView;
private TextView entryTitleView;
private TextView entryUserNameView;
private TextView entryUrlView;
private TextView entryPasswordView;
private TextView entryConfirmationPasswordView;
private TextView entryCommentView;
private EditText entryTitleView;
private EditText entryUserNameView;
private EditText entryUrlView;
private EditText entryPasswordView;
private EditText entryConfirmationPasswordView;
private EditText entryCommentView;
private ViewGroup entryExtraFieldsContainer;
/**
@@ -123,23 +122,23 @@ public class EntryEditActivity extends LockingHideActivity
super.onCreate(savedInstanceState);
setContentView(R.layout.entry_edit);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.app_name));
setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
scrollView = (ScrollView) findViewById(R.id.entry_scroll);
scrollView = findViewById(R.id.entry_scroll);
scrollView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
entryTitleView = (TextView) findViewById(R.id.entry_title);
entryUserNameView = (TextView) findViewById(R.id.entry_user_name);
entryUrlView = (TextView) findViewById(R.id.entry_url);
entryPasswordView = (TextView) findViewById(R.id.entry_password);
entryConfirmationPasswordView = (TextView) findViewById(R.id.entry_confpassword);
entryCommentView = (TextView) findViewById(R.id.entry_comment);
entryExtraFieldsContainer = (ViewGroup) findViewById(R.id.advanced_container);
entryTitleView = findViewById(R.id.entry_title);
entryUserNameView = findViewById(R.id.entry_user_name);
entryUrlView = findViewById(R.id.entry_url);
entryPasswordView = findViewById(R.id.entry_password);
entryConfirmationPasswordView = findViewById(R.id.entry_confpassword);
entryCommentView = findViewById(R.id.entry_comment);
entryExtraFieldsContainer = findViewById(R.id.advanced_container);
// Likely the app has been killed exit the activity
Database db = App.getDB();
@@ -165,67 +164,47 @@ public class EntryEditActivity extends LockingHideActivity
}
View iconButton = findViewById(R.id.icon_button);
iconButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
IconPickerDialogFragment.launch(EntryEditActivity.this);
}
});
iconButton.setOnClickListener(v ->
IconPickerDialogFragment.launch(EntryEditActivity.this));
// Generate password button
View generatePassword = findViewById(R.id.generate_button);
generatePassword.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
GeneratePasswordDialogFragment generatePasswordDialogFragment = new GeneratePasswordDialogFragment();
generatePasswordDialogFragment.show(getSupportFragmentManager(), "PasswordGeneratorFragment");
}
});
generatePassword.setOnClickListener(v -> {
GeneratePasswordDialogFragment generatePasswordDialogFragment = new GeneratePasswordDialogFragment();
generatePasswordDialogFragment.show(getSupportFragmentManager(), "PasswordGeneratorFragment");
});
// Save button
View save = findViewById(R.id.entry_save);
save.setOnClickListener(new View.OnClickListener() {
save.setOnClickListener(v -> {
if (!validateBeforeSaving()) {
return;
}
mCallbackNewEntry = populateNewEntry();
public void onClick(View v) {
if (!validateBeforeSaving()) {
return;
}
mCallbackNewEntry = populateNewEntry();
OnFinish onFinish = new AfterSave();
EntryEditActivity act = EntryEditActivity.this;
RunnableOnFinish task;
if ( mIsNew ) {
task = new AddEntry(act, App.getDB(), mCallbackNewEntry, onFinish);
} else {
task = new UpdateEntry(act, App.getDB(), mEntry, mCallbackNewEntry, onFinish);
}
ProgressTask pt = new ProgressTask(act, task, R.string.saving_database);
pt.run();
}
});
OnFinish onFinish = new AfterSave();
EntryEditActivity act = EntryEditActivity.this;
RunnableOnFinish task;
if ( mIsNew ) {
task = new AddEntry(act, App.getDB(), mCallbackNewEntry, onFinish);
} else {
task = new UpdateEntry(act, App.getDB(), mEntry, mCallbackNewEntry, onFinish);
}
ProgressTask pt = new ProgressTask(act, task, R.string.saving_database);
pt.run();
});
if (mEntry.allowExtraFields()) {
View add = findViewById(R.id.add_new_field);
add.setVisibility(View.VISIBLE);
add.setOnClickListener(new View.OnClickListener() {
add.setOnClickListener(v -> {
EntryEditNewField ees = new EntryEditNewField(EntryEditActivity.this);
ees.setData("", new ProtectedString(false, ""));
entryExtraFieldsContainer.addView(ees);
@Override
public void onClick(View v) {
EntryEditNewField ees = new EntryEditNewField(EntryEditActivity.this);
ees.setData("", new ProtectedString(false, ""));
entryExtraFieldsContainer.addView(ees);
// Scroll bottom
scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
}
// Scroll bottom
scrollView.post(() -> scrollView.fullScroll(ScrollView.FOCUS_DOWN));
});
}
}
@@ -334,11 +313,9 @@ public class EntryEditActivity extends LockingHideActivity
}
protected void fillData() {
ImageButton currIconButton = (ImageButton) findViewById(R.id.icon_button);
ImageButton currIconButton = findViewById(R.id.icon_button);
App.getDB().drawFactory.assignDrawableTo(currIconButton, getResources(), mEntry.getIcon());
boolean visibilityFont = PreferencesUtil.fieldFontIsInVisibility(this);
entryTitleView.setText(mEntry.getTitle());
entryUserNameView.setText(mEntry.getUsername());
entryUrlView.setText(mEntry.getUrl());
@@ -346,14 +323,21 @@ public class EntryEditActivity extends LockingHideActivity
entryPasswordView.setText(password);
entryConfirmationPasswordView.setText(password);
entryCommentView.setText(mEntry.getNotes());
Util.applyFontVisibilityToTextView(visibilityFont, entryCommentView);
boolean visibilityFontActivated = PreferencesUtil.fieldFontIsInVisibility(this);
if (visibilityFontActivated) {
Util.applyFontVisibilityTo(entryUserNameView);
Util.applyFontVisibilityTo(entryPasswordView);
Util.applyFontVisibilityTo(entryConfirmationPasswordView);
Util.applyFontVisibilityTo(entryCommentView);
}
if (mEntry.allowExtraFields()) {
LinearLayout container = (LinearLayout) findViewById(R.id.advanced_container);
LinearLayout container = findViewById(R.id.advanced_container);
for (Map.Entry<String, ProtectedString> pair : mEntry.getExtraProtectedFields().entrySet()) {
EntryEditNewField entryEditNewField = new EntryEditNewField(EntryEditActivity.this);
entryEditNewField.setData(pair.getKey(), pair.getValue());
entryEditNewField.setFontVisibility(visibilityFont);
entryEditNewField.setFontVisibility(visibilityFontActivated);
container.addView(entryEditNewField);
}
}
@@ -362,7 +346,7 @@ public class EntryEditActivity extends LockingHideActivity
@Override
public void iconPicked(Bundle bundle) {
mSelectedIconID = bundle.getInt(IconPickerDialogFragment.KEY_ICON_ID);
ImageButton currIconButton = (ImageButton) findViewById(R.id.icon_button);
ImageButton currIconButton = findViewById(R.id.icon_button);
currIconButton.setImageResource(Icons.iconToResId(mSelectedIconID));
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.utils;
import android.os.Parcel;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SpannableReplacer {
private final CharSequence mSource;
private final CharSequence mReplacement;
private final Matcher mMatcher;
private int mAppendPosition;
private final boolean mIsSpannable;
public static CharSequence replace(CharSequence source, String regex,
CharSequence replacement) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(source);
return new SpannableReplacer(source, matcher, replacement).doReplace();
}
private SpannableReplacer(CharSequence source, Matcher matcher,
CharSequence replacement) {
mSource = source;
mReplacement = replacement;
mMatcher = matcher;
mAppendPosition = 0;
mIsSpannable = replacement instanceof Spannable;
}
private CharSequence doReplace() {
SpannableStringBuilder buffer = new SpannableStringBuilder();
while (mMatcher.find()) {
appendReplacement(buffer);
}
return appendTail(buffer);
}
private void appendReplacement(SpannableStringBuilder buffer) {
buffer.append(mSource.subSequence(mAppendPosition, mMatcher.start()));
CharSequence replacement = mIsSpannable
? copyCharSequenceWithSpans(mReplacement)
: mReplacement;
buffer.append(replacement);
mAppendPosition = mMatcher.end();
}
public SpannableStringBuilder appendTail(SpannableStringBuilder buffer) {
buffer.append(mSource.subSequence(mAppendPosition, mSource.length()));
return buffer;
}
// This is a weird way of copying spans, but I don't know any better way.
private CharSequence copyCharSequenceWithSpans(CharSequence string) {
Parcel parcel = Parcel.obtain();
try {
TextUtils.writeToParcel(string, parcel, 0);
parcel.setDataPosition(0);
return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
} finally {
parcel.recycle();
}
}
}

View File

@@ -24,6 +24,12 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.net.Uri;
import android.text.Editable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.style.StrikethroughSpan;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
@@ -51,9 +57,66 @@ public class Util {
}
}
public static void applyFontVisibilityToTextView(boolean applyMonospace, TextView textView) {
if (applyMonospace)
textView.setTypeface(Typeface.MONOSPACE);
private final static String stringToStrikeThrough = "0";
/**
* Replace font by monospace and strike through all zeros, must be called after seText()
*/
public static void applyFontVisibilityTo(final TextView textView) {
textView.setText(strikeThroughToZero(textView.getText()));
textView.setTypeface(Typeface.MONOSPACE);
}
/**
* Replace font by monospace and strike through all zeros, must be called after seText()
*/
public static void applyFontVisibilityTo(final EditText editText) {
// Assign spans to default text
editText.setText(strikeThroughToZero(editText.getText()));
// Add spans for each new 0 character
class TextWatcherCustomFont implements TextWatcher {
private boolean applySpannable;
@Override
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
applySpannable = count < after;
}
@Override
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
if (applySpannable) {
String text = charSequence.toString();
if (text.contains(stringToStrikeThrough)) {
for (int index = text.indexOf(stringToStrikeThrough);
index >= 0; index = text.indexOf(stringToStrikeThrough,
index + 1)) {
editText.getText().setSpan(new StrikethroughSpan(),
index,
index + stringToStrikeThrough.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
}
@Override
public void afterTextChanged(Editable editable) {}
};
TextWatcher textWatcher = new TextWatcherCustomFont();
editText.addTextChangedListener(textWatcher);
editText.setTypeface(Typeface.MONOSPACE);
}
private static CharSequence strikeThroughToZero(final CharSequence text) {
if (text.toString().contains(stringToStrikeThrough)) {
SpannableString spannable = new SpannableString(stringToStrikeThrough);
spannable.setSpan(new StrikethroughSpan(),
0,
stringToStrikeThrough.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return SpannableReplacer.replace(text, stringToStrikeThrough, spannable);
}
return text;
}
}

View File

@@ -84,25 +84,25 @@ public class EntryContentsView extends LinearLayout {
inflater.inflate(R.layout.entry_view_contents, this);
userNameContainerView = findViewById(R.id.entry_user_name_container);
userNameView = (TextView) findViewById(R.id.entry_user_name);
userNameActionView = (ImageView) findViewById(R.id.entry_user_name_action_image);
userNameView = findViewById(R.id.entry_user_name);
userNameActionView = findViewById(R.id.entry_user_name_action_image);
passwordContainerView = findViewById(R.id.entry_password_container);
passwordView = (TextView) findViewById(R.id.entry_password);
passwordActionView = (ImageView) findViewById(R.id.entry_password_action_image);
passwordView = findViewById(R.id.entry_password);
passwordActionView = findViewById(R.id.entry_password_action_image);
urlContainerView = findViewById(R.id.entry_url_container);
urlView = (TextView) findViewById(R.id.entry_url);
urlView = findViewById(R.id.entry_url);
commentContainerView = findViewById(R.id.entry_comment_container);
commentView = (TextView) findViewById(R.id.entry_comment);
commentView = findViewById(R.id.entry_comment);
extrasView = (ViewGroup) findViewById(R.id.extra_strings);
extrasView = findViewById(R.id.extra_strings);
creationDateView = (TextView) findViewById(R.id.entry_created);
modificationDateView = (TextView) findViewById(R.id.entry_modified);
lastAccessDateView = (TextView) findViewById(R.id.entry_accessed);
expiresDateView = (TextView) findViewById(R.id.entry_expires);
creationDateView = findViewById(R.id.entry_created);
modificationDateView = findViewById(R.id.entry_modified);
lastAccessDateView = findViewById(R.id.entry_accessed);
expiresDateView = findViewById(R.id.entry_expires);
}
public void applyFontVisibilityToFields(boolean fontInVisibility) {
@@ -113,6 +113,10 @@ public class EntryContentsView extends LinearLayout {
if (userName != null && !userName.isEmpty()) {
userNameContainerView.setVisibility(VISIBLE);
userNameView.setText(userName);
if (fontInVisibility)
Util.applyFontVisibilityTo(userNameView);
} else {
userNameContainerView.setVisibility(GONE);
}
}
@@ -124,6 +128,10 @@ public class EntryContentsView extends LinearLayout {
if (password != null && !password.isEmpty()) {
passwordContainerView.setVisibility(VISIBLE);
passwordView.setText(password);
if (fontInVisibility)
Util.applyFontVisibilityTo(passwordView);
} else {
passwordContainerView.setVisibility(GONE);
}
}
@@ -147,21 +155,25 @@ public class EntryContentsView extends LinearLayout {
if (url != null && !url.isEmpty()) {
urlContainerView.setVisibility(VISIBLE);
urlView.setText(url);
} else {
urlContainerView.setVisibility(GONE);
}
}
public void assignComment(String comment) {
if (comment != null && !comment.isEmpty()) {
commentContainerView.setVisibility(VISIBLE);
Util.applyFontVisibilityToTextView(fontInVisibility, commentView);
commentView.setText(comment);
if (fontInVisibility)
Util.applyFontVisibilityTo(commentView);
} else {
commentContainerView.setVisibility(GONE);
}
}
public void addExtraField(String title, String value, OnClickListener onActionClickListener) {
EntryNewField entryNewField = new EntryNewField(getContext(), null, title, value, onActionClickListener);
entryNewField.applyFontVisibilityToValue(fontInVisibility);
entryNewField.applyFontVisibility(fontInVisibility);
extrasView.addView(entryNewField);
}

View File

@@ -26,6 +26,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -36,7 +37,7 @@ import com.kunzisoft.keepass.R;
public class EntryEditNewField extends RelativeLayout {
private TextView labelView;
private TextView valueView;
private EditText valueView;
private CompoundButton protectionCheckView;
public EntryEditNewField(Context context) {
@@ -55,16 +56,11 @@ public class EntryEditNewField extends RelativeLayout {
inflater.inflate(R.layout.entry_edit_new_field, this);
View deleteView = findViewById(R.id.entry_edit_new_field_delete);
deleteView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
deleteViewFromParent();
}
});
deleteView.setOnClickListener(v -> deleteViewFromParent());
labelView = (TextView) findViewById(R.id.entry_edit_new_field_label);
valueView = (TextView) findViewById(R.id.entry_edit_new_field_value);
protectionCheckView = (CompoundButton) findViewById(R.id.protection);
labelView = findViewById(R.id.entry_edit_new_field_label);
valueView = findViewById(R.id.entry_edit_new_field_value);
protectionCheckView = findViewById(R.id.protection);
}
public void setData(String label, ProtectedString value) {
@@ -89,7 +85,8 @@ public class EntryEditNewField extends RelativeLayout {
}
public void setFontVisibility(boolean applyFontVisibility) {
Util.applyFontVisibilityToTextView(applyFontVisibility, valueView);
if (applyFontVisibility)
Util.applyFontVisibilityTo(valueView);
}
public void deleteViewFromParent() {

View File

@@ -54,17 +54,18 @@ public class EntryNewField extends LinearLayout {
assert inflater != null;
inflater.inflate(R.layout.entry_new_field, this);
labelView = (TextView) findViewById(R.id.title);
valueView = (TextView) findViewById(R.id.value);
actionImageView = (ImageView) findViewById(R.id.action_image);
labelView = findViewById(R.id.title);
valueView = findViewById(R.id.value);
actionImageView = findViewById(R.id.action_image);
setLabel(label);
setValue(value);
setAction(onClickActionListener);
}
public void applyFontVisibilityToValue(boolean changeFont) {
Util.applyFontVisibilityToTextView(changeFont, valueView);
public void applyFontVisibility(boolean fontInVisibility) {
if (fontInVisibility)
Util.applyFontVisibilityTo(valueView);
}
public void setLabel(String label) {

View File

@@ -79,7 +79,7 @@
<bool name="sort_group_before_default" translatable="true">true</bool>
<bool name="sort_ascending_default" translatable="true">true</bool>
<bool name="sort_recycle_bin_bottom_default" translatable="true">true</bool>
<bool name="monospace_font_fields_enable_default" translatable="true">false</bool>
<bool name="monospace_font_fields_enable_default" translatable="true">true</bool>
<string name="clipboard_timeout_default" translatable="false">300000</string>
<string-array name="clipboard_timeout_values">