mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Kotlinized EntryActivity
This commit is contained in:
@@ -1,484 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* 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 3 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.kunzisoft.keepass.activities;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.kunzisoft.keepass.R;
|
|
||||||
import com.kunzisoft.keepass.activities.lock.LockingHideActivity;
|
|
||||||
import com.kunzisoft.keepass.app.App;
|
|
||||||
import com.kunzisoft.keepass.database.element.Database;
|
|
||||||
import com.kunzisoft.keepass.database.element.EntryVersioned;
|
|
||||||
import com.kunzisoft.keepass.database.element.PwNodeId;
|
|
||||||
import com.kunzisoft.keepass.database.element.security.ProtectedString;
|
|
||||||
import com.kunzisoft.keepass.education.EntryActivityEducation;
|
|
||||||
import com.kunzisoft.keepass.notifications.NotificationCopyingService;
|
|
||||||
import com.kunzisoft.keepass.notifications.NotificationField;
|
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
|
||||||
import com.kunzisoft.keepass.settings.SettingsAutofillActivity;
|
|
||||||
import com.kunzisoft.keepass.timeout.ClipboardHelper;
|
|
||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper;
|
|
||||||
import com.kunzisoft.keepass.utils.EmptyUtils;
|
|
||||||
import com.kunzisoft.keepass.utils.MenuUtil;
|
|
||||||
import com.kunzisoft.keepass.utils.Util;
|
|
||||||
import com.kunzisoft.keepass.view.EntryContentsView;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import kotlin.Unit;
|
|
||||||
import kotlin.jvm.functions.Function2;
|
|
||||||
|
|
||||||
import static com.kunzisoft.keepass.settings.PreferencesUtil.isClipboardNotificationsEnable;
|
|
||||||
import static com.kunzisoft.keepass.settings.PreferencesUtil.isFirstTimeAskAllowCopyPasswordAndProtectedFields;
|
|
||||||
|
|
||||||
public class EntryActivity extends LockingHideActivity {
|
|
||||||
private final static String TAG = EntryActivity.class.getName();
|
|
||||||
|
|
||||||
public static final String KEY_ENTRY = "entry";
|
|
||||||
|
|
||||||
private ImageView titleIconView;
|
|
||||||
private TextView titleView;
|
|
||||||
private EntryContentsView entryContentsView;
|
|
||||||
private Toolbar toolbar;
|
|
||||||
|
|
||||||
protected EntryVersioned mEntry;
|
|
||||||
private boolean mShowPassword;
|
|
||||||
|
|
||||||
private ClipboardHelper clipboardHelper;
|
|
||||||
private boolean firstLaunchOfActivity;
|
|
||||||
|
|
||||||
private int iconColor;
|
|
||||||
|
|
||||||
public static void launch(Activity activity, EntryVersioned pw, boolean readOnly) {
|
|
||||||
if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) {
|
|
||||||
Intent intent = new Intent(activity, EntryActivity.class);
|
|
||||||
intent.putExtra(KEY_ENTRY, pw.getNodeId());
|
|
||||||
ReadOnlyHelper.INSTANCE.putReadOnlyInIntent(intent, readOnly);
|
|
||||||
activity.startActivityForResult(intent, EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
setContentView(R.layout.entry_view);
|
|
||||||
|
|
||||||
toolbar = findViewById(R.id.toolbar);
|
|
||||||
setSupportActionBar(toolbar);
|
|
||||||
assert getSupportActionBar() != null;
|
|
||||||
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
|
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
||||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
|
||||||
|
|
||||||
Database db = App.Companion.getCurrentDatabase();
|
|
||||||
setReadOnly(db.isReadOnly() || getReadOnly());
|
|
||||||
|
|
||||||
mShowPassword = !PreferencesUtil.isPasswordMask(this);
|
|
||||||
|
|
||||||
// Get Entry from UUID
|
|
||||||
Intent i = getIntent();
|
|
||||||
PwNodeId keyEntry;
|
|
||||||
try {
|
|
||||||
keyEntry = i.getParcelableExtra(KEY_ENTRY);
|
|
||||||
mEntry = db.getEntryById(keyEntry);
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
Log.e(TAG, "Unable to retrieve the entry key");
|
|
||||||
}
|
|
||||||
if (mEntry == null) {
|
|
||||||
Toast.makeText(this, R.string.entry_not_found, Toast.LENGTH_LONG).show();
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update last access time.
|
|
||||||
mEntry.touch(false, false);
|
|
||||||
|
|
||||||
// Retrieve the textColor to tint the icon
|
|
||||||
int[] attrs = {R.attr.textColorInverse};
|
|
||||||
TypedArray ta = getTheme().obtainStyledAttributes(attrs);
|
|
||||||
iconColor = ta.getColor(0, Color.WHITE);
|
|
||||||
|
|
||||||
// Refresh Menu contents in case onCreateMenuOptions was called before mEntry was set
|
|
||||||
invalidateOptionsMenu();
|
|
||||||
|
|
||||||
// Get views
|
|
||||||
titleIconView = findViewById(R.id.entry_icon);
|
|
||||||
titleView = findViewById(R.id.entry_title);
|
|
||||||
entryContentsView = findViewById(R.id.entry_contents);
|
|
||||||
entryContentsView.applyFontVisibilityToFields(PreferencesUtil.fieldFontIsInVisibility(this));
|
|
||||||
|
|
||||||
// Init the clipboard helper
|
|
||||||
clipboardHelper = new ClipboardHelper(this);
|
|
||||||
firstLaunchOfActivity = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
// Fill data in resume to update from EntryEditActivity
|
|
||||||
fillData();
|
|
||||||
invalidateOptionsMenu();
|
|
||||||
|
|
||||||
Database database = App.Companion.getCurrentDatabase();
|
|
||||||
// Start to manage field reference to copy a value from ref
|
|
||||||
database.startManageEntry(mEntry);
|
|
||||||
|
|
||||||
boolean containsUsernameToCopy =
|
|
||||||
mEntry.getUsername().length() > 0;
|
|
||||||
boolean containsPasswordToCopy =
|
|
||||||
(mEntry.getPassword().length() > 0
|
|
||||||
&& PreferencesUtil.allowCopyPasswordAndProtectedFields(this));
|
|
||||||
boolean containsExtraFieldToCopy =
|
|
||||||
(mEntry.allowExtraFields()
|
|
||||||
&& ((mEntry.containsCustomFields()
|
|
||||||
&& mEntry.containsCustomFieldsNotProtected())
|
|
||||||
|| (mEntry.containsCustomFields()
|
|
||||||
&& mEntry.containsCustomFieldsProtected()
|
|
||||||
&& PreferencesUtil.allowCopyPasswordAndProtectedFields(this))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// If notifications enabled in settings
|
|
||||||
// Don't if application timeout
|
|
||||||
if (firstLaunchOfActivity && isClipboardNotificationsEnable(getApplicationContext())) {
|
|
||||||
if (containsUsernameToCopy
|
|
||||||
|| containsPasswordToCopy
|
|
||||||
|| containsExtraFieldToCopy
|
|
||||||
) {
|
|
||||||
// username already copied, waiting for user's action before copy password.
|
|
||||||
Intent intent = new Intent(this, NotificationCopyingService.class);
|
|
||||||
intent.setAction(NotificationCopyingService.ACTION_NEW_NOTIFICATION);
|
|
||||||
if (mEntry.getTitle() != null)
|
|
||||||
intent.putExtra(NotificationCopyingService.EXTRA_ENTRY_TITLE, mEntry.getTitle());
|
|
||||||
// Construct notification fields
|
|
||||||
ArrayList<NotificationField> notificationFields = new ArrayList<>();
|
|
||||||
// Add username if exists to notifications
|
|
||||||
if (containsUsernameToCopy)
|
|
||||||
notificationFields.add(
|
|
||||||
new NotificationField(
|
|
||||||
NotificationField.NotificationFieldId.USERNAME,
|
|
||||||
mEntry.getUsername(),
|
|
||||||
getResources()));
|
|
||||||
// Add password to notifications
|
|
||||||
if (containsPasswordToCopy) {
|
|
||||||
notificationFields.add(
|
|
||||||
new NotificationField(
|
|
||||||
NotificationField.NotificationFieldId.PASSWORD,
|
|
||||||
mEntry.getPassword(),
|
|
||||||
getResources()));
|
|
||||||
}
|
|
||||||
// Add extra fields
|
|
||||||
if (containsExtraFieldToCopy) {
|
|
||||||
try {
|
|
||||||
mEntry.getFields().doActionToAllCustomProtectedField(new Function2<String, ProtectedString, Unit>() {
|
|
||||||
private int anonymousFieldNumber = 0;
|
|
||||||
@Override
|
|
||||||
public Unit invoke(String key, ProtectedString value) {
|
|
||||||
//If value is not protected or allowed
|
|
||||||
if (!value.isProtected() || PreferencesUtil.allowCopyPasswordAndProtectedFields(EntryActivity.this)) {
|
|
||||||
notificationFields.add(
|
|
||||||
new NotificationField(
|
|
||||||
NotificationField.NotificationFieldId.getAnonymousFieldId()[anonymousFieldNumber],
|
|
||||||
value.toString(),
|
|
||||||
key,
|
|
||||||
getResources()));
|
|
||||||
anonymousFieldNumber++;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (ArrayIndexOutOfBoundsException e) {
|
|
||||||
Log.w(TAG, "Only " + NotificationField.NotificationFieldId.getAnonymousFieldId().length +
|
|
||||||
" anonymous notifications are available");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add notifications
|
|
||||||
intent.putParcelableArrayListExtra(NotificationCopyingService.EXTRA_FIELDS, notificationFields);
|
|
||||||
|
|
||||||
startService(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
database.stopManageEntry(mEntry);
|
|
||||||
}
|
|
||||||
firstLaunchOfActivity = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void fillData() {
|
|
||||||
Database database = App.Companion.getCurrentDatabase();
|
|
||||||
database.startManageEntry(mEntry);
|
|
||||||
// Assign title icon
|
|
||||||
database.getDrawFactory().assignDatabaseIconTo(this, titleIconView, mEntry.getIcon(), iconColor);
|
|
||||||
|
|
||||||
// Assign title text
|
|
||||||
titleView.setText(mEntry.getVisualTitle());
|
|
||||||
|
|
||||||
// Assign basic fields
|
|
||||||
entryContentsView.assignUserName(mEntry.getUsername());
|
|
||||||
entryContentsView.assignUserNameCopyListener(view ->
|
|
||||||
clipboardHelper.timeoutCopyToClipboard(mEntry.getUsername(),
|
|
||||||
getString(R.string.copy_field, getString(R.string.entry_user_name)))
|
|
||||||
);
|
|
||||||
|
|
||||||
boolean allowCopyPassword = PreferencesUtil.allowCopyPasswordAndProtectedFields(this);
|
|
||||||
entryContentsView.assignPassword(mEntry.getPassword(), allowCopyPassword);
|
|
||||||
if (allowCopyPassword) {
|
|
||||||
entryContentsView.assignPasswordCopyListener(view ->
|
|
||||||
clipboardHelper.timeoutCopyToClipboard(mEntry.getPassword(),
|
|
||||||
getString(R.string.copy_field, getString(R.string.entry_password)))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// If dialog not already shown
|
|
||||||
if (isFirstTimeAskAllowCopyPasswordAndProtectedFields(this)) {
|
|
||||||
entryContentsView.assignPasswordCopyListener(v -> {
|
|
||||||
String message = getString(R.string.allow_copy_password_warning) +
|
|
||||||
"\n\n" +
|
|
||||||
getString(R.string.clipboard_warning);
|
|
||||||
AlertDialog warningDialog = new AlertDialog.Builder(EntryActivity.this)
|
|
||||||
.setMessage(message).create();
|
|
||||||
warningDialog.setButton(AlertDialog.BUTTON1, getText(android.R.string.ok),
|
|
||||||
(dialog, which) -> {
|
|
||||||
PreferencesUtil.setAllowCopyPasswordAndProtectedFields(EntryActivity.this, true);
|
|
||||||
dialog.dismiss();
|
|
||||||
fillData();
|
|
||||||
});
|
|
||||||
warningDialog.setButton(AlertDialog.BUTTON2, getText(android.R.string.cancel),
|
|
||||||
(dialog, which) -> {
|
|
||||||
PreferencesUtil.setAllowCopyPasswordAndProtectedFields(EntryActivity.this, false);
|
|
||||||
dialog.dismiss();
|
|
||||||
fillData();
|
|
||||||
});
|
|
||||||
warningDialog.show();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
entryContentsView.assignPasswordCopyListener(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entryContentsView.assignURL(mEntry.getUrl());
|
|
||||||
|
|
||||||
entryContentsView.setHiddenPasswordStyle(!mShowPassword);
|
|
||||||
entryContentsView.assignComment(mEntry.getNotes());
|
|
||||||
|
|
||||||
// Assign custom fields
|
|
||||||
if (mEntry.allowExtraFields()) {
|
|
||||||
entryContentsView.clearExtraFields();
|
|
||||||
|
|
||||||
mEntry.getFields().doActionToAllCustomProtectedField((label, value) -> {
|
|
||||||
boolean showAction = (!value.isProtected() || PreferencesUtil.allowCopyPasswordAndProtectedFields(EntryActivity.this));
|
|
||||||
entryContentsView.addExtraField(label, value, showAction, view ->
|
|
||||||
clipboardHelper.timeoutCopyToClipboard(
|
|
||||||
value.toString(),
|
|
||||||
getString(R.string.copy_field, label)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign dates
|
|
||||||
entryContentsView.assignCreationDate(mEntry.getCreationTime().getDate());
|
|
||||||
entryContentsView.assignModificationDate(mEntry.getLastModificationTime().getDate());
|
|
||||||
entryContentsView.assignLastAccessDate(mEntry.getLastAccessTime().getDate());
|
|
||||||
Date expires = mEntry.getExpiryTime().getDate();
|
|
||||||
if ( mEntry.isExpires() ) {
|
|
||||||
entryContentsView.assignExpiresDate(expires);
|
|
||||||
} else {
|
|
||||||
entryContentsView.assignExpiresDate(getString(R.string.never));
|
|
||||||
}
|
|
||||||
|
|
||||||
database.stopManageEntry(mEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
switch (requestCode) {
|
|
||||||
case EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE:
|
|
||||||
// Not directly get the entry from intent data but from database
|
|
||||||
fillData();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void changeShowPasswordIcon(MenuItem togglePassword) {
|
|
||||||
if ( mShowPassword ) {
|
|
||||||
togglePassword.setTitle(R.string.menu_hide_password);
|
|
||||||
togglePassword.setIcon(R.drawable.ic_visibility_off_white_24dp);
|
|
||||||
} else {
|
|
||||||
togglePassword.setTitle(R.string.menu_showpass);
|
|
||||||
togglePassword.setIcon(R.drawable.ic_visibility_white_24dp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
super.onCreateOptionsMenu(menu);
|
|
||||||
|
|
||||||
MenuInflater inflater = getMenuInflater();
|
|
||||||
MenuUtil.INSTANCE.contributionMenuInflater(inflater, menu);
|
|
||||||
inflater.inflate(R.menu.entry, menu);
|
|
||||||
inflater.inflate(R.menu.database_lock, menu);
|
|
||||||
|
|
||||||
if (getReadOnly()) {
|
|
||||||
MenuItem edit = menu.findItem(R.id.menu_edit);
|
|
||||||
if (edit != null)
|
|
||||||
edit.setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
MenuItem togglePassword = menu.findItem(R.id.menu_toggle_pass);
|
|
||||||
if (entryContentsView != null && togglePassword != null) {
|
|
||||||
if (entryContentsView.isPasswordPresent() || entryContentsView.atLeastOneFieldProtectedPresent()) {
|
|
||||||
changeShowPasswordIcon(togglePassword);
|
|
||||||
} else {
|
|
||||||
togglePassword.setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MenuItem gotoUrl = menu.findItem(R.id.menu_goto_url);
|
|
||||||
if (gotoUrl != null) {
|
|
||||||
// In API >= 11 onCreateOptionsMenu may be called before onCreate completes
|
|
||||||
// so mEntry may not be set
|
|
||||||
if (mEntry == null) {
|
|
||||||
gotoUrl.setVisible(false);
|
|
||||||
} else {
|
|
||||||
String url = mEntry.getUrl();
|
|
||||||
if (EmptyUtils.INSTANCE.isNullOrEmpty(url)) {
|
|
||||||
// disable button if url is not available
|
|
||||||
gotoUrl.setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show education views
|
|
||||||
new Handler().post(() -> performedNextEducation(new EntryActivityEducation(this), menu));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void performedNextEducation(EntryActivityEducation entryActivityEducation,
|
|
||||||
Menu menu) {
|
|
||||||
if (entryContentsView != null
|
|
||||||
&& entryContentsView.isUserNamePresent()
|
|
||||||
&& entryActivityEducation.checkAndPerformedEntryCopyEducation(
|
|
||||||
findViewById(R.id.entry_user_name_action_image),
|
|
||||||
tapTargetView -> {
|
|
||||||
clipboardHelper.timeoutCopyToClipboard(mEntry.getUsername(),
|
|
||||||
getString(R.string.copy_field,
|
|
||||||
getString(R.string.entry_user_name)));
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
tapTargetView -> {
|
|
||||||
// Launch autofill settings
|
|
||||||
startActivity(new Intent(EntryActivity.this, SettingsAutofillActivity.class));
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
else if (toolbar.findViewById(R.id.menu_edit) != null
|
|
||||||
&& entryActivityEducation.checkAndPerformedEntryEditEducation(
|
|
||||||
toolbar.findViewById(R.id.menu_edit),
|
|
||||||
tapTargetView -> {
|
|
||||||
onOptionsItemSelected(menu.findItem(R.id.menu_edit));
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
tapTargetView -> {
|
|
||||||
// Open Keepass doc to create field references
|
|
||||||
startActivity(new Intent(Intent.ACTION_VIEW,
|
|
||||||
Uri.parse(getString(R.string.field_references_url))));
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
switch ( item.getItemId() ) {
|
|
||||||
case R.id.menu_contribute:
|
|
||||||
return MenuUtil.INSTANCE.onContributionItemSelected(this);
|
|
||||||
|
|
||||||
case R.id.menu_toggle_pass:
|
|
||||||
mShowPassword = !mShowPassword;
|
|
||||||
changeShowPasswordIcon(item);
|
|
||||||
entryContentsView.setHiddenPasswordStyle(!mShowPassword);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.menu_edit:
|
|
||||||
EntryEditActivity.launch(EntryActivity.this, mEntry);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.menu_goto_url:
|
|
||||||
String url;
|
|
||||||
url = mEntry.getUrl();
|
|
||||||
|
|
||||||
// Default http:// if no protocol specified
|
|
||||||
if ( ! url.contains("://") ) {
|
|
||||||
url = "http://" + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Util.gotoUrl(this, url);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
Toast.makeText(this, R.string.no_url_handler, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.menu_lock:
|
|
||||||
lockAndExit();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case android.R.id.home :
|
|
||||||
finish(); // close this activity and return to preview activity (if there is any)
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
// Transit data in previous Activity after an update
|
|
||||||
/*
|
|
||||||
TODO Slowdown when add entry as result
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mEntry);
|
|
||||||
setResult(EntryEditActivity.UPDATE_ENTRY_RESULT_CODE, intent);
|
|
||||||
*/
|
|
||||||
super.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,389 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 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 3 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.kunzisoft.keepass.activities
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.support.v7.app.AlertDialog
|
||||||
|
import android.support.v7.widget.Toolbar
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.activities.lock.LockingHideActivity
|
||||||
|
import com.kunzisoft.keepass.app.App
|
||||||
|
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||||
|
import com.kunzisoft.keepass.database.element.PwNodeId
|
||||||
|
import com.kunzisoft.keepass.education.EntryActivityEducation
|
||||||
|
import com.kunzisoft.keepass.notifications.NotificationEntryCopyManager
|
||||||
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.settings.PreferencesUtil.isFirstTimeAskAllowCopyPasswordAndProtectedFields
|
||||||
|
import com.kunzisoft.keepass.settings.SettingsAutofillActivity
|
||||||
|
import com.kunzisoft.keepass.timeout.ClipboardHelper
|
||||||
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
|
import com.kunzisoft.keepass.utils.MenuUtil
|
||||||
|
import com.kunzisoft.keepass.utils.Util
|
||||||
|
import com.kunzisoft.keepass.view.EntryContentsView
|
||||||
|
|
||||||
|
class EntryActivity : LockingHideActivity() {
|
||||||
|
|
||||||
|
private var titleIconView: ImageView? = null
|
||||||
|
private var titleView: TextView? = null
|
||||||
|
private var entryContentsView: EntryContentsView? = null
|
||||||
|
private var toolbar: Toolbar? = null
|
||||||
|
|
||||||
|
private var mEntry: EntryVersioned? = null
|
||||||
|
private var mShowPassword: Boolean = false
|
||||||
|
|
||||||
|
private var clipboardHelper: ClipboardHelper? = null
|
||||||
|
private var firstLaunchOfActivity: Boolean = false
|
||||||
|
|
||||||
|
private var iconColor: Int = 0
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setContentView(R.layout.entry_view)
|
||||||
|
|
||||||
|
toolbar = findViewById(R.id.toolbar)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp)
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
|
||||||
|
val currentDatabase = App.currentDatabase
|
||||||
|
readOnly = currentDatabase.isReadOnly || readOnly
|
||||||
|
|
||||||
|
mShowPassword = !PreferencesUtil.isPasswordMask(this)
|
||||||
|
|
||||||
|
// Get Entry from UUID
|
||||||
|
try {
|
||||||
|
val keyEntry: PwNodeId<*> = intent.getParcelableExtra(KEY_ENTRY)
|
||||||
|
mEntry = currentDatabase.getEntryById(keyEntry)
|
||||||
|
} catch (e: ClassCastException) {
|
||||||
|
Log.e(TAG, "Unable to retrieve the entry key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEntry == null) {
|
||||||
|
Toast.makeText(this, R.string.entry_not_found, Toast.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update last access time.
|
||||||
|
mEntry?.touch(modified = false, touchParents = false)
|
||||||
|
|
||||||
|
// Retrieve the textColor to tint the icon
|
||||||
|
iconColor = theme.
|
||||||
|
obtainStyledAttributes(intArrayOf(R.attr.textColorInverse))
|
||||||
|
.getColor(0, Color.WHITE)
|
||||||
|
|
||||||
|
// Refresh Menu contents in case onCreateMenuOptions was called before mEntry was set
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
|
||||||
|
// Get views
|
||||||
|
titleIconView = findViewById(R.id.entry_icon)
|
||||||
|
titleView = findViewById(R.id.entry_title)
|
||||||
|
entryContentsView = findViewById(R.id.entry_contents)
|
||||||
|
entryContentsView?.applyFontVisibilityToFields(PreferencesUtil.fieldFontIsInVisibility(this))
|
||||||
|
|
||||||
|
// Init the clipboard helper
|
||||||
|
clipboardHelper = ClipboardHelper(this)
|
||||||
|
firstLaunchOfActivity = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
mEntry?.let { entry ->
|
||||||
|
// Fill data in resume to update from EntryEditActivity
|
||||||
|
fillEntryDataInContentsView(entry)
|
||||||
|
// Refresh Menu
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
// Manage entry copy to start notification if allowed
|
||||||
|
NotificationEntryCopyManager.launchNotificationIfAllowed(this,
|
||||||
|
firstLaunchOfActivity,
|
||||||
|
entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
firstLaunchOfActivity = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fillEntryDataInContentsView(entry: EntryVersioned) {
|
||||||
|
|
||||||
|
val database = App.currentDatabase
|
||||||
|
database.startManageEntry(entry)
|
||||||
|
// Assign title icon
|
||||||
|
database.drawFactory.assignDatabaseIconTo(this, titleIconView, entry.icon, iconColor)
|
||||||
|
|
||||||
|
// Assign title text
|
||||||
|
titleView?.text = entry.getVisualTitle()
|
||||||
|
|
||||||
|
// Assign basic fields
|
||||||
|
entryContentsView?.assignUserName(entry.username)
|
||||||
|
entryContentsView?.assignUserNameCopyListener(View.OnClickListener {
|
||||||
|
clipboardHelper?.timeoutCopyToClipboard(entry.username,
|
||||||
|
getString(R.string.copy_field,
|
||||||
|
getString(R.string.entry_user_name)))
|
||||||
|
})
|
||||||
|
|
||||||
|
val allowCopyPassword = PreferencesUtil.allowCopyPasswordAndProtectedFields(this)
|
||||||
|
entryContentsView?.assignPassword(entry.password, allowCopyPassword)
|
||||||
|
if (allowCopyPassword) {
|
||||||
|
entryContentsView?.assignPasswordCopyListener(View.OnClickListener {
|
||||||
|
clipboardHelper?.timeoutCopyToClipboard(entry.password,
|
||||||
|
getString(R.string.copy_field,
|
||||||
|
getString(R.string.entry_password)))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// If dialog not already shown
|
||||||
|
if (isFirstTimeAskAllowCopyPasswordAndProtectedFields(this)) {
|
||||||
|
entryContentsView?.assignPasswordCopyListener(View.OnClickListener {
|
||||||
|
val message = getString(R.string.allow_copy_password_warning) +
|
||||||
|
"\n\n" +
|
||||||
|
getString(R.string.clipboard_warning)
|
||||||
|
val warningDialog = AlertDialog.Builder(this@EntryActivity)
|
||||||
|
.setMessage(message).create()
|
||||||
|
warningDialog.setButton(AlertDialog.BUTTON1, getText(android.R.string.ok)
|
||||||
|
) { dialog, _ ->
|
||||||
|
PreferencesUtil.setAllowCopyPasswordAndProtectedFields(this@EntryActivity, true)
|
||||||
|
dialog.dismiss()
|
||||||
|
fillEntryDataInContentsView(entry)
|
||||||
|
}
|
||||||
|
warningDialog.setButton(AlertDialog.BUTTON2, getText(android.R.string.cancel)
|
||||||
|
) { dialog, _ ->
|
||||||
|
PreferencesUtil.setAllowCopyPasswordAndProtectedFields(this@EntryActivity, false)
|
||||||
|
dialog.dismiss()
|
||||||
|
fillEntryDataInContentsView(entry)
|
||||||
|
}
|
||||||
|
warningDialog.show()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
entryContentsView?.assignPasswordCopyListener(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entryContentsView?.assignURL(entry.url)
|
||||||
|
entryContentsView?.setHiddenPasswordStyle(!mShowPassword)
|
||||||
|
entryContentsView?.assignComment(entry.notes)
|
||||||
|
|
||||||
|
// Assign custom fields
|
||||||
|
if (entry.allowExtraFields()) {
|
||||||
|
entryContentsView?.clearExtraFields()
|
||||||
|
|
||||||
|
entry.fields.doActionToAllCustomProtectedField { label, value ->
|
||||||
|
val showAction = !value.isProtected || PreferencesUtil.allowCopyPasswordAndProtectedFields(this@EntryActivity)
|
||||||
|
entryContentsView?.addExtraField(label, value, showAction, View.OnClickListener {
|
||||||
|
clipboardHelper?.timeoutCopyToClipboard(
|
||||||
|
value.toString(),
|
||||||
|
getString(R.string.copy_field, label)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign dates
|
||||||
|
entry.creationTime.date?.let {
|
||||||
|
entryContentsView?.assignCreationDate(it)
|
||||||
|
}
|
||||||
|
entry.lastModificationTime.date?.let {
|
||||||
|
entryContentsView?.assignModificationDate(it)
|
||||||
|
}
|
||||||
|
entry.lastAccessTime.date?.let {
|
||||||
|
entryContentsView?.assignLastAccessDate(it)
|
||||||
|
}
|
||||||
|
val expires = entry.expiryTime.date
|
||||||
|
if (entry.isExpires && expires != null) {
|
||||||
|
entryContentsView?.assignExpiresDate(expires)
|
||||||
|
} else {
|
||||||
|
entryContentsView?.assignExpiresDate(getString(R.string.never))
|
||||||
|
}
|
||||||
|
|
||||||
|
database.stopManageEntry(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
when (requestCode) {
|
||||||
|
EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE ->
|
||||||
|
// Not directly get the entry from intent data but from database
|
||||||
|
mEntry?.let {
|
||||||
|
fillEntryDataInContentsView(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeShowPasswordIcon(togglePassword: MenuItem?) {
|
||||||
|
if (mShowPassword) {
|
||||||
|
togglePassword?.setTitle(R.string.menu_hide_password)
|
||||||
|
togglePassword?.setIcon(R.drawable.ic_visibility_off_white_24dp)
|
||||||
|
} else {
|
||||||
|
togglePassword?.setTitle(R.string.menu_showpass)
|
||||||
|
togglePassword?.setIcon(R.drawable.ic_visibility_white_24dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
super.onCreateOptionsMenu(menu)
|
||||||
|
|
||||||
|
val inflater = menuInflater
|
||||||
|
MenuUtil.contributionMenuInflater(inflater, menu)
|
||||||
|
inflater.inflate(R.menu.entry, menu)
|
||||||
|
inflater.inflate(R.menu.database_lock, menu)
|
||||||
|
|
||||||
|
if (readOnly) {
|
||||||
|
menu.findItem(R.id.menu_edit)?.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
val togglePassword = menu.findItem(R.id.menu_toggle_pass)
|
||||||
|
entryContentsView?.let {
|
||||||
|
if (it.isPasswordPresent || it.atLeastOneFieldProtectedPresent()) {
|
||||||
|
changeShowPasswordIcon(togglePassword)
|
||||||
|
} else {
|
||||||
|
togglePassword?.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val gotoUrl = menu.findItem(R.id.menu_goto_url)
|
||||||
|
gotoUrl?.apply {
|
||||||
|
// In API >= 11 onCreateOptionsMenu may be called before onCreate completes
|
||||||
|
// so mEntry may not be set
|
||||||
|
if (mEntry == null) {
|
||||||
|
isVisible = false
|
||||||
|
} else {
|
||||||
|
if (mEntry?.url?.isEmpty() != false) {
|
||||||
|
// disable button if url is not available
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show education views
|
||||||
|
Handler().post { performedNextEducation(EntryActivityEducation(this), menu) }
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun performedNextEducation(entryActivityEducation: EntryActivityEducation,
|
||||||
|
menu: Menu) {
|
||||||
|
if (entryContentsView?.isUserNamePresent == true
|
||||||
|
&& entryActivityEducation.checkAndPerformedEntryCopyEducation(
|
||||||
|
findViewById(R.id.entry_user_name_action_image),
|
||||||
|
{
|
||||||
|
clipboardHelper?.timeoutCopyToClipboard(mEntry!!.username,
|
||||||
|
getString(R.string.copy_field,
|
||||||
|
getString(R.string.entry_user_name)))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Launch autofill settings
|
||||||
|
startActivity(Intent(this@EntryActivity, SettingsAutofillActivity::class.java))
|
||||||
|
}))
|
||||||
|
else if (toolbar?.findViewById<View>(R.id.menu_edit) != null && entryActivityEducation.checkAndPerformedEntryEditEducation(
|
||||||
|
toolbar!!.findViewById(R.id.menu_edit),
|
||||||
|
{
|
||||||
|
onOptionsItemSelected(menu.findItem(R.id.menu_edit))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Open Keepass doc to create field references
|
||||||
|
startActivity(Intent(Intent.ACTION_VIEW,
|
||||||
|
Uri.parse(getString(R.string.field_references_url))))
|
||||||
|
}))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.menu_contribute -> return MenuUtil.onContributionItemSelected(this)
|
||||||
|
|
||||||
|
R.id.menu_toggle_pass -> {
|
||||||
|
mShowPassword = !mShowPassword
|
||||||
|
changeShowPasswordIcon(item)
|
||||||
|
entryContentsView?.setHiddenPasswordStyle(!mShowPassword)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.menu_edit -> {
|
||||||
|
EntryEditActivity.launch(this@EntryActivity, mEntry)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.menu_goto_url -> {
|
||||||
|
var url: String = mEntry?.url ?: ""
|
||||||
|
|
||||||
|
// Default http:// if no protocol specified
|
||||||
|
if (!url.contains("://")) {
|
||||||
|
url = "http://$url"
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Util.gotoUrl(this, url)
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
Toast.makeText(this, R.string.no_url_handler, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.menu_lock -> {
|
||||||
|
lockAndExit()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
android.R.id.home -> finish() // close this activity and return to preview activity (if there is any)
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun finish() {
|
||||||
|
// Transit data in previous Activity after an update
|
||||||
|
/*
|
||||||
|
TODO Slowdown when add entry as result
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mEntry);
|
||||||
|
setResult(EntryEditActivity.UPDATE_ENTRY_RESULT_CODE, intent);
|
||||||
|
*/
|
||||||
|
super.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = EntryActivity::class.java.name
|
||||||
|
|
||||||
|
const val KEY_ENTRY = "entry"
|
||||||
|
|
||||||
|
fun launch(activity: Activity, pw: EntryVersioned, readOnly: Boolean) {
|
||||||
|
if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
|
||||||
|
val intent = Intent(activity, EntryActivity::class.java)
|
||||||
|
intent.putExtra(KEY_ENTRY, pw.nodeId)
|
||||||
|
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly)
|
||||||
|
activity.startActivityForResult(intent, EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -503,7 +503,7 @@ public class GroupActivity extends LockingActivity
|
|||||||
EntryVersioned entry = ((EntryVersioned) node);
|
EntryVersioned entry = ((EntryVersioned) node);
|
||||||
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(),
|
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(),
|
||||||
() -> {
|
() -> {
|
||||||
EntryActivity.launch(GroupActivity.this, entry, getReadOnly());
|
EntryActivity.Companion.launch(GroupActivity.this, entry, getReadOnly());
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
() -> {
|
() -> {
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.kunzisoft.keepass.notifications
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import com.kunzisoft.keepass.app.App
|
||||||
|
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||||
|
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||||
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
object NotificationEntryCopyManager {
|
||||||
|
|
||||||
|
fun launchNotificationIfAllowed(context: Context, firstLaunch: Boolean, entry: EntryVersioned) {
|
||||||
|
// Start to manage field reference to copy a value from ref
|
||||||
|
val database = App.currentDatabase
|
||||||
|
database.startManageEntry(entry)
|
||||||
|
|
||||||
|
val containsUsernameToCopy = entry.username.isNotEmpty()
|
||||||
|
val containsPasswordToCopy = entry.password.isNotEmpty()
|
||||||
|
&& PreferencesUtil.allowCopyPasswordAndProtectedFields(context)
|
||||||
|
val containsExtraFieldToCopy = entry.allowExtraFields()
|
||||||
|
&& (entry.containsCustomFields()
|
||||||
|
&& entry.containsCustomFieldsNotProtected()
|
||||||
|
|| (entry.containsCustomFields()
|
||||||
|
&& entry.containsCustomFieldsProtected()
|
||||||
|
&& PreferencesUtil.allowCopyPasswordAndProtectedFields(context))
|
||||||
|
)
|
||||||
|
|
||||||
|
// If notifications enabled in settings
|
||||||
|
// Don't if application timeout
|
||||||
|
if (firstLaunch
|
||||||
|
&& PreferencesUtil.isClipboardNotificationsEnable(context.applicationContext)) {
|
||||||
|
if (containsUsernameToCopy || containsPasswordToCopy || containsExtraFieldToCopy) {
|
||||||
|
|
||||||
|
// username already copied, waiting for user's action before copy password.
|
||||||
|
val intent = Intent(context, NotificationCopyingService::class.java)
|
||||||
|
intent.action = NotificationCopyingService.ACTION_NEW_NOTIFICATION
|
||||||
|
intent.putExtra(NotificationCopyingService.EXTRA_ENTRY_TITLE, entry.title)
|
||||||
|
// Construct notification fields
|
||||||
|
val notificationFields = ArrayList<NotificationField>()
|
||||||
|
// Add username if exists to notifications
|
||||||
|
if (containsUsernameToCopy)
|
||||||
|
notificationFields.add(
|
||||||
|
NotificationField(
|
||||||
|
NotificationField.NotificationFieldId.USERNAME,
|
||||||
|
entry.username,
|
||||||
|
context.resources))
|
||||||
|
// Add password to notifications
|
||||||
|
if (containsPasswordToCopy) {
|
||||||
|
notificationFields.add(
|
||||||
|
NotificationField(
|
||||||
|
NotificationField.NotificationFieldId.PASSWORD,
|
||||||
|
entry.password,
|
||||||
|
context.resources))
|
||||||
|
}
|
||||||
|
// Add extra fields
|
||||||
|
if (containsExtraFieldToCopy) {
|
||||||
|
try {
|
||||||
|
entry.fields.doActionToAllCustomProtectedField(object : (String, ProtectedString) -> Unit {
|
||||||
|
private var anonymousFieldNumber = 0
|
||||||
|
override fun invoke(key: String, value: ProtectedString) {
|
||||||
|
//If value is not protected or allowed
|
||||||
|
if (!value.isProtected
|
||||||
|
|| PreferencesUtil.allowCopyPasswordAndProtectedFields(context)) {
|
||||||
|
notificationFields.add(
|
||||||
|
NotificationField(
|
||||||
|
NotificationField.NotificationFieldId.getAnonymousFieldId()[anonymousFieldNumber],
|
||||||
|
value.toString(),
|
||||||
|
key,
|
||||||
|
context.resources))
|
||||||
|
anonymousFieldNumber++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||||
|
Log.w("NotificationEntryCopyMg", "Only " + NotificationField.NotificationFieldId.getAnonymousFieldId().size +
|
||||||
|
" anonymous notifications are available")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// Add notifications
|
||||||
|
intent.putParcelableArrayListExtra(NotificationCopyingService.EXTRA_FIELDS, notificationFields)
|
||||||
|
context.startService(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
database.stopManageEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 3 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.kunzisoft.keepass.view;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.text.method.PasswordTransformationMethod;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.kunzisoft.keepass.R;
|
|
||||||
import com.kunzisoft.keepass.database.element.security.ProtectedString;
|
|
||||||
import com.kunzisoft.keepass.utils.Util;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
public class EntryContentsView extends LinearLayout {
|
|
||||||
|
|
||||||
private boolean fontInVisibility;
|
|
||||||
private int colorAccent;
|
|
||||||
|
|
||||||
private View userNameContainerView;
|
|
||||||
private TextView userNameView;
|
|
||||||
private ImageView userNameActionView;
|
|
||||||
|
|
||||||
private View passwordContainerView;
|
|
||||||
private TextView passwordView;
|
|
||||||
private ImageView passwordActionView;
|
|
||||||
|
|
||||||
private View urlContainerView;
|
|
||||||
private TextView urlView;
|
|
||||||
|
|
||||||
private View commentContainerView;
|
|
||||||
private TextView commentView;
|
|
||||||
|
|
||||||
private ViewGroup extrasView;
|
|
||||||
|
|
||||||
private DateFormat dateFormat;
|
|
||||||
private DateFormat timeFormat;
|
|
||||||
|
|
||||||
private TextView creationDateView;
|
|
||||||
private TextView modificationDateView;
|
|
||||||
private TextView lastAccessDateView;
|
|
||||||
private TextView expiresDateView;
|
|
||||||
|
|
||||||
public EntryContentsView(Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntryContentsView(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
fontInVisibility = false;
|
|
||||||
|
|
||||||
dateFormat = android.text.format.DateFormat.getDateFormat(context);
|
|
||||||
timeFormat = android.text.format.DateFormat.getTimeFormat(context);
|
|
||||||
|
|
||||||
inflate(context);
|
|
||||||
|
|
||||||
int[] attrColorAccent = {R.attr.colorAccentCompat};
|
|
||||||
TypedArray taColorAccent = context.getTheme().obtainStyledAttributes(attrColorAccent);
|
|
||||||
this.colorAccent = taColorAccent.getColor(0, Color.BLACK);
|
|
||||||
taColorAccent.recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void inflate(Context context) {
|
|
||||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
assert inflater != null;
|
|
||||||
inflater.inflate(R.layout.entry_view_contents, this);
|
|
||||||
|
|
||||||
userNameContainerView = findViewById(R.id.entry_user_name_container);
|
|
||||||
userNameView = findViewById(R.id.entry_user_name);
|
|
||||||
userNameActionView = findViewById(R.id.entry_user_name_action_image);
|
|
||||||
|
|
||||||
passwordContainerView = findViewById(R.id.entry_password_container);
|
|
||||||
passwordView = findViewById(R.id.entry_password);
|
|
||||||
passwordActionView = findViewById(R.id.entry_password_action_image);
|
|
||||||
|
|
||||||
urlContainerView = findViewById(R.id.entry_url_container);
|
|
||||||
urlView = findViewById(R.id.entry_url);
|
|
||||||
|
|
||||||
commentContainerView = findViewById(R.id.entry_notes_container);
|
|
||||||
commentView = findViewById(R.id.entry_notes);
|
|
||||||
|
|
||||||
extrasView = findViewById(R.id.extra_strings);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
this.fontInVisibility = fontInVisibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignUserName(String userName) {
|
|
||||||
if (userName != null && !userName.isEmpty()) {
|
|
||||||
userNameContainerView.setVisibility(VISIBLE);
|
|
||||||
userNameView.setText(userName);
|
|
||||||
if (fontInVisibility)
|
|
||||||
Util.applyFontVisibilityTo(getContext(), userNameView);
|
|
||||||
} else {
|
|
||||||
userNameContainerView.setVisibility(GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignUserNameCopyListener(OnClickListener onClickListener) {
|
|
||||||
userNameActionView.setOnClickListener(onClickListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUserNamePresent() {
|
|
||||||
return userNameContainerView.getVisibility() == VISIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignPassword(String password, boolean allowCopyPassword) {
|
|
||||||
if (password != null && !password.isEmpty()) {
|
|
||||||
passwordContainerView.setVisibility(VISIBLE);
|
|
||||||
passwordView.setText(password);
|
|
||||||
if (fontInVisibility)
|
|
||||||
Util.applyFontVisibilityTo(getContext(), passwordView);
|
|
||||||
if (!allowCopyPassword) {
|
|
||||||
passwordActionView.setColorFilter(ContextCompat.getColor(getContext(), R.color.grey_dark));
|
|
||||||
} else {
|
|
||||||
passwordActionView.setColorFilter(colorAccent);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
passwordContainerView.setVisibility(GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignPasswordCopyListener(OnClickListener onClickListener) {
|
|
||||||
if (onClickListener == null)
|
|
||||||
setClickable(false);
|
|
||||||
passwordActionView.setOnClickListener(onClickListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPasswordPresent() {
|
|
||||||
return passwordContainerView.getVisibility() == VISIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean atLeastOneFieldProtectedPresent() {
|
|
||||||
for (int i = 0; i < extrasView.getChildCount(); i++) {
|
|
||||||
View childCustomView = extrasView.getChildAt(i);
|
|
||||||
if (childCustomView instanceof EntryCustomFieldProtected)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHiddenPasswordStyle(boolean hiddenStyle) {
|
|
||||||
if ( !hiddenStyle ) {
|
|
||||||
passwordView.setTransformationMethod(null);
|
|
||||||
} else {
|
|
||||||
passwordView.setTransformationMethod(PasswordTransformationMethod.getInstance());
|
|
||||||
}
|
|
||||||
// Hidden style for custom fields
|
|
||||||
for (int i = 0; i < extrasView.getChildCount(); i++) {
|
|
||||||
View childCustomView = extrasView.getChildAt(i);
|
|
||||||
if (childCustomView instanceof EntryCustomFieldProtected)
|
|
||||||
((EntryCustomFieldProtected) childCustomView).setHiddenPasswordStyle(hiddenStyle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignURL(String url) {
|
|
||||||
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);
|
|
||||||
commentView.setText(comment);
|
|
||||||
if (fontInVisibility)
|
|
||||||
Util.applyFontVisibilityTo(getContext(), commentView);
|
|
||||||
} else {
|
|
||||||
commentContainerView.setVisibility(GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addExtraField(String title, ProtectedString value, boolean showAction, OnClickListener onActionClickListener) {
|
|
||||||
EntryCustomField entryCustomField;
|
|
||||||
if (value.isProtected())
|
|
||||||
entryCustomField = new EntryCustomFieldProtected(getContext(), null, title, value, showAction, onActionClickListener);
|
|
||||||
else
|
|
||||||
entryCustomField = new EntryCustomField(getContext(), null, title, value, showAction, onActionClickListener);
|
|
||||||
entryCustomField.applyFontVisibility(fontInVisibility);
|
|
||||||
extrasView.addView(entryCustomField);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearExtraFields() {
|
|
||||||
extrasView.removeAllViews();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDateTime(Date date) {
|
|
||||||
return dateFormat.format(date) + " " + timeFormat.format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignCreationDate(Date date) {
|
|
||||||
creationDateView.setText(getDateTime(date));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignModificationDate(Date date) {
|
|
||||||
modificationDateView.setText(getDateTime(date));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignLastAccessDate(Date date) {
|
|
||||||
lastAccessDateView.setText(getDateTime(date));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignExpiresDate(Date date) {
|
|
||||||
expiresDateView.setText(getDateTime(date));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assignExpiresDate(String constString) {
|
|
||||||
expiresDateView.setText(constString);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected LayoutParams generateDefaultLayoutParams() {
|
|
||||||
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 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 3 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.kunzisoft.keepass.view
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
|
import android.text.method.PasswordTransformationMethod
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||||
|
import com.kunzisoft.keepass.utils.Util
|
||||||
|
import java.text.DateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class EntryContentsView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) {
|
||||||
|
|
||||||
|
private var fontInVisibility: Boolean = false
|
||||||
|
private val colorAccent: Int
|
||||||
|
|
||||||
|
private var userNameContainerView: View? = null
|
||||||
|
private var userNameView: TextView? = null
|
||||||
|
private var userNameActionView: ImageView? = null
|
||||||
|
|
||||||
|
private var passwordContainerView: View? = null
|
||||||
|
private var passwordView: TextView? = null
|
||||||
|
private var passwordActionView: ImageView? = null
|
||||||
|
|
||||||
|
private var urlContainerView: View? = null
|
||||||
|
private var urlView: TextView? = null
|
||||||
|
|
||||||
|
private var commentContainerView: View? = null
|
||||||
|
private var commentView: TextView? = null
|
||||||
|
|
||||||
|
private var extrasView: ViewGroup? = null
|
||||||
|
|
||||||
|
private val dateFormat: DateFormat
|
||||||
|
private val timeFormat: DateFormat
|
||||||
|
|
||||||
|
private var creationDateView: TextView? = null
|
||||||
|
private var modificationDateView: TextView? = null
|
||||||
|
private var lastAccessDateView: TextView? = null
|
||||||
|
private var expiresDateView: TextView? = null
|
||||||
|
|
||||||
|
val isUserNamePresent: Boolean
|
||||||
|
get() = userNameContainerView!!.visibility == View.VISIBLE
|
||||||
|
|
||||||
|
val isPasswordPresent: Boolean
|
||||||
|
get() = passwordContainerView!!.visibility == View.VISIBLE
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
fontInVisibility = false
|
||||||
|
|
||||||
|
dateFormat = android.text.format.DateFormat.getDateFormat(context)
|
||||||
|
timeFormat = android.text.format.DateFormat.getTimeFormat(context)
|
||||||
|
|
||||||
|
inflate(context)
|
||||||
|
|
||||||
|
val attrColorAccent = intArrayOf(R.attr.colorAccentCompat)
|
||||||
|
val taColorAccent = context.theme.obtainStyledAttributes(attrColorAccent)
|
||||||
|
this.colorAccent = taColorAccent.getColor(0, Color.BLACK)
|
||||||
|
taColorAccent.recycle()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun inflate(context: Context) {
|
||||||
|
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
inflater.inflate(R.layout.entry_view_contents, this)
|
||||||
|
|
||||||
|
userNameContainerView = findViewById(R.id.entry_user_name_container)
|
||||||
|
userNameView = findViewById(R.id.entry_user_name)
|
||||||
|
userNameActionView = findViewById(R.id.entry_user_name_action_image)
|
||||||
|
|
||||||
|
passwordContainerView = findViewById(R.id.entry_password_container)
|
||||||
|
passwordView = findViewById(R.id.entry_password)
|
||||||
|
passwordActionView = findViewById(R.id.entry_password_action_image)
|
||||||
|
|
||||||
|
urlContainerView = findViewById(R.id.entry_url_container)
|
||||||
|
urlView = findViewById(R.id.entry_url)
|
||||||
|
|
||||||
|
commentContainerView = findViewById(R.id.entry_notes_container)
|
||||||
|
commentView = findViewById(R.id.entry_notes)
|
||||||
|
|
||||||
|
extrasView = findViewById(R.id.extra_strings)
|
||||||
|
|
||||||
|
creationDateView = findViewById(R.id.entry_created)
|
||||||
|
modificationDateView = findViewById(R.id.entry_modified)
|
||||||
|
lastAccessDateView = findViewById(R.id.entry_accessed)
|
||||||
|
expiresDateView = findViewById(R.id.entry_expires)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun applyFontVisibilityToFields(fontInVisibility: Boolean) {
|
||||||
|
this.fontInVisibility = fontInVisibility
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignUserName(userName: String?) {
|
||||||
|
if (userName != null && userName.isNotEmpty()) {
|
||||||
|
userNameContainerView?.visibility = View.VISIBLE
|
||||||
|
userNameView?.apply {
|
||||||
|
text = userName
|
||||||
|
if (fontInVisibility)
|
||||||
|
Util.applyFontVisibilityTo(context, this)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
userNameContainerView?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignUserNameCopyListener(onClickListener: OnClickListener) {
|
||||||
|
userNameActionView?.setOnClickListener(onClickListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignPassword(password: String?, allowCopyPassword: Boolean) {
|
||||||
|
if (password != null && password.isNotEmpty()) {
|
||||||
|
passwordContainerView?.visibility = View.VISIBLE
|
||||||
|
passwordView?.apply {
|
||||||
|
text = password
|
||||||
|
if (fontInVisibility)
|
||||||
|
Util.applyFontVisibilityTo(context, this)
|
||||||
|
}
|
||||||
|
if (!allowCopyPassword) {
|
||||||
|
passwordActionView?.setColorFilter(ContextCompat.getColor(context, R.color.grey_dark))
|
||||||
|
} else {
|
||||||
|
passwordActionView?.setColorFilter(colorAccent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
passwordContainerView?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignPasswordCopyListener(onClickListener: OnClickListener?) {
|
||||||
|
if (onClickListener == null)
|
||||||
|
isClickable = false
|
||||||
|
passwordActionView?.setOnClickListener(onClickListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun atLeastOneFieldProtectedPresent(): Boolean {
|
||||||
|
extrasView?.let {
|
||||||
|
for (i in 0 until it.childCount) {
|
||||||
|
val childCustomView = it.getChildAt(i)
|
||||||
|
if (childCustomView is EntryCustomFieldProtected)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setHiddenPasswordStyle(hiddenStyle: Boolean) {
|
||||||
|
if (!hiddenStyle) {
|
||||||
|
passwordView?.transformationMethod = null
|
||||||
|
} else {
|
||||||
|
passwordView?.transformationMethod = PasswordTransformationMethod.getInstance()
|
||||||
|
}
|
||||||
|
// Hidden style for custom fields
|
||||||
|
extrasView?.let {
|
||||||
|
for (i in 0 until it.childCount) {
|
||||||
|
val childCustomView = it.getChildAt(i)
|
||||||
|
if (childCustomView is EntryCustomFieldProtected)
|
||||||
|
childCustomView.setHiddenPasswordStyle(hiddenStyle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignURL(url: String?) {
|
||||||
|
if (url != null && url.isNotEmpty()) {
|
||||||
|
urlContainerView?.visibility = View.VISIBLE
|
||||||
|
urlView?.text = url
|
||||||
|
} else {
|
||||||
|
urlContainerView?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignComment(comment: String?) {
|
||||||
|
if (comment != null && comment.isNotEmpty()) {
|
||||||
|
commentContainerView?.visibility = View.VISIBLE
|
||||||
|
commentView?.apply {
|
||||||
|
text = comment
|
||||||
|
if (fontInVisibility)
|
||||||
|
Util.applyFontVisibilityTo(context, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
commentContainerView?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addExtraField(title: String, value: ProtectedString, showAction: Boolean, onActionClickListener: OnClickListener) {
|
||||||
|
val entryCustomField: EntryCustomField
|
||||||
|
if (value.isProtected)
|
||||||
|
entryCustomField = EntryCustomFieldProtected(context, null, title, value, showAction, onActionClickListener)
|
||||||
|
else
|
||||||
|
entryCustomField = EntryCustomField(context, null, title, value, showAction, onActionClickListener)
|
||||||
|
entryCustomField.applyFontVisibility(fontInVisibility)
|
||||||
|
extrasView?.addView(entryCustomField)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearExtraFields() {
|
||||||
|
extrasView?.removeAllViews()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDateTime(date: Date): String {
|
||||||
|
return dateFormat.format(date) + " " + timeFormat.format(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignCreationDate(date: Date) {
|
||||||
|
creationDateView?.text = getDateTime(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignModificationDate(date: Date) {
|
||||||
|
modificationDateView?.text = getDateTime(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignLastAccessDate(date: Date) {
|
||||||
|
lastAccessDateView?.text = getDateTime(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignExpiresDate(date: Date) {
|
||||||
|
expiresDateView?.text = getDateTime(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignExpiresDate(constString: String) {
|
||||||
|
expiresDateView?.text = constString
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateDefaultLayoutParams(): LayoutParams {
|
||||||
|
return LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user