- Now the contacts can be changed

This commit is contained in:
Javier Varona 2018-02-12 22:11:11 -04:00
parent 58afdb144b
commit 4c9e6ebfc3
12 changed files with 276 additions and 17 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 2, "version": 2,
"identityHash": "1b825c6a18815f35456f569f59868945", "identityHash": "6f4a0d464f042d577c584ed532bffd2c",
"entities": [ "entities": [
{ {
"tableName": "account_seed", "tableName": "account_seed",
@ -284,8 +284,14 @@
}, },
{ {
"tableName": "contact_address", "tableName": "contact_address",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`contact_id` INTEGER NOT NULL, `crypto_net` TEXT NOT NULL, `address` TEXT, PRIMARY KEY(`contact_id`, `crypto_net`))", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `contact_id` INTEGER NOT NULL, `crypto_net` TEXT NOT NULL, `address` TEXT)",
"fields": [ "fields": [
{
"fieldPath": "mId",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{ {
"fieldPath": "mContactId", "fieldPath": "mContactId",
"columnName": "contact_id", "columnName": "contact_id",
@ -307,12 +313,19 @@
], ],
"primaryKey": { "primaryKey": {
"columnNames": [ "columnNames": [
"contact_id", "id"
"crypto_net"
], ],
"autoGenerate": false "autoGenerate": true
}, },
"indices": [ "indices": [
{
"name": "index_contact_address_id",
"unique": true,
"columnNames": [
"id"
],
"createSql": "CREATE UNIQUE INDEX `index_contact_address_id` ON `${TABLE_NAME}` (`id`)"
},
{ {
"name": "index_contact_address_contact_id_crypto_net", "name": "index_contact_address_contact_id_crypto_net",
"unique": true, "unique": true,
@ -665,7 +678,7 @@
], ],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"1b825c6a18815f35456f569f59868945\")" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"6f4a0d464f042d577c584ed532bffd2c\")"
] ]
} }
} }

View file

@ -1,13 +1,18 @@
package cy.agorise.crystalwallet.activities; package cy.agorise.crystalwallet.activities;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders; import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.Editable; import android.text.Editable;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
@ -31,9 +36,11 @@ import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
import cy.agorise.crystalwallet.viewmodels.ContactViewModel; import cy.agorise.crystalwallet.viewmodels.ContactViewModel;
import cy.agorise.crystalwallet.viewmodels.validators.CreateContactValidator; import cy.agorise.crystalwallet.viewmodels.validators.CreateContactValidator;
import cy.agorise.crystalwallet.viewmodels.validators.CreateSeedValidator; import cy.agorise.crystalwallet.viewmodels.validators.CreateSeedValidator;
import cy.agorise.crystalwallet.viewmodels.validators.ModifyContactValidator;
import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener; import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener;
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ValidationField; import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ValidationField;
import cy.agorise.crystalwallet.views.ContactAddressListAdapter; import cy.agorise.crystalwallet.views.ContactAddressListAdapter;
import cy.agorise.crystalwallet.views.ContactViewHolder;
public class CreateContactActivity extends AppCompatActivity implements UIValidatorListener { public class CreateContactActivity extends AppCompatActivity implements UIValidatorListener {
@ -45,6 +52,8 @@ public class CreateContactActivity extends AppCompatActivity implements UIValida
Button btnCancel; Button btnCancel;
@BindView(R.id.btnCreate) @BindView(R.id.btnCreate)
Button btnCreate; Button btnCreate;
@BindView(R.id.btnModify)
Button btnModify;
@BindView(R.id.rvContactAddresses) @BindView(R.id.rvContactAddresses)
RecyclerView rvContactAddresses; RecyclerView rvContactAddresses;
@BindView(R.id.btnAddAddress) @BindView(R.id.btnAddAddress)
@ -53,6 +62,9 @@ public class CreateContactActivity extends AppCompatActivity implements UIValida
ContactAddressListAdapter listAdapter; ContactAddressListAdapter listAdapter;
CreateContactValidator createContactValidator; CreateContactValidator createContactValidator;
ModifyContactValidator modifyContactValidator;
Contact contact;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -62,21 +74,81 @@ public class CreateContactActivity extends AppCompatActivity implements UIValida
btnCreate.setEnabled(false); btnCreate.setEnabled(false);
//Initializes the recyclerview
contactAddressList = new ArrayList<ContactAddress>();
listAdapter = new ContactAddressListAdapter(); listAdapter = new ContactAddressListAdapter();
listAdapter.setList(contactAddressList);
rvContactAddresses.setLayoutManager(new LinearLayoutManager(getApplicationContext())); rvContactAddresses.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
rvContactAddresses.setAdapter(listAdapter); rvContactAddresses.setAdapter(listAdapter);
createContactValidator = new CreateContactValidator(this.getApplicationContext(),etName); long contactId = this.getIntent().getLongExtra("CONTACT_ID",-1);
createContactValidator.setListener(this);
btnCreate.setVisibility(View.GONE);
btnModify.setVisibility(View.GONE);
if (contactId >= 0){
final ContactViewModel contactViewModel = ViewModelProviders.of(this).get(ContactViewModel.class);
contactViewModel.init(contactId);
LiveData<Contact> contactLiveData = contactViewModel.getContact();
final CreateContactActivity thisActivity = this;
contactLiveData.observe(this, new Observer<Contact>() {
@Override
public void onChanged(@Nullable Contact contactChanged) {
if (contactChanged != null){
contact = contactChanged;
etName.setText(contact.getName());
LiveData<List<ContactAddress>> contactAddresses = contactViewModel.getContactAddresses();
contactAddresses.observe(thisActivity, new Observer<List<ContactAddress>>() {
@Override
public void onChanged(@Nullable List<ContactAddress> contactAddresses) {
contactAddressList = contactAddresses;
listAdapter.setList(contactAddressList);
listAdapter.notifyDataSetChanged();
}
});
modifyContactValidator = new ModifyContactValidator(thisActivity.getApplicationContext(),contact,etName);
modifyContactValidator.setListener(thisActivity);
btnModify.setVisibility(View.VISIBLE);
} else {
//No contact was found, this will exit the activity
finish();
}
}
});
} else {
contactAddressList = new ArrayList<ContactAddress>();
listAdapter.setList(contactAddressList);
createContactValidator = new CreateContactValidator(this.getApplicationContext(),etName);
createContactValidator.setListener(this);
btnCreate.setVisibility(View.VISIBLE);
}
}
public void validate(){
if (this.createContactValidator != null){
this.createContactValidator.validate();
} else if (this.modifyContactValidator != null){
this.modifyContactValidator.validate();
}
}
public boolean isValid(){
if (this.createContactValidator != null){
return this.createContactValidator.isValid();
} else if (this.modifyContactValidator != null){
return this.modifyContactValidator.isValid();
}
return false;
} }
@OnTextChanged(value = R.id.etName, @OnTextChanged(value = R.id.etName,
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterContactNameChanged(Editable editable) { void afterContactNameChanged(Editable editable) {
this.createContactValidator.validate(); this.validate();
} }
@OnClick(R.id.btnAddAddress) @OnClick(R.id.btnAddAddress)
@ -91,6 +163,25 @@ public class CreateContactActivity extends AppCompatActivity implements UIValida
this.finish(); this.finish();
} }
@OnClick(R.id.btnModify)
public void modifyContact(){
if (this.modifyContactValidator.isValid()) {
this.contact.setName(etName.getText().toString());
this.contact.clearAddresses();
for (ContactAddress contactAddress : contactAddressList){
this.contact.addAddress(contactAddress);
}
ContactViewModel contactViewModel = ViewModelProviders.of(this).get(ContactViewModel.class);
if (contactViewModel.modifyContact(this.contact)){
this.finish();
} else {
this.modifyContactValidator.validate();
}
}
}
@OnClick(R.id.btnCreate) @OnClick(R.id.btnCreate)
public void createContact(){ public void createContact(){
if (this.createContactValidator.isValid()) { if (this.createContactValidator.isValid()) {
@ -121,7 +212,7 @@ public class CreateContactActivity extends AppCompatActivity implements UIValida
tvNameError.setText(""); tvNameError.setText("");
} }
if (activity.createContactValidator.isValid()){ if (activity.isValid()){
btnCreate.setEnabled(true); btnCreate.setEnabled(true);
} else { } else {
btnCreate.setEnabled(false); btnCreate.setEnabled(false);

View file

@ -6,6 +6,7 @@ import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert; import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy; import android.arch.persistence.room.OnConflictStrategy;
import android.arch.persistence.room.Query; import android.arch.persistence.room.Query;
import android.arch.persistence.room.Update;
import java.util.List; import java.util.List;
@ -31,9 +32,21 @@ public interface ContactDao {
@Query("SELECT count(*) FROM contact WHERE name = :name") @Query("SELECT count(*) FROM contact WHERE name = :name")
boolean existsByName(String name); boolean existsByName(String name);
@Query("SELECT * FROM contact_address WHERE contact_id = :contactId")
LiveData<List<ContactAddress>> getContactAddresses(long contactId);
@Update(onConflict = OnConflictStrategy.ABORT)
public void update(Contact... contacts);
@Insert(onConflict = OnConflictStrategy.ABORT) @Insert(onConflict = OnConflictStrategy.ABORT)
public long[] add(Contact... contacts); public long[] add(Contact... contacts);
@Insert(onConflict = OnConflictStrategy.ABORT) @Insert(onConflict = OnConflictStrategy.ABORT)
public void addAddresses(ContactAddress... contactAddresses); public void addAddresses(ContactAddress... contactAddresses);
@Update(onConflict = OnConflictStrategy.REPLACE)
public void updateAddresses(ContactAddress... contactAddresses);
@Update(onConflict = OnConflictStrategy.REPLACE)
public void updateAddressesFields(ContactAddress... contactAddresses);
} }

View file

@ -71,6 +71,12 @@ public class Contact {
return this.mAddresses.get(index); return this.mAddresses.get(index);
} }
public void clearAddresses(){
if (this.mAddresses != null) {
this.mAddresses.clear();
}
}
public void addAddress(ContactAddress address){ public void addAddress(ContactAddress address){
if (this.mAddresses == null) { if (this.mAddresses == null) {
this.mAddresses = new ArrayList<ContactAddress>(); this.mAddresses = new ArrayList<ContactAddress>();

View file

@ -4,6 +4,7 @@ package cy.agorise.crystalwallet.models;
import android.arch.persistence.room.ColumnInfo; import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity; import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Index; import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.recyclerview.extensions.DiffCallback; import android.support.v7.recyclerview.extensions.DiffCallback;
@ -16,10 +17,16 @@ import cy.agorise.crystalwallet.enums.CryptoNet;
*/ */
@Entity(tableName="contact_address", @Entity(tableName="contact_address",
primaryKeys = {"contact_id","crypto_net"}, indices = {@Index(value = {"id"}, unique=true),@Index(value = {"contact_id","crypto_net"}, unique=true)})
indices = {@Index(value = {"contact_id","crypto_net"}, unique=true)})
public class ContactAddress { public class ContactAddress {
/**
* The id on the database
*/
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
private long mId;
@ColumnInfo(name = "contact_id") @ColumnInfo(name = "contact_id")
private long mContactId; private long mContactId;
@ -33,6 +40,14 @@ public class ContactAddress {
@ColumnInfo(name="address") @ColumnInfo(name="address")
private String mAddress; private String mAddress;
public long getId() {
return mId;
}
public void setId(long id) {
this.mId = id;
}
public long getContactId() { public long getContactId() {
return mContactId; return mContactId;
} }

View file

@ -5,6 +5,8 @@ import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData; import android.arch.lifecycle.LiveData;
import android.arch.paging.PagedList; import android.arch.paging.PagedList;
import java.util.List;
import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.Contact; import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.models.ContactAddress; import cy.agorise.crystalwallet.models.ContactAddress;
@ -16,12 +18,43 @@ import cy.agorise.crystalwallet.models.ContactAddress;
public class ContactViewModel extends AndroidViewModel { public class ContactViewModel extends AndroidViewModel {
private CrystalDatabase db; private CrystalDatabase db;
private LiveData<Contact> contact;
private LiveData<List<ContactAddress>> contactAddresses;
public ContactViewModel(Application application) { public ContactViewModel(Application application) {
super(application); super(application);
this.db = CrystalDatabase.getAppDatabase(application.getApplicationContext()); this.db = CrystalDatabase.getAppDatabase(application.getApplicationContext());
} }
public void init(long contactId){
this.contact = this.db.contactDao().getById(contactId);
this.contactAddresses = this.db.contactDao().getContactAddresses(contactId);
}
public LiveData<Contact> getContact(){
return this.contact;
}
public LiveData<List<ContactAddress>> getContactAddresses(){
return this.contactAddresses;
}
public boolean modifyContact(Contact contact){
this.db.contactDao().update(contact);
for (int i=0;i<contact.addressesCount();i++){
ContactAddress nextAddress = contact.getAddress(i);
if (nextAddress.getId() > 0){
this.db.contactDao().updateAddresses(nextAddress);
} else {
nextAddress.setContactId(contact.getId());
this.db.contactDao().addAddresses(nextAddress);
}
}
return true;
}
public boolean addContact(Contact contact){ public boolean addContact(Contact contact){
long newContactId = this.db.contactDao().add(contact)[0]; long newContactId = this.db.contactDao().add(contact)[0];
boolean contactWasAdded = newContactId >= 0; boolean contactWasAdded = newContactId >= 0;

View file

@ -0,0 +1,19 @@
package cy.agorise.crystalwallet.viewmodels.validators;
import android.content.Context;
import android.widget.EditText;
import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ContactNameValidationField;
/**
* Created by Henry Varona on 2/11/2018.
*/
public class ModifyContactValidator extends UIValidator {
public ModifyContactValidator(Context context, Contact contact, EditText nameEdit){
super(context);
this.addField(new ContactNameValidationField(nameEdit, contact));
}
}

View file

@ -15,6 +15,7 @@ import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestListener; import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestListener;
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests; import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateExistBitsharesAccountRequest; import cy.agorise.crystalwallet.cryptonetinforequests.ValidateExistBitsharesAccountRequest;
import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.models.GeneralSetting; import cy.agorise.crystalwallet.models.GeneralSetting;
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel; import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel; import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
@ -26,15 +27,31 @@ import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
public class ContactNameValidationField extends ValidationField { public class ContactNameValidationField extends ValidationField {
private EditText nameField; private EditText nameField;
private Contact contact;
public ContactNameValidationField(EditText nameField){ public ContactNameValidationField(EditText nameField){
super(nameField); super(nameField);
this.nameField = nameField; this.nameField = nameField;
this.contact = null;
}
public ContactNameValidationField(EditText nameField, Contact contact){
super(nameField);
this.nameField = nameField;
this.contact = contact;
} }
public void validate(){ public void validate(){
final String newValue = this.nameField.getText().toString(); final String newValue = this.nameField.getText().toString();
if (this.contact != null){
if (this.contact.getName().equals(newValue)){
this.setLastValue(newValue);
this.startValidating();
this.setValidForValue(newValue, true);
return;
}
}
if (!newValue.equals("")) { if (!newValue.equals("")) {
if (!newValue.equals(this.getLastValue())) { if (!newValue.equals(this.getLastValue())) {

View file

@ -30,6 +30,8 @@ public class ContactAddressViewHolder extends RecyclerView.ViewHolder {
private Spinner spCryptoNet; private Spinner spCryptoNet;
private EditText etAddress; private EditText etAddress;
private Context context; private Context context;
private CryptoNet[] cryptoNetArray;
private ArrayAdapter<CryptoNet> cryptoNetSpinnerAdapter;
public ContactAddressViewHolder(View itemView) { public ContactAddressViewHolder(View itemView) {
super(itemView); super(itemView);
@ -40,8 +42,8 @@ public class ContactAddressViewHolder extends RecyclerView.ViewHolder {
//load spinners values //load spinners values
CryptoNet[] cryptoNetArray = CryptoNet.values(); cryptoNetArray = CryptoNet.values();
ArrayAdapter<CryptoNet> cryptoNetSpinnerAdapter = new ArrayAdapter<CryptoNet>( cryptoNetSpinnerAdapter = new ArrayAdapter<CryptoNet>(
this.context, this.context,
android.R.layout.simple_list_item_1, android.R.layout.simple_list_item_1,
cryptoNetArray cryptoNetArray
@ -64,6 +66,18 @@ public class ContactAddressViewHolder extends RecyclerView.ViewHolder {
if (contactAddress == null){ if (contactAddress == null){
this.clear(); this.clear();
} else { } else {
etAddress.setText(contactAddress.getAddress());
CryptoNet nextCryptoNet;
for (int i=0;i<cryptoNetArray.length;i++){
nextCryptoNet = cryptoNetArray[i];
if (nextCryptoNet.equals(contactAddress.getCryptoNet())){
spCryptoNet.setSelection(i);
break;
}
}
spCryptoNet.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { spCryptoNet.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {

View file

@ -1,12 +1,15 @@
package cy.agorise.crystalwallet.views; package cy.agorise.crystalwallet.views;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.provider.ContactsContract;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import cy.agorise.crystalwallet.R; import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.activities.CreateContactActivity;
import cy.agorise.crystalwallet.models.Contact; import cy.agorise.crystalwallet.models.Contact;
/** /**
@ -19,6 +22,7 @@ public class ContactViewHolder extends RecyclerView.ViewHolder {
private TextView tvName; private TextView tvName;
private ImageView ivThumbnail; private ImageView ivThumbnail;
private TextView tvLastPaid; private TextView tvLastPaid;
private ImageView ivDeleteContact;
private Context context; private Context context;
public ContactViewHolder(View itemView) { public ContactViewHolder(View itemView) {
@ -27,6 +31,7 @@ public class ContactViewHolder extends RecyclerView.ViewHolder {
tvName = (TextView) itemView.findViewById(R.id.tvContactName); tvName = (TextView) itemView.findViewById(R.id.tvContactName);
ivThumbnail = (ImageView) itemView.findViewById(R.id.ivContactThumbnail); ivThumbnail = (ImageView) itemView.findViewById(R.id.ivContactThumbnail);
tvLastPaid = (TextView) itemView.findViewById(R.id.tvLastPaid); tvLastPaid = (TextView) itemView.findViewById(R.id.tvLastPaid);
ivDeleteContact = (ImageView) itemView.findViewById(R.id.ivDeleteContact);
this.context = itemView.getContext(); this.context = itemView.getContext();
} }
@ -49,6 +54,22 @@ public class ContactViewHolder extends RecyclerView.ViewHolder {
} else { } else {
tvName.setText(contact.getName()); tvName.setText(contact.getName());
tvLastPaid.setText("Paid: 1 Jan, 2001 01:01"); tvLastPaid.setText("Paid: 1 Jan, 2001 01:01");
this.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(itemView.getContext(), CreateContactActivity.class);
intent.putExtra("CONTACT_ID", contact.getId());
itemView.getContext().startActivity(intent);
}
});
this.ivDeleteContact.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//
}
});
} }
} }
} }

View file

@ -81,6 +81,16 @@
android:padding="10dp" android:padding="10dp"
android:text="Create Contact" android:text="Create Contact"
android:textColor="@color/white" /> android:textColor="@color/white" />
<Button
android:id="@+id/btnModify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:background="@color/green"
android:padding="10dp"
android:text="Modify Contact"
android:textColor="@color/white" />
</LinearLayout> </LinearLayout>

View file

@ -35,5 +35,12 @@
android:layout_toRightOf="@+id/ivContactThumbnail" android:layout_toRightOf="@+id/ivContactThumbnail"
android:text="Paid: Jan 1, 2001, 01:01" android:text="Paid: Jan 1, 2001, 01:01"
android:textColor="@android:color/darker_gray" /> android:textColor="@android:color/darker_gray" />
<ImageView
android:id="@+id/ivDeleteContact"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:src="@drawable/deleteicon" />
</RelativeLayout> </RelativeLayout>
</LinearLayout> </LinearLayout>