- Contacts can be created

- Contacts can have multiple addresses for every crypto net (still in progress...)
This commit is contained in:
Javier Varona 2018-02-07 21:47:58 -04:00
parent 5eae79d011
commit 58afdb144b
11 changed files with 298 additions and 13 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 2, "version": 2,
"identityHash": "a44ccb96c8213951403ed2a283fb3367", "identityHash": "1b825c6a18815f35456f569f59868945",
"entities": [ "entities": [
{ {
"tableName": "account_seed", "tableName": "account_seed",
@ -282,6 +282,49 @@
], ],
"foreignKeys": [] "foreignKeys": []
}, },
{
"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`))",
"fields": [
{
"fieldPath": "mContactId",
"columnName": "contact_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mCryptoNet",
"columnName": "crypto_net",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mAddress",
"columnName": "address",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"contact_id",
"crypto_net"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_contact_address_contact_id_crypto_net",
"unique": true,
"columnNames": [
"contact_id",
"crypto_net"
],
"createSql": "CREATE UNIQUE INDEX `index_contact_address_contact_id_crypto_net` ON `${TABLE_NAME}` (`contact_id`, `crypto_net`)"
}
],
"foreignKeys": []
},
{ {
"tableName": "crypto_currency", "tableName": "crypto_currency",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `crypto_net` TEXT, `precision` INTEGER NOT NULL)", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `crypto_net` TEXT, `precision` INTEGER NOT NULL)",
@ -622,7 +665,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, \"a44ccb96c8213951403ed2a283fb3367\")" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"1b825c6a18815f35456f569f59868945\")"
] ]
} }
} }

View file

@ -5,12 +5,17 @@ import android.content.Intent;
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.RecyclerView;
import android.text.Editable; import android.text.Editable;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
@ -20,6 +25,7 @@ import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestListen
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests; import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateCreateBitsharesAccountRequest; import cy.agorise.crystalwallet.cryptonetinforequests.ValidateCreateBitsharesAccountRequest;
import cy.agorise.crystalwallet.models.Contact; import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.models.ContactAddress;
import cy.agorise.crystalwallet.models.GrapheneAccount; import cy.agorise.crystalwallet.models.GrapheneAccount;
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel; import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
import cy.agorise.crystalwallet.viewmodels.ContactViewModel; import cy.agorise.crystalwallet.viewmodels.ContactViewModel;
@ -27,6 +33,7 @@ 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.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;
public class CreateContactActivity extends AppCompatActivity implements UIValidatorListener { public class CreateContactActivity extends AppCompatActivity implements UIValidatorListener {
@ -38,6 +45,12 @@ 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.rvContactAddresses)
RecyclerView rvContactAddresses;
@BindView(R.id.btnAddAddress)
Button btnAddAddress;
List<ContactAddress> contactAddressList;
ContactAddressListAdapter listAdapter;
CreateContactValidator createContactValidator; CreateContactValidator createContactValidator;
@ -48,6 +61,14 @@ public class CreateContactActivity extends AppCompatActivity implements UIValida
ButterKnife.bind(this); ButterKnife.bind(this);
btnCreate.setEnabled(false); btnCreate.setEnabled(false);
//Initializes the recyclerview
contactAddressList = new ArrayList<ContactAddress>();
listAdapter = new ContactAddressListAdapter();
listAdapter.setList(contactAddressList);
rvContactAddresses.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
rvContactAddresses.setAdapter(listAdapter);
createContactValidator = new CreateContactValidator(this.getApplicationContext(),etName); createContactValidator = new CreateContactValidator(this.getApplicationContext(),etName);
createContactValidator.setListener(this); createContactValidator.setListener(this);
} }
@ -58,6 +79,12 @@ public class CreateContactActivity extends AppCompatActivity implements UIValida
this.createContactValidator.validate(); this.createContactValidator.validate();
} }
@OnClick(R.id.btnAddAddress)
public void addAddress(){
ContactAddress newContactAddress = new ContactAddress();
this.contactAddressList.add(newContactAddress);
this.listAdapter.notifyDataSetChanged();
}
@OnClick(R.id.btnCancel) @OnClick(R.id.btnCancel)
public void cancel(){ public void cancel(){
@ -69,6 +96,11 @@ public class CreateContactActivity extends AppCompatActivity implements UIValida
if (this.createContactValidator.isValid()) { if (this.createContactValidator.isValid()) {
Contact newContact = new Contact(); Contact newContact = new Contact();
newContact.setName(etName.getText().toString()); newContact.setName(etName.getText().toString());
for (ContactAddress contactAddress : contactAddressList){
newContact.addAddress(contactAddress);
}
ContactViewModel contactViewModel = ViewModelProviders.of(this).get(ContactViewModel.class); ContactViewModel contactViewModel = ViewModelProviders.of(this).get(ContactViewModel.class);
if (contactViewModel.addContact(newContact)){ if (contactViewModel.addContact(newContact)){
this.finish(); this.finish();

View file

@ -10,6 +10,7 @@ import android.arch.persistence.room.Query;
import java.util.List; import java.util.List;
import cy.agorise.crystalwallet.models.Contact; import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.models.ContactAddress;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction; import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
/** /**
@ -32,4 +33,7 @@ public interface ContactDao {
@Insert(onConflict = OnConflictStrategy.ABORT) @Insert(onConflict = OnConflictStrategy.ABORT)
public long[] add(Contact... contacts); public long[] add(Contact... contacts);
@Insert(onConflict = OnConflictStrategy.ABORT)
public void addAddresses(ContactAddress... contactAddresses);
} }

View file

@ -10,6 +10,7 @@ import cy.agorise.crystalwallet.dao.converters.Converters;
import cy.agorise.crystalwallet.models.AccountSeed; import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.models.BitsharesAssetInfo; import cy.agorise.crystalwallet.models.BitsharesAssetInfo;
import cy.agorise.crystalwallet.models.Contact; import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.models.ContactAddress;
import cy.agorise.crystalwallet.models.CryptoCoinBalance; import cy.agorise.crystalwallet.models.CryptoCoinBalance;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction; import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoCurrency;
@ -28,6 +29,7 @@ import cy.agorise.crystalwallet.models.GrapheneAccountInfo;
CryptoNetAccount.class, CryptoNetAccount.class,
CryptoCoinTransaction.class, CryptoCoinTransaction.class,
Contact.class, Contact.class,
ContactAddress.class,
CryptoCurrency.class, CryptoCurrency.class,
CryptoCoinBalance.class, CryptoCoinBalance.class,
GrapheneAccountInfo.class, GrapheneAccountInfo.class,

View file

@ -10,6 +10,7 @@ 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;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -71,7 +72,11 @@ public class Contact {
} }
public void addAddress(ContactAddress address){ public void addAddress(ContactAddress address){
if (this.mAddresses == null) {
this.mAddresses = new ArrayList<ContactAddress>();
}
this.mAddresses.add(address); this.mAddresses.add(address);
address.setContactId(this.getId());
} }
public static final DiffCallback<Contact> DIFF_CALLBACK = new DiffCallback<Contact>() { public static final DiffCallback<Contact> DIFF_CALLBACK = new DiffCallback<Contact>() {

View file

@ -7,6 +7,8 @@ import android.arch.persistence.room.Index;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.recyclerview.extensions.DiffCallback; import android.support.v7.recyclerview.extensions.DiffCallback;
import cy.agorise.crystalwallet.enums.CryptoNet;
/** /**
* Represents a user contact address * Represents a user contact address
* *
@ -14,15 +16,19 @@ import android.support.v7.recyclerview.extensions.DiffCallback;
*/ */
@Entity(tableName="contact_address", @Entity(tableName="contact_address",
primaryKeys = {"contact_id","crypto_currency_id"}, primaryKeys = {"contact_id","crypto_net"},
indices = {@Index(value = {"contact_id","crypto_currency_id"}, unique=true)}) indices = {@Index(value = {"contact_id","crypto_net"}, unique=true)})
public class ContactAddress { public class ContactAddress {
@ColumnInfo(name = "contact_id") @ColumnInfo(name = "contact_id")
private long mContactId; private long mContactId;
@ColumnInfo(name = "crypto_currency_id") /**
private long mCryptoCurrencyId; * The crypto net of the address
*/
@NonNull
@ColumnInfo(name = "crypto_net")
private CryptoNet mCryptoNet;
@ColumnInfo(name="address") @ColumnInfo(name="address")
private String mAddress; private String mAddress;
@ -35,12 +41,12 @@ public class ContactAddress {
this.mContactId = contactId; this.mContactId = contactId;
} }
public long getCryptoCurrencyId() { public CryptoNet getCryptoNet() {
return mCryptoCurrencyId; return mCryptoNet;
} }
public void setCryptoCurrencyId(long cryptoCurrencyId) { public void setCryptoNet(CryptoNet cryptoNet) {
this.mCryptoCurrencyId = cryptoCurrencyId; this.mCryptoNet = cryptoNet;
} }
public String getAddress() { public String getAddress() {
@ -56,7 +62,7 @@ public class ContactAddress {
public boolean areItemsTheSame( public boolean areItemsTheSame(
@NonNull ContactAddress oldContactAddress, @NonNull ContactAddress newContactAddress) { @NonNull ContactAddress oldContactAddress, @NonNull ContactAddress newContactAddress) {
return (oldContactAddress.getContactId() == newContactAddress.getContactId()) return (oldContactAddress.getContactId() == newContactAddress.getContactId())
&& (oldContactAddress.getCryptoCurrencyId() == newContactAddress.getCryptoCurrencyId()); && (oldContactAddress.getCryptoNet() == newContactAddress.getCryptoNet());
} }
@Override @Override
public boolean areContentsTheSame( public boolean areContentsTheSame(
@ -73,7 +79,7 @@ public class ContactAddress {
ContactAddress that = (ContactAddress) o; ContactAddress that = (ContactAddress) o;
if (mContactId != that.mContactId) return false; if (mContactId != that.mContactId) return false;
if (mCryptoCurrencyId != that.mCryptoCurrencyId) return false; if (mCryptoNet != that.mCryptoNet) return false;
return mAddress.equals(that.mAddress); return mAddress.equals(that.mAddress);
} }
} }

View file

@ -7,6 +7,7 @@ import android.arch.paging.PagedList;
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;
/** /**
* Created by Henry Varona on 2/4/2018. * Created by Henry Varona on 2/4/2018.
@ -22,6 +23,15 @@ public class ContactViewModel extends AndroidViewModel {
} }
public boolean addContact(Contact contact){ public boolean addContact(Contact contact){
return this.db.contactDao().add(contact)[0] >= 0; long newContactId = this.db.contactDao().add(contact)[0];
boolean contactWasAdded = newContactId >= 0;
for (int i=0;i<contact.addressesCount();i++){
ContactAddress nextAddress = contact.getAddress(i);
nextAddress.setContactId(newContactId);
this.db.contactDao().addAddresses(nextAddress);
}
return contactWasAdded;
} }
} }

View file

@ -0,0 +1,41 @@
package cy.agorise.crystalwallet.views;
import android.support.v7.recyclerview.extensions.ListAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.models.ContactAddress;
/**
* Created by Henry Varona on 2/5/2018.
*
* An adapter to show the elements of a list of contacts addresses
*/
public class ContactAddressListAdapter extends ListAdapter<ContactAddress, ContactAddressViewHolder> {
public ContactAddressListAdapter() {
super(ContactAddress.DIFF_CALLBACK);
}
@Override
public ContactAddressViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_address_list_item,parent,false);
return new ContactAddressViewHolder(v);
}
@Override
public void onBindViewHolder(ContactAddressViewHolder holder, int position) {
ContactAddress contactAddress = getItem(position);
if (contactAddress != null) {
holder.bindTo(contactAddress);
} else {
holder.clear();
}
}
}

View file

@ -0,0 +1,97 @@
package cy.agorise.crystalwallet.views;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.enums.CryptoNet;
import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.models.ContactAddress;
/**
* Created by Henry Varona on 2/5/2017.
*
* Represents an element view from the Contact Address List
*/
public class ContactAddressViewHolder extends RecyclerView.ViewHolder {
private Spinner spCryptoNet;
private EditText etAddress;
private Context context;
public ContactAddressViewHolder(View itemView) {
super(itemView);
//TODO: use ButterKnife to load this
spCryptoNet = (Spinner) itemView.findViewById(R.id.spCryptoNet);
etAddress = (EditText) itemView.findViewById(R.id.etAddress);
this.context = itemView.getContext();
//load spinners values
CryptoNet[] cryptoNetArray = CryptoNet.values();
ArrayAdapter<CryptoNet> cryptoNetSpinnerAdapter = new ArrayAdapter<CryptoNet>(
this.context,
android.R.layout.simple_list_item_1,
cryptoNetArray
);
spCryptoNet.setAdapter(cryptoNetSpinnerAdapter);
}
/*
* Clears the information in this element view
*/
public void clear(){
spCryptoNet.setSelection(0);
etAddress.setText("");
}
/*
* Binds this view with the data of an element of the list
*/
public void bindTo(final ContactAddress contactAddress) {
if (contactAddress == null){
this.clear();
} else {
spCryptoNet.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
contactAddress.setCryptoNet(((CryptoNet)spCryptoNet.getSelectedItem()));
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
//
}
});
etAddress.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
//
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
//
}
@Override
public void afterTextChanged(Editable editable) {
contactAddress.setAddress(editable.toString());
}
});
//etAddress.setText(contactAddress.getAddress());
}
}
}

View file

@ -37,6 +37,21 @@
android:maxLines="1" android:maxLines="1"
android:textColor="@color/red" /> android:textColor="@color/red" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/rvContactAddresses"
android:layout_width="match_parent"
android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
<Button
android:id="@+id/btnAddAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/rvContactAddresses"
android:text="Add"/>
</RelativeLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<Spinner
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:id="@+id/spCryptoNet"/>
<EditText
android:id="@+id/etAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/spCryptoNet"
android:layout_alignParentEnd="true"
android:textStyle="bold" />
</RelativeLayout>
</LinearLayout>