- Now the user can select a contact in the Send Fragment

This commit is contained in:
Javier Varona 2018-02-17 21:08:38 -04:00
parent 033a959e00
commit 09ae532446
9 changed files with 400 additions and 0 deletions

View file

@ -3,6 +3,7 @@ package cy.agorise.crystalwallet.dao;
import android.arch.lifecycle.LiveData; import android.arch.lifecycle.LiveData;
import android.arch.paging.LivePagedListProvider; import android.arch.paging.LivePagedListProvider;
import android.arch.persistence.room.Dao; import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
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;
@ -26,6 +27,9 @@ public interface ContactDao {
@Query("SELECT * FROM contact ORDER BY name ASC") @Query("SELECT * FROM contact ORDER BY name ASC")
LivePagedListProvider<Integer, Contact> contactsByName(); LivePagedListProvider<Integer, Contact> contactsByName();
@Query("SELECT c.* FROM contact c WHERE c.id IN (SELECT DISTINCT(ca.contact_id) FROM contact_address ca WHERE ca.crypto_net == :cryptoNet) ORDER BY name ASC")
LivePagedListProvider<Integer, Contact> contactsByNameAndCryptoNet(String cryptoNet);
@Query("SELECT * FROM contact WHERE id = :id") @Query("SELECT * FROM contact WHERE id = :id")
LiveData<Contact> getById(long id); LiveData<Contact> getById(long id);
@ -49,4 +53,7 @@ public interface ContactDao {
@Update(onConflict = OnConflictStrategy.REPLACE) @Update(onConflict = OnConflictStrategy.REPLACE)
public void updateAddressesFields(ContactAddress... contactAddresses); public void updateAddressesFields(ContactAddress... contactAddresses);
@Delete
public void deleteContacts(Contact... contacts);
} }

View file

@ -0,0 +1,129 @@
package cy.agorise.crystalwallet.fragments;
import android.app.Dialog;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.arch.paging.PagedList;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import com.google.zxing.Result;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnItemSelected;
import butterknife.OnTextChanged;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestListener;
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateBitsharesSendRequest;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.enums.CryptoNet;
import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.models.CryptoCoinBalance;
import cy.agorise.crystalwallet.models.CryptoCurrency;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.models.GrapheneAccount;
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountListViewModel;
import cy.agorise.crystalwallet.viewmodels.validators.SendTransactionValidator;
import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener;
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ValidationField;
import cy.agorise.crystalwallet.views.ContactSelectionListAdapter;
import cy.agorise.crystalwallet.views.CryptoCurrencyAdapter;
import cy.agorise.crystalwallet.views.CryptoNetAccountAdapter;
import me.dm7.barcodescanner.zxing.ZXingScannerView;
public class ContactSelectionFragment extends DialogFragment implements ContactSelectionListAdapter.ContactSelectionListAdapterListener{
private CryptoNet cryptoNet;
private CrystalDatabase db;
private AlertDialog.Builder builder;
@BindView(R.id.contactListView)
RecyclerView contactSelectionListView;
public static ContactSelectionFragment newInstance(CryptoNet cryptoNet) {
ContactSelectionFragment f = new ContactSelectionFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putString("CRYPTO_NET", cryptoNet.name());
f.setArguments(args);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//AlertDialog.Builder
builder = new AlertDialog.Builder(getActivity(), R.style.SendTransactionTheme);
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.contact_list, null);
ButterKnife.bind(this, view);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this.getContext());
this.contactSelectionListView.setLayoutManager(linearLayoutManager);
//Prevents the list to start again when scrolling to the end
this.contactSelectionListView.setNestedScrollingEnabled(false);
final ContactSelectionListAdapter contactSelectionListAdapter = new ContactSelectionListAdapter();
contactSelectionListAdapter.setListener(this);
contactSelectionListView.setAdapter(contactSelectionListAdapter);
this.cryptoNet = CryptoNet.valueOf(getArguments().getString("CRYPTO_NET"));
if (this.cryptoNet != null) {
ContactListViewModel contactListViewModel = ViewModelProviders.of(this).get(ContactListViewModel.class);
contactListViewModel.init(this.cryptoNet);
LiveData<PagedList<Contact>> contactsLiveData = contactListViewModel.getContactList();
contactsLiveData.observe(this, new Observer<PagedList<Contact>>() {
@Override
public void onChanged(@Nullable PagedList<Contact> contacts) {
contactSelectionListAdapter.setList(contacts);
}
});
}
return builder.setView(view).create();
}
@Override
public void onContactSelected(Contact contact) {
Intent result = new Intent();
result.putExtra("CONTACT_ID", contact.getId());
getTargetFragment().onActivityResult(getTargetRequestCode(), 1, result);
this.dismiss();
}
}

View file

@ -47,6 +47,7 @@ public class ContactsFragment extends Fragment {
ButterKnife.bind(this, v); ButterKnife.bind(this, v);
ContactListViewModel contactListViewModel = ViewModelProviders.of(this).get(ContactListViewModel.class); ContactListViewModel contactListViewModel = ViewModelProviders.of(this).get(ContactListViewModel.class);
contactListViewModel.init();
LiveData<PagedList<Contact>> contactsLiveData = contactListViewModel.getContactList(); LiveData<PagedList<Contact>> contactsLiveData = contactListViewModel.getContactList();
contactsLiveData.observe(this, new Observer<PagedList<Contact>>() { contactsLiveData.observe(this, new Observer<PagedList<Contact>>() {

View file

@ -5,6 +5,7 @@ import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer; import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders; import android.arch.lifecycle.ViewModelProviders;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -12,6 +13,7 @@ import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
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.text.Editable; import android.text.Editable;
@ -23,8 +25,10 @@ import android.view.Window;
import android.view.animation.LinearInterpolator; import android.view.animation.LinearInterpolator;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.Result; import com.google.zxing.Result;
@ -41,10 +45,13 @@ import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestListen
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests; import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateBitsharesSendRequest; import cy.agorise.crystalwallet.cryptonetinforequests.ValidateBitsharesSendRequest;
import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.dao.CrystalDatabase;
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.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoCurrency;
import cy.agorise.crystalwallet.models.CryptoNetAccount; import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.models.GrapheneAccount; import cy.agorise.crystalwallet.models.GrapheneAccount;
import cy.agorise.crystalwallet.viewmodels.ContactViewModel;
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountListViewModel; import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountListViewModel;
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountViewModel; import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountViewModel;
import cy.agorise.crystalwallet.viewmodels.validators.SendTransactionValidator; import cy.agorise.crystalwallet.viewmodels.validators.SendTransactionValidator;
@ -82,6 +89,8 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
FloatingActionButton btnSend; FloatingActionButton btnSend;
@BindView(R.id.btnCancel) @BindView(R.id.btnCancel)
TextView btnCancel; TextView btnCancel;
@BindView(R.id.ivPeople)
ImageView ivPeople;
Button btnScanQrCode; Button btnScanQrCode;
@ -222,6 +231,50 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
this.sendTransactionValidator.validate(); this.sendTransactionValidator.validate();
} }
@OnClick(R.id.ivPeople)
public void searchContact(){
FragmentTransaction ft = this.getActivity().getSupportFragmentManager().beginTransaction();
Fragment prev = this.getActivity().getSupportFragmentManager().findFragmentByTag("ContactSelectionDialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Show a contact selection list
ContactSelectionFragment contactSelectionFragment = ContactSelectionFragment.newInstance(this.cryptoNetAccount.getCryptoNet());
contactSelectionFragment.setTargetFragment(this, 1);
contactSelectionFragment.show(ft, "ContactSelectionDialog");
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,resultCode,data);
if(requestCode == 1) {
if(resultCode == 1) {
long contactId = data.getLongExtra("CONTACT_ID",-1);
if (contactId > -1){
ContactViewModel contactViewModel = ViewModelProviders.of(this).get(ContactViewModel.class);
contactViewModel.init(contactId);
LiveData<List<ContactAddress>> contactAddressesLiveData = contactViewModel.getContactAddresses();
contactAddressesLiveData.observe(this, new Observer<List<ContactAddress>>() {
@Override
public void onChanged(@Nullable List<ContactAddress> contactAddresses) {
if (contactAddresses != null) {
for (ContactAddress contactAddress : contactAddresses) {
if (contactAddress.getCryptoNet() == cryptoNetAccount.getCryptoNet()) {
etTo.setText(contactAddress.getAddress());
}
}
}
}
});
}
}
}
}
@OnClick(R.id.btnCancel) @OnClick(R.id.btnCancel)
public void cancel(){ public void cancel(){
this.dismiss(); this.dismiss();

View file

@ -13,6 +13,8 @@ import android.support.v7.recyclerview.extensions.DiffCallback;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import cy.agorise.crystalwallet.enums.CryptoNet;
/** /**
* Represents a user contact * Represents a user contact
* *
@ -85,6 +87,18 @@ public class Contact {
address.setContactId(this.getId()); address.setContactId(this.getId());
} }
public ContactAddress getCryptoNetAddress(CryptoNet cryptoNet){
if (this.mAddresses != null) {
for (ContactAddress address : this.mAddresses) {
if (address.getCryptoNet() == cryptoNet) {
return address;
}
}
}
return null;
}
public static final DiffCallback<Contact> DIFF_CALLBACK = new DiffCallback<Contact>() { public static final DiffCallback<Contact> DIFF_CALLBACK = new DiffCallback<Contact>() {
@Override @Override
public boolean areItemsTheSame( public boolean areItemsTheSame(

View file

@ -6,6 +6,7 @@ import android.arch.lifecycle.LiveData;
import android.arch.paging.PagedList; import android.arch.paging.PagedList;
import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.enums.CryptoNet;
import cy.agorise.crystalwallet.models.Contact; import cy.agorise.crystalwallet.models.Contact;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction; import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
@ -30,6 +31,26 @@ public class ContactListViewModel extends AndroidViewModel {
); );
} }
public void init(){
contactList = this.db.contactDao().contactsByName().create(0,
new PagedList.Config.Builder()
.setEnablePlaceholders(true)
.setPageSize(10)
.setPrefetchDistance(10)
.build()
);
}
public void init(CryptoNet cryptoNet){
contactList = this.db.contactDao().contactsByNameAndCryptoNet(cryptoNet.name()).create(0,
new PagedList.Config.Builder()
.setEnablePlaceholders(true)
.setPageSize(10)
.setPrefetchDistance(10)
.build()
);
}
public LiveData<PagedList<Contact>> getContactList(){ public LiveData<PagedList<Contact>> getContactList(){
return this.contactList; return this.contactList;
} }

View file

@ -0,0 +1,57 @@
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.Contact;
/**
* Created by Henry Varona on 2/16/2018.
*
* An adapter to show the elements of a list of contacts to be selected by the user
*/
public class ContactSelectionListAdapter extends ListAdapter<Contact, ContactSelectionViewHolder> implements ContactSelectionViewHolder.ContactSelectionViewHolderListener {
private ContactSelectionListAdapterListener listener;
public ContactSelectionListAdapter() {
super(Contact.DIFF_CALLBACK);
}
@Override
public ContactSelectionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_selection_list_item,parent,false);
return new ContactSelectionViewHolder(v);
}
@Override
public void onBindViewHolder(ContactSelectionViewHolder holder, int position) {
Contact contact = getItem(position);
if (contact != null) {
holder.bindTo(contact);
holder.setListener(this);
} else {
holder.clear();
}
}
@Override
public void onContactSelected(ContactSelectionViewHolder contactSelectionViewHolder, Contact contact) {
if (this.listener != null){
this.listener.onContactSelected(contact);
}
}
public void setListener(ContactSelectionListAdapterListener listener){
this.listener = listener;
}
public interface ContactSelectionListAdapterListener{
public void onContactSelected(Contact contact);
}
}

View file

@ -0,0 +1,79 @@
package cy.agorise.crystalwallet.views;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.activities.CreateContactActivity;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.Contact;
/**
* Created by Henry Varona on 2/16/2018.
*
* Represents an element view from the Contact Selection List
*/
public class ContactSelectionViewHolder extends RecyclerView.ViewHolder {
private TextView tvName;
private ImageView ivThumbnail;
private TextView tvLastPaid;
private Context context;
private ContactSelectionViewHolderListener listener;
public ContactSelectionViewHolder(View itemView) {
super(itemView);
//TODO: use ButterKnife to load this
tvName = (TextView) itemView.findViewById(R.id.tvContactName);
ivThumbnail = (ImageView) itemView.findViewById(R.id.ivContactThumbnail);
tvLastPaid = (TextView) itemView.findViewById(R.id.tvLastPaid);
this.context = itemView.getContext();
}
public void setListener(ContactSelectionViewHolderListener listener){
this.listener = listener;
}
/*
* Clears the information in this element view
*/
public void clear(){
tvName.setText("");
ivThumbnail.setImageResource(android.R.color.transparent);
tvLastPaid.setText("");
}
/*
* Binds this view with the data of an element of the list
*/
public void bindTo(final Contact contact) {
if (contact == null){
this.clear();
} else {
final ContactSelectionViewHolder thisViewHolder = this;
tvName.setText(contact.getName());
tvLastPaid.setText("Paid: 1 Jan, 2001 01:01");
this.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null){
listener.onContactSelected(thisViewHolder, contact);
}
}
});
}
}
public interface ContactSelectionViewHolderListener {
public void onContactSelected(ContactSelectionViewHolder contactSelectionViewHolder, Contact contact);
}
}

View file

@ -0,0 +1,39 @@
<?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">
<ImageView
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:id="@+id/ivContactThumbnail"/>
<TextView
android:id="@+id/tvContactName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/ivContactThumbnail"
android:text="Loading name..."
android:textStyle="bold" />
<TextView
android:id="@+id/tvLastPaid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tvContactName"
android:layout_toRightOf="@+id/ivContactThumbnail"
android:text="Paid: Jan 1, 2001, 01:01"
android:textColor="@android:color/darker_gray" />
</RelativeLayout>
</LinearLayout>