Merge branch 'master' into master
This commit is contained in:
commit
fcc20711dd
68 changed files with 3261 additions and 438 deletions
|
@ -63,4 +63,6 @@ dependencies {
|
||||||
annotationProcessor 'android.arch.lifecycle:compiler:1.0.0'
|
annotationProcessor 'android.arch.lifecycle:compiler:1.0.0'
|
||||||
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
|
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
||||||
|
|
||||||
|
compile 'com.squareup.picasso:picasso:2.5.2'
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"identityHash": "a44ccb96c8213951403ed2a283fb3367",
|
"identityHash": "22cb2a56b28a9f7088ec98d6a72f9f67",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "account_seed",
|
"tableName": "account_seed",
|
||||||
|
@ -235,7 +235,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "contact",
|
"tableName": "contact",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `gravatar` TEXT)",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `email` TEXT, `gravatar` TEXT)",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "mId",
|
"fieldPath": "mId",
|
||||||
|
@ -249,6 +249,12 @@
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "mEmail",
|
||||||
|
"columnName": "email",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "mGravatar",
|
"fieldPath": "mGravatar",
|
||||||
"columnName": "gravatar",
|
"columnName": "gravatar",
|
||||||
|
@ -278,6 +284,70 @@
|
||||||
"name"
|
"name"
|
||||||
],
|
],
|
||||||
"createSql": "CREATE UNIQUE INDEX `index_contact_name` ON `${TABLE_NAME}` (`name`)"
|
"createSql": "CREATE UNIQUE INDEX `index_contact_name` ON `${TABLE_NAME}` (`name`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_contact_email",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"createSql": "CREATE INDEX `index_contact_email` ON `${TABLE_NAME}` (`email`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "contact_address",
|
||||||
|
"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": [
|
||||||
|
{
|
||||||
|
"fieldPath": "mId",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"autoGenerate": true
|
||||||
|
},
|
||||||
|
"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",
|
||||||
|
"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": []
|
"foreignKeys": []
|
||||||
|
@ -622,7 +692,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, \"22cb2a56b28a9f7088ec98d6a72f9f67\")"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="cy.agorise.crystalwallet">
|
package="cy.agorise.crystalwallet">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="cy.agorise.crystalwallet.application.CrystalApplication"
|
android:name=".application.CrystalApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="Crystal"
|
android:label="Crystal"
|
||||||
|
@ -21,7 +22,7 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".activities.BoardActivity"
|
<activity android:name=".activities.BoardActivity"
|
||||||
android:theme="@style/AppTheme.NoActionBar" > <!-- Dirty trick to avoid toolbar error on balance -->
|
android:theme="@style/AppTheme.NoActionBar" >
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".activities.AccountSeedsManagementActivity" >
|
<activity android:name=".activities.AccountSeedsManagementActivity" >
|
||||||
</activity>
|
</activity>
|
||||||
|
@ -37,20 +38,27 @@
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".activities.BackupSeedActivity" >
|
<activity android:name=".activities.BackupSeedActivity" >
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".activities.SettingsActivity"
|
<activity android:name=".activities.PinRequestActivity">
|
||||||
android:theme="@style/AppTheme.NoActionBar"
|
|
||||||
android:windowSoftInputMode="adjustPan" >
|
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".activities.AccountsActivity"
|
<activity
|
||||||
android:theme="@style/ActivityDialog"
|
android:name=".activities.SettingsActivity"
|
||||||
android:parentActivityName=".activities.BoardActivity" >
|
android:theme="@style/AppTheme.NoActionBar"
|
||||||
|
android:windowSoftInputMode="adjustPan">
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".activities.AccountsActivity"
|
||||||
|
android:parentActivityName=".activities.BoardActivity"
|
||||||
|
android:theme="@style/ActivityDialog">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".activities.BoardActivity" />
|
android:value=".activities.BoardActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service android:name=".service.CrystalWalletService"
|
<service
|
||||||
android:exported="false"/>
|
android:name=".service.CrystalWalletService"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<activity android:name=".activities.CreateContactActivity"></activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -204,6 +204,12 @@ public class BoardActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.fabAddContact)
|
||||||
|
public void beginCreateContact(){
|
||||||
|
Intent intent = new Intent(this, CreateContactActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dispatch the user to the receive fragment using this account
|
* dispatch the user to the receive fragment using this account
|
||||||
*/
|
*/
|
||||||
|
@ -215,8 +221,16 @@ public class BoardActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
ft.addToBackStack(null);
|
ft.addToBackStack(null);
|
||||||
|
|
||||||
|
long receiveCryptoNetAccountId = -1;
|
||||||
|
if (this.cryptoNetAccountId != -1){
|
||||||
|
receiveCryptoNetAccountId = this.cryptoNetAccountId;
|
||||||
|
} else {
|
||||||
|
CryptoNetBalanceListViewModel cryptoNetBalanceListViewModel = ViewModelProviders.of(this).get(CryptoNetBalanceListViewModel.class);
|
||||||
|
receiveCryptoNetAccountId = cryptoNetBalanceListViewModel.getFirstBitsharesAccountId();
|
||||||
|
}
|
||||||
|
|
||||||
// Create and show the dialog.
|
// Create and show the dialog.
|
||||||
ReceiveTransactionFragment newFragment = ReceiveTransactionFragment.newInstance(this.cryptoNetAccountId);
|
ReceiveTransactionFragment newFragment = ReceiveTransactionFragment.newInstance(receiveCryptoNetAccountId);
|
||||||
newFragment.show(ft, "ReceiveDialog");
|
newFragment.show(ft, "ReceiveDialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
package cy.agorise.crystalwallet.activities;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
|
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.AppCompatActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnClick;
|
||||||
|
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.ValidateCreateBitsharesAccountRequest;
|
||||||
|
import cy.agorise.crystalwallet.models.Contact;
|
||||||
|
import cy.agorise.crystalwallet.models.ContactAddress;
|
||||||
|
import cy.agorise.crystalwallet.models.GrapheneAccount;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.ContactViewModel;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.CreateContactValidator;
|
||||||
|
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.validationfields.ValidationField;
|
||||||
|
import cy.agorise.crystalwallet.views.ContactAddressListAdapter;
|
||||||
|
import cy.agorise.crystalwallet.views.ContactViewHolder;
|
||||||
|
|
||||||
|
public class CreateContactActivity extends AppCompatActivity implements UIValidatorListener {
|
||||||
|
|
||||||
|
@BindView(R.id.etName)
|
||||||
|
EditText etName;
|
||||||
|
@BindView(R.id.tvNameError)
|
||||||
|
TextView tvNameError;
|
||||||
|
@BindView(R.id.etEmail)
|
||||||
|
EditText etEmail;
|
||||||
|
@BindView(R.id.tvEmailError)
|
||||||
|
TextView tvEmailError;
|
||||||
|
@BindView(R.id.btnCancel)
|
||||||
|
Button btnCancel;
|
||||||
|
@BindView(R.id.btnCreate)
|
||||||
|
Button btnCreate;
|
||||||
|
@BindView(R.id.btnModify)
|
||||||
|
Button btnModify;
|
||||||
|
@BindView(R.id.rvContactAddresses)
|
||||||
|
RecyclerView rvContactAddresses;
|
||||||
|
@BindView(R.id.btnAddAddress)
|
||||||
|
Button btnAddAddress;
|
||||||
|
List<ContactAddress> contactAddressList;
|
||||||
|
ContactAddressListAdapter listAdapter;
|
||||||
|
|
||||||
|
CreateContactValidator createContactValidator;
|
||||||
|
ModifyContactValidator modifyContactValidator;
|
||||||
|
|
||||||
|
Contact contact;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_create_contact);
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
|
btnCreate.setEnabled(false);
|
||||||
|
|
||||||
|
listAdapter = new ContactAddressListAdapter();
|
||||||
|
rvContactAddresses.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
|
||||||
|
rvContactAddresses.setAdapter(listAdapter);
|
||||||
|
|
||||||
|
long contactId = this.getIntent().getLongExtra("CONTACT_ID",-1);
|
||||||
|
|
||||||
|
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());
|
||||||
|
etEmail.setText(contact.getEmail());
|
||||||
|
|
||||||
|
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,etEmail);
|
||||||
|
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,etEmail);
|
||||||
|
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,
|
||||||
|
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
||||||
|
void afterContactNameChanged(Editable editable) {
|
||||||
|
this.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnTextChanged(value = R.id.etEmail,
|
||||||
|
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
||||||
|
void afterEmailChanged(Editable editable) {
|
||||||
|
this.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@OnClick(R.id.btnAddAddress)
|
||||||
|
public void addAddress(){
|
||||||
|
ContactAddress newContactAddress = new ContactAddress();
|
||||||
|
this.contactAddressList.add(newContactAddress);
|
||||||
|
this.listAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.btnCancel)
|
||||||
|
public void cancel(){
|
||||||
|
this.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.btnModify)
|
||||||
|
public void modifyContact(){
|
||||||
|
if (this.modifyContactValidator.isValid()) {
|
||||||
|
this.contact.setName(etName.getText().toString());
|
||||||
|
this.contact.setEmail(etEmail.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)
|
||||||
|
public void createContact(){
|
||||||
|
if (this.createContactValidator.isValid()) {
|
||||||
|
Contact newContact = new Contact();
|
||||||
|
newContact.setName(etName.getText().toString());
|
||||||
|
newContact.setEmail(etEmail.getText().toString());
|
||||||
|
|
||||||
|
for (ContactAddress contactAddress : contactAddressList){
|
||||||
|
newContact.addAddress(contactAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactViewModel contactViewModel = ViewModelProviders.of(this).get(ContactViewModel.class);
|
||||||
|
if (contactViewModel.addContact(newContact)){
|
||||||
|
this.finish();
|
||||||
|
} else {
|
||||||
|
createContactValidator.validate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValidationSucceeded(final ValidationField field) {
|
||||||
|
final CreateContactActivity activity = this;
|
||||||
|
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
if (field.getView() == etName) {
|
||||||
|
tvNameError.setText("");
|
||||||
|
} else if (field.getView() == etEmail) {
|
||||||
|
tvEmailError.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activity.isValid()){
|
||||||
|
btnCreate.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
btnCreate.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValidationFailed(final ValidationField field) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (field.getView() == etName) {
|
||||||
|
tvNameError.setText(field.getMessage());
|
||||||
|
} else if (field.getView() == etEmail) {
|
||||||
|
tvEmailError.setText(field.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,6 @@
|
||||||
package cy.agorise.crystalwallet.activities;
|
package cy.agorise.crystalwallet.activities;
|
||||||
|
|
||||||
import android.arch.lifecycle.LifecycleActivity;
|
|
||||||
import android.arch.lifecycle.LiveData;
|
|
||||||
import android.arch.lifecycle.Observer;
|
|
||||||
import android.arch.lifecycle.ViewModelProvider;
|
|
||||||
import android.arch.lifecycle.ViewModelProviders;
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.arch.paging.PagedList;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -34,12 +29,11 @@ import cy.agorise.crystalwallet.randomdatagenerators.RandomCryptoCoinBalanceGene
|
||||||
import cy.agorise.crystalwallet.randomdatagenerators.RandomCryptoNetAccountGenerator;
|
import cy.agorise.crystalwallet.randomdatagenerators.RandomCryptoNetAccountGenerator;
|
||||||
import cy.agorise.crystalwallet.randomdatagenerators.RandomSeedGenerator;
|
import cy.agorise.crystalwallet.randomdatagenerators.RandomSeedGenerator;
|
||||||
import cy.agorise.crystalwallet.randomdatagenerators.RandomTransactionsGenerator;
|
import cy.agorise.crystalwallet.randomdatagenerators.RandomTransactionsGenerator;
|
||||||
|
import cy.agorise.crystalwallet.application.CrystalSecurityMonitor;
|
||||||
import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel;
|
import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel;
|
||||||
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
|
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
|
||||||
import cy.agorise.crystalwallet.views.TransactionListView;
|
import cy.agorise.crystalwallet.views.TransactionListView;
|
||||||
|
|
||||||
import static cy.agorise.crystalwallet.R.string.transactions;
|
|
||||||
|
|
||||||
public class IntroActivity extends AppCompatActivity {
|
public class IntroActivity extends AppCompatActivity {
|
||||||
|
|
||||||
TransactionListViewModel transactionListViewModel;
|
TransactionListViewModel transactionListViewModel;
|
||||||
|
@ -82,6 +76,9 @@ public class IntroActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.getApplication().registerActivityLifecycleCallbacks(new CrystalSecurityMonitor(this));
|
||||||
|
|
||||||
|
|
||||||
//Checks if the user has any seed created
|
//Checks if the user has any seed created
|
||||||
/*AccountSeedListViewModel accountSeedListViewModel = ViewModelProviders.of(this).get(AccountSeedListViewModel.class);
|
/*AccountSeedListViewModel accountSeedListViewModel = ViewModelProviders.of(this).get(AccountSeedListViewModel.class);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
package cy.agorise.crystalwallet.activities;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnClick;
|
||||||
|
import butterknife.OnTextChanged;
|
||||||
|
import cy.agorise.crystalwallet.R;
|
||||||
|
import cy.agorise.crystalwallet.models.AccountSeed;
|
||||||
|
import cy.agorise.crystalwallet.models.GeneralSetting;
|
||||||
|
import cy.agorise.crystalwallet.util.PasswordManager;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.AccountSeedViewModel;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
|
||||||
|
|
||||||
|
public class PinRequestActivity extends AppCompatActivity {
|
||||||
|
private String passwordEncrypted;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
//Do nothing to prevent the user to use the back button
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindView(R.id.etPassword)
|
||||||
|
EditText etPassword;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_pin_request);
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
|
GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of(this).get(GeneralSettingListViewModel.class);
|
||||||
|
LiveData<List<GeneralSetting>> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList();
|
||||||
|
generalSettingsLiveData.observe(this, new Observer<List<GeneralSetting>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable List<GeneralSetting> generalSettings) {
|
||||||
|
passwordEncrypted = "";
|
||||||
|
|
||||||
|
if (generalSettings != null){
|
||||||
|
for (GeneralSetting generalSetting:generalSettings) {
|
||||||
|
if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){
|
||||||
|
if (!generalSetting.getValue().isEmpty()){
|
||||||
|
passwordEncrypted = generalSetting.getValue();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnTextChanged(value = R.id.etPassword,
|
||||||
|
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
||||||
|
void afterPasswordChanged(Editable editable) {
|
||||||
|
if (PasswordManager.checkPassword(passwordEncrypted, etPassword.getText().toString())) {
|
||||||
|
this.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,9 @@ public abstract class BitsharesFaucetApiGenerator {
|
||||||
* @param url The url of the faucet
|
* @param url The url of the faucet
|
||||||
* @return The bitshares id of the registered account, or null
|
* @return The bitshares id of the registered account, or null
|
||||||
*/
|
*/
|
||||||
public static boolean registerBitsharesAccount(String accountName, String ownerKey,
|
public static void registerBitsharesAccount(String accountName, String ownerKey,
|
||||||
String activeKey, String memoKey, String url){
|
String activeKey, String memoKey, String url,
|
||||||
|
final ApiRequest request){
|
||||||
CreateAccountPetition petition = new CreateAccountPetition();
|
CreateAccountPetition petition = new CreateAccountPetition();
|
||||||
final Account account = new Account();
|
final Account account = new Account();
|
||||||
account.name=accountName;
|
account.name=accountName;
|
||||||
|
@ -62,8 +63,7 @@ public abstract class BitsharesFaucetApiGenerator {
|
||||||
|
|
||||||
HashMap<String, HashMap> hashMap = new HashMap<>();
|
HashMap<String, HashMap> hashMap = new HashMap<>();
|
||||||
hashMap.put("account", hm);
|
hashMap.put("account", hm);
|
||||||
final boolean[] answer = {false};
|
|
||||||
final Object SYNC = new Object();
|
|
||||||
try {
|
try {
|
||||||
ServiceGenerator sg = new ServiceGenerator(url);
|
ServiceGenerator sg = new ServiceGenerator(url);
|
||||||
IWebService service = sg.getService(IWebService.class);
|
IWebService service = sg.getService(IWebService.class);
|
||||||
|
@ -78,56 +78,36 @@ public abstract class BitsharesFaucetApiGenerator {
|
||||||
if (resp.account != null) {
|
if (resp.account != null) {
|
||||||
try {
|
try {
|
||||||
if(resp.account.name.equals(account.name)) {
|
if(resp.account.name.equals(account.name)) {
|
||||||
synchronized (SYNC){
|
request.getListener().success(true,request.getId());
|
||||||
answer[0] = true;
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
System.out.println("ERROR account name different" + resp.account.name);
|
request.getListener().fail(request.getId());
|
||||||
//ERROR
|
|
||||||
synchronized (SYNC) {
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
synchronized (SYNC) {
|
request.getListener().fail(request.getId());
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
System.out.println("ERROR response doesn't have account " + response.message());
|
System.out.println("ERROR response doesn't have account " + response.message());
|
||||||
//ERROR
|
request.getListener().fail(request.getId());
|
||||||
synchronized (SYNC) {
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
System.out.println("ERROR fetching info");
|
System.out.println("ERROR fetching info");
|
||||||
//ERROR
|
request.getListener().fail(request.getId());
|
||||||
synchronized (SYNC) {
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<RegisterAccountResponse> call, Throwable t) {
|
public void onFailure(Call<RegisterAccountResponse> call, Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
synchronized (SYNC) {
|
request.getListener().fail(request.getId());
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
synchronized (SYNC) {
|
|
||||||
SYNC.wait(60000);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
request.getListener().fail(request.getId());
|
||||||
|
|
||||||
return answer[0];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,14 +12,14 @@ import cy.agorise.crystalwallet.dao.BitsharesAssetDao;
|
||||||
import cy.agorise.crystalwallet.dao.CryptoCoinBalanceDao;
|
import cy.agorise.crystalwallet.dao.CryptoCoinBalanceDao;
|
||||||
import cy.agorise.crystalwallet.dao.CryptoCurrencyDao;
|
import cy.agorise.crystalwallet.dao.CryptoCurrencyDao;
|
||||||
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
||||||
import cy.agorise.crystalwallet.dao.TransactionDao;
|
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||||
import cy.agorise.crystalwallet.manager.BitsharesAccountManager;
|
|
||||||
import cy.agorise.crystalwallet.models.BitsharesAsset;
|
import cy.agorise.crystalwallet.models.BitsharesAsset;
|
||||||
import cy.agorise.crystalwallet.models.BitsharesAssetInfo;
|
import cy.agorise.crystalwallet.models.BitsharesAssetInfo;
|
||||||
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;
|
||||||
import cy.agorise.crystalwallet.models.CryptoCurrencyEquivalence;
|
import cy.agorise.crystalwallet.models.CryptoCurrencyEquivalence;
|
||||||
|
import cy.agorise.crystalwallet.network.CryptoNetManager;
|
||||||
import cy.agorise.crystalwallet.network.WebSocketThread;
|
import cy.agorise.crystalwallet.network.WebSocketThread;
|
||||||
import cy.agorise.graphenej.Address;
|
import cy.agorise.graphenej.Address;
|
||||||
import cy.agorise.graphenej.Asset;
|
import cy.agorise.graphenej.Asset;
|
||||||
|
@ -43,11 +43,9 @@ import cy.agorise.graphenej.api.TransactionBroadcastSequence;
|
||||||
import cy.agorise.graphenej.interfaces.NodeErrorListener;
|
import cy.agorise.graphenej.interfaces.NodeErrorListener;
|
||||||
import cy.agorise.graphenej.interfaces.SubscriptionListener;
|
import cy.agorise.graphenej.interfaces.SubscriptionListener;
|
||||||
import cy.agorise.graphenej.interfaces.WitnessResponseListener;
|
import cy.agorise.graphenej.interfaces.WitnessResponseListener;
|
||||||
import cy.agorise.graphenej.models.AccountBalanceUpdate;
|
|
||||||
import cy.agorise.graphenej.models.AccountProperties;
|
import cy.agorise.graphenej.models.AccountProperties;
|
||||||
import cy.agorise.graphenej.models.BaseResponse;
|
import cy.agorise.graphenej.models.BaseResponse;
|
||||||
import cy.agorise.graphenej.models.BroadcastedTransaction;
|
import cy.agorise.graphenej.models.BroadcastedTransaction;
|
||||||
import cy.agorise.graphenej.models.HistoricalTransfer;
|
|
||||||
import cy.agorise.graphenej.models.SubscriptionResponse;
|
import cy.agorise.graphenej.models.SubscriptionResponse;
|
||||||
import cy.agorise.graphenej.models.WitnessResponse;
|
import cy.agorise.graphenej.models.WitnessResponse;
|
||||||
import cy.agorise.graphenej.operations.TransferOperation;
|
import cy.agorise.graphenej.operations.TransferOperation;
|
||||||
|
@ -62,12 +60,8 @@ public abstract class GrapheneApiGenerator {
|
||||||
|
|
||||||
//TODO network connections
|
//TODO network connections
|
||||||
//TODO make to work with all Graphene type, not only bitshares
|
//TODO make to work with all Graphene type, not only bitshares
|
||||||
public static String url = "http://185.208.208.147:11012";
|
|
||||||
public static String faucetUrl = "http://185.208.208.147:5010";
|
public static String faucetUrl = "http://185.208.208.147:5010";
|
||||||
private static String equivalentUrl = "http://185.208.208.147:8090";
|
private static String equivalentUrl = "wss://bitshares.openledger.info/ws";
|
||||||
//public static String url = "wss://bitshares.openledger.info/ws";
|
|
||||||
//private static Str ing equivalentUrl = "wss://bitshares.openledger.info/ws";
|
|
||||||
|
|
||||||
|
|
||||||
// The message broker for bitshares
|
// The message broker for bitshares
|
||||||
private static SubscriptionMessagesHub bitsharesSubscriptionHub = new SubscriptionMessagesHub("", "", true, new NodeErrorListener() {
|
private static SubscriptionMessagesHub bitsharesSubscriptionHub = new SubscriptionMessagesHub("", "", true, new NodeErrorListener() {
|
||||||
|
@ -81,7 +75,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
/**
|
/**
|
||||||
* The subscription thread for the real time updates
|
* The subscription thread for the real time updates
|
||||||
*/
|
*/
|
||||||
private static WebSocketThread subscriptionThread = new WebSocketThread(bitsharesSubscriptionHub,url);
|
private static WebSocketThread subscriptionThread = new WebSocketThread(bitsharesSubscriptionHub, CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
/**
|
/**
|
||||||
* This is used for manager each listener in the subscription thread
|
* This is used for manager each listener in the subscription thread
|
||||||
*/
|
*/
|
||||||
|
@ -114,7 +108,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +136,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
|
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
@ -169,7 +163,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +190,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +217,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +241,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +286,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +334,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,12 +347,10 @@ public abstract class GrapheneApiGenerator {
|
||||||
*/
|
*/
|
||||||
public static void subscribeBitsharesAccount(final long accountId, final String accountBitsharesId,
|
public static void subscribeBitsharesAccount(final long accountId, final String accountBitsharesId,
|
||||||
final Context context){
|
final Context context){
|
||||||
System.out.println("GrapheneAPI subscribe to account balance update");
|
|
||||||
if(!currentBitsharesListener.containsKey(accountId)){
|
if(!currentBitsharesListener.containsKey(accountId)){
|
||||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||||
final BitsharesAssetDao bitsharesAssetDao = db.bitsharesAssetDao();
|
final BitsharesAssetDao bitsharesAssetDao = db.bitsharesAssetDao();
|
||||||
final CryptoCurrencyDao cryptoCurrencyDao = db.cryptoCurrencyDao();
|
final CryptoCurrencyDao cryptoCurrencyDao = db.cryptoCurrencyDao();
|
||||||
final TransactionDao transactionDao = db.transactionDao();
|
|
||||||
SubscriptionListener balanceListener = new SubscriptionListener() {
|
SubscriptionListener balanceListener = new SubscriptionListener() {
|
||||||
@Override
|
@Override
|
||||||
public ObjectType getInterestObjectType() {
|
public ObjectType getInterestObjectType() {
|
||||||
|
@ -374,16 +366,15 @@ public abstract class GrapheneApiGenerator {
|
||||||
BroadcastedTransaction transactionUpdate = (BroadcastedTransaction) update;
|
BroadcastedTransaction transactionUpdate = (BroadcastedTransaction) update;
|
||||||
for(BaseOperation operation : transactionUpdate.getTransaction().getOperations()){
|
for(BaseOperation operation : transactionUpdate.getTransaction().getOperations()){
|
||||||
if(operation instanceof TransferOperation){
|
if(operation instanceof TransferOperation){
|
||||||
TransferOperation tOperation = (TransferOperation) operation;
|
final TransferOperation tOperation = (TransferOperation) operation;
|
||||||
if(tOperation.getFrom().getObjectId().equals(accountBitsharesId) || tOperation.getTo().getObjectId().equals(accountBitsharesId)){
|
if(tOperation.getFrom().getObjectId().equals(accountBitsharesId) || tOperation.getTo().getObjectId().equals(accountBitsharesId)){
|
||||||
GrapheneApiGenerator.getAccountBalance(accountId,accountBitsharesId,context);
|
GrapheneApiGenerator.getAccountBalance(accountId,accountBitsharesId,context);
|
||||||
CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
final CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
||||||
transaction.setAccountId(accountId);
|
transaction.setAccountId(accountId);
|
||||||
transaction.setAmount(tOperation.getAssetAmount().getAmount().longValue());
|
transaction.setAmount(tOperation.getAssetAmount().getAmount().longValue());
|
||||||
BitsharesAssetInfo info = bitsharesAssetDao.getBitsharesAssetInfoById(tOperation.getAssetAmount().getAsset().getObjectId());
|
BitsharesAssetInfo info = bitsharesAssetDao.getBitsharesAssetInfoById(tOperation.getAssetAmount().getAsset().getObjectId());
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
//The cryptoCurrency is not in the database, queringfor its data
|
//The cryptoCurrency is not in the database, queringfor its data
|
||||||
final Object SYNC = new Object(); //Object to syn the answer
|
|
||||||
ApiRequest assetRequest = new ApiRequest(0, new ApiRequestListener() {
|
ApiRequest assetRequest = new ApiRequest(0, new ApiRequestListener() {
|
||||||
@Override
|
@Override
|
||||||
public void success(Object answer, int idPetition) {
|
public void success(Object answer, int idPetition) {
|
||||||
|
@ -394,40 +385,21 @@ public abstract class GrapheneApiGenerator {
|
||||||
info.setCryptoCurrencyId(idCryptoCurrency);
|
info.setCryptoCurrencyId(idCryptoCurrency);
|
||||||
asset.setId((int)idCryptoCurrency);
|
asset.setId((int)idCryptoCurrency);
|
||||||
bitsharesAssetDao.insertBitsharesAssetInfo(info);
|
bitsharesAssetDao.insertBitsharesAssetInfo(info);
|
||||||
}
|
saveTransaction(transaction,(int)info.getCryptoCurrencyId(),accountBitsharesId,tOperation,context);
|
||||||
synchronized (SYNC){
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(int idPetition) {
|
public void fail(int idPetition) {
|
||||||
synchronized (SYNC){
|
//TODO error retrieving asset
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ArrayList<String> assets = new ArrayList<>();
|
ArrayList<String> assets = new ArrayList<>();
|
||||||
assets.add(tOperation.getAssetAmount().getAsset().getObjectId());
|
assets.add(tOperation.getAssetAmount().getAsset().getObjectId());
|
||||||
GrapheneApiGenerator.getAssetById(assets,assetRequest);
|
GrapheneApiGenerator.getAssetById(assets,assetRequest);
|
||||||
|
}else{
|
||||||
synchronized (SYNC){
|
saveTransaction(transaction,(int)info.getCryptoCurrencyId(),accountBitsharesId,tOperation,context);
|
||||||
try {SYNC.wait(60000);} catch (InterruptedException ignore) {}
|
|
||||||
}
|
|
||||||
info = bitsharesAssetDao.getBitsharesAssetInfoById(tOperation.getAssetAmount().getAsset().getObjectId());
|
|
||||||
}
|
}
|
||||||
if( info == null){
|
|
||||||
//We couldn't retrieve the cryptocurrency
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
transaction.setIdCurrency((int)info.getCryptoCurrencyId());
|
|
||||||
transaction.setConfirmed(true); //graphene transaction are always confirmed
|
|
||||||
transaction.setFrom(tOperation.getFrom().getObjectId());
|
|
||||||
transaction.setInput(!tOperation.getFrom().getObjectId().equals(accountBitsharesId));
|
|
||||||
transaction.setTo(tOperation.getTo().getObjectId());
|
|
||||||
transaction.setDate(new Date());
|
|
||||||
transactionDao.insertTransaction(transaction);
|
|
||||||
//GrapheneApiGenerator.getBlockHeaderTime(, new ApiRequest(0, new BitsharesAccountManager.GetTransactionDate(transaction, db.transactionDao())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,6 +421,26 @@ public abstract class GrapheneApiGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fucniton to save a transaction retrieved from the update
|
||||||
|
* @param transaction The transaction db object
|
||||||
|
* @param currencyId The id of the currency on the database
|
||||||
|
* @param accountBitsharesId The id of the account in the bitshares network
|
||||||
|
* @param tOperation The transfer operation fetched from the update
|
||||||
|
* @param context The context of this app
|
||||||
|
*/
|
||||||
|
private static void saveTransaction(CryptoCoinTransaction transaction, int currencyId,
|
||||||
|
String accountBitsharesId, TransferOperation tOperation ,
|
||||||
|
Context context){
|
||||||
|
transaction.setIdCurrency(currencyId);
|
||||||
|
transaction.setConfirmed(true); //graphene transaction are always confirmed
|
||||||
|
transaction.setFrom(tOperation.getFrom().getObjectId());
|
||||||
|
transaction.setInput(!tOperation.getFrom().getObjectId().equals(accountBitsharesId));
|
||||||
|
transaction.setTo(tOperation.getTo().getObjectId());
|
||||||
|
transaction.setDate(new Date());
|
||||||
|
CrystalDatabase.getAppDatabase(context).transactionDao().insertTransaction(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels all bitshares account subscriptions
|
* Cancels all bitshares account subscriptions
|
||||||
*/
|
*/
|
||||||
|
@ -515,7 +507,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
|
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
|
@ -542,7 +534,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
public void onError(BaseResponse.Error error) {
|
public void onError(BaseResponse.Error error) {
|
||||||
request.getListener().fail(request.getId());
|
request.getListener().fail(request.getId());
|
||||||
}
|
}
|
||||||
}),url);
|
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -674,7 +666,7 @@ public abstract class GrapheneApiGenerator {
|
||||||
Converter converter = new Converter();
|
Converter converter = new Converter();
|
||||||
order.getSellPrice().base.getAsset().setPrecision(baseAsset.getPrecision());
|
order.getSellPrice().base.getAsset().setPrecision(baseAsset.getPrecision());
|
||||||
order.getSellPrice().quote.getAsset().setPrecision(quoteAsset.getPrecision());
|
order.getSellPrice().quote.getAsset().setPrecision(quoteAsset.getPrecision());
|
||||||
double equiValue = converter.getConversionRate(order.getSellPrice(), Converter.BASE_TO_QUOTE);
|
double equiValue = converter.getConversionRate(order.getSellPrice(), Converter.QUOTE_TO_BASE);
|
||||||
CryptoCurrencyEquivalence equivalence = new CryptoCurrencyEquivalence(baseAsset.getId(), quoteAsset.getId(), (int) (Math.pow(10, baseAsset.getPrecision()) * equiValue), new Date());
|
CryptoCurrencyEquivalence equivalence = new CryptoCurrencyEquivalence(baseAsset.getId(), quoteAsset.getId(), (int) (Math.pow(10, baseAsset.getPrecision()) * equiValue), new Date());
|
||||||
CrystalDatabase.getAppDatabase(context).cryptoCurrencyEquivalenceDao().insertCryptoCurrencyEquivalence(equivalence);
|
CrystalDatabase.getAppDatabase(context).cryptoCurrencyEquivalenceDao().insertCryptoCurrencyEquivalence(equivalence);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -6,6 +6,11 @@ import android.content.Intent;
|
||||||
import com.idescout.sql.SqlScoutServer;
|
import com.idescout.sql.SqlScoutServer;
|
||||||
|
|
||||||
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
||||||
|
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||||
|
import cy.agorise.crystalwallet.models.BitsharesAsset;
|
||||||
|
import cy.agorise.crystalwallet.models.BitsharesAssetInfo;
|
||||||
|
import cy.agorise.crystalwallet.models.CryptoCurrencyEquivalence;
|
||||||
|
import cy.agorise.crystalwallet.network.CryptoNetManager;
|
||||||
import cy.agorise.crystalwallet.service.CrystalWalletService;
|
import cy.agorise.crystalwallet.service.CrystalWalletService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,6 +20,25 @@ import cy.agorise.crystalwallet.service.CrystalWalletService;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class CrystalApplication extends Application {
|
public class CrystalApplication extends Application {
|
||||||
|
public static String BITSHARES_URL[] =
|
||||||
|
{
|
||||||
|
"wss://de.palmpay.io/ws", // Custom node
|
||||||
|
"wss://bitshares.nu/ws",
|
||||||
|
"wss://dexnode.net/ws", // Dallas, USA
|
||||||
|
"wss://bitshares.crypto.fans/ws", // Munich, Germany
|
||||||
|
"wss://bitshares.openledger.info/ws", // Openledger node
|
||||||
|
"ws://185.208.208.147:8090" // Custom node
|
||||||
|
};
|
||||||
|
|
||||||
|
public static String BITSHARES_TESTNET_URL[] =
|
||||||
|
{
|
||||||
|
"http://185.208.208.147:11012", // Openledger node
|
||||||
|
};
|
||||||
|
|
||||||
|
//This is for testing the equivalent values on the testnet TODO remove
|
||||||
|
public static BitsharesAsset bitUSDAsset = new BitsharesAsset("USD",4,"1.3.121",BitsharesAsset.Type.SMART_COIN);
|
||||||
|
//This is for testing the equivalent values on the testnet TODO remove
|
||||||
|
public static BitsharesAsset bitEURAsset = new BitsharesAsset("EUR",4,"1.3.120",BitsharesAsset.Type.SMART_COIN);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
|
@ -24,6 +48,36 @@ public class CrystalApplication extends Application {
|
||||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(this.getApplicationContext());
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(this.getApplicationContext());
|
||||||
SqlScoutServer.create(this, getPackageName());
|
SqlScoutServer.create(this, getPackageName());
|
||||||
|
|
||||||
|
//Using Bitshares Agorise Testnet
|
||||||
|
CryptoNetManager.addCryptoNetURL(CryptoNet.BITSHARES,BITSHARES_TESTNET_URL);
|
||||||
|
|
||||||
|
//This is for testing the equivalent values on the testnet TODO remove
|
||||||
|
if(db.bitsharesAssetDao().getBitsharesAssetInfoById(bitEURAsset.getBitsharesId())== null){
|
||||||
|
if(db.cryptoCurrencyDao().getByName(bitEURAsset.getName())== null){
|
||||||
|
db.cryptoCurrencyDao().insertCryptoCurrency(bitEURAsset);
|
||||||
|
}
|
||||||
|
long idCurrency = db.cryptoCurrencyDao().getByName(bitEURAsset.getName()).getId();
|
||||||
|
BitsharesAssetInfo info = new BitsharesAssetInfo(bitEURAsset);
|
||||||
|
info.setCryptoCurrencyId(idCurrency);
|
||||||
|
db.bitsharesAssetDao().insertBitsharesAssetInfo(info);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//This is for testing the equivalent values on the testnet TODO remove
|
||||||
|
if(db.bitsharesAssetDao().getBitsharesAssetInfoById(bitUSDAsset.getBitsharesId())== null){
|
||||||
|
if(db.cryptoCurrencyDao().getByName(bitUSDAsset.getName())== null){
|
||||||
|
db.cryptoCurrencyDao().insertCryptoCurrency(bitUSDAsset);
|
||||||
|
}
|
||||||
|
long idCurrency = db.cryptoCurrencyDao().getByName(bitUSDAsset.getName()).getId();
|
||||||
|
BitsharesAssetInfo info = new BitsharesAssetInfo(bitUSDAsset);
|
||||||
|
info.setCryptoCurrencyId(idCurrency);
|
||||||
|
db.bitsharesAssetDao().insertBitsharesAssetInfo(info);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Next line is for use the bitshares main net
|
||||||
|
//CryptoNetManager.addCryptoNetURL(CryptoNet.BITSHARES,BITSHARES_URL);
|
||||||
|
|
||||||
Intent intent = new Intent(getApplicationContext(), CrystalWalletService.class);
|
Intent intent = new Intent(getApplicationContext(), CrystalWalletService.class);
|
||||||
startService(intent);
|
startService(intent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package cy.agorise.crystalwallet.application;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.activities.PinRequestActivity;
|
||||||
|
import cy.agorise.crystalwallet.models.GeneralSetting;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 27/1/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CrystalSecurityMonitor implements Application.ActivityLifecycleCallbacks {
|
||||||
|
private int numStarted = 0;
|
||||||
|
private String passwordEncrypted;
|
||||||
|
|
||||||
|
public CrystalSecurityMonitor(final FragmentActivity fragmentActivity){
|
||||||
|
GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of(fragmentActivity).get(GeneralSettingListViewModel.class);
|
||||||
|
LiveData<List<GeneralSetting>> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList();
|
||||||
|
|
||||||
|
generalSettingsLiveData.observe(fragmentActivity, new Observer<List<GeneralSetting>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable List<GeneralSetting> generalSettings) {
|
||||||
|
boolean founded = false;
|
||||||
|
passwordEncrypted = "";
|
||||||
|
|
||||||
|
if (generalSettings != null){
|
||||||
|
for (GeneralSetting generalSetting:generalSettings) {
|
||||||
|
if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){
|
||||||
|
founded = true;
|
||||||
|
if (!generalSetting.getValue().isEmpty()){
|
||||||
|
passwordEncrypted = generalSetting.getValue();
|
||||||
|
callPasswordRequest(fragmentActivity);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityStarted(Activity activity) {
|
||||||
|
if (numStarted == 0) {
|
||||||
|
if ((this.passwordEncrypted != null) && (!this.passwordEncrypted.equals(""))) {
|
||||||
|
callPasswordRequest(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numStarted++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityStopped(Activity activity) {
|
||||||
|
numStarted--;
|
||||||
|
if (numStarted == 0) {
|
||||||
|
if ((this.passwordEncrypted != null) && (!this.passwordEncrypted.equals(""))) {
|
||||||
|
callPasswordRequest(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callPasswordRequest(Activity activity){
|
||||||
|
if ((!activity.getIntent().hasExtra("ACTIVITY_TYPE")) || (!activity.getIntent().getStringExtra("ACTIVITY_TYPE").equals("PASSWORD_REQUEST"))) {
|
||||||
|
Intent intent = new Intent(activity, PinRequestActivity.class);
|
||||||
|
intent.putExtra("ACTIVITY_TYPE", "PASSWORD_REQUEST");
|
||||||
|
activity.startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Activity activity, Bundle bundle) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResumed(Activity activity) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityPaused(Activity activity) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityDestroyed(Activity activity) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -3,13 +3,16 @@ 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;
|
||||||
|
import android.arch.persistence.room.Update;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,6 +27,33 @@ 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, email 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);
|
||||||
|
|
||||||
|
@Query("SELECT count(*) FROM contact WHERE name = :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)
|
||||||
|
public long[] add(Contact... contacts);
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||||
|
public void addAddresses(ContactAddress... contactAddresses);
|
||||||
|
|
||||||
|
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
public void updateAddresses(ContactAddress... contactAddresses);
|
||||||
|
|
||||||
|
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
public void updateAddressesFields(ContactAddress... contactAddresses);
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
public void deleteContacts(Contact... contacts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cy.agorise.crystalwallet.dao;
|
package cy.agorise.crystalwallet.dao;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
import android.arch.persistence.room.Dao;
|
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;
|
||||||
|
@ -28,6 +29,9 @@ public interface CryptoCurrencyDao {
|
||||||
@Query("SELECT * FROM crypto_currency WHERE id IN (:ids)")
|
@Query("SELECT * FROM crypto_currency WHERE id IN (:ids)")
|
||||||
List<CryptoCurrency> getByIds(List<Long> ids);
|
List<CryptoCurrency> getByIds(List<Long> ids);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM crypto_currency WHERE name = :name")
|
||||||
|
LiveData<CryptoCurrency> getLiveDataByName(String name);
|
||||||
|
|
||||||
@Query("SELECT * FROM crypto_currency WHERE name = :name")
|
@Query("SELECT * FROM crypto_currency WHERE name = :name")
|
||||||
CryptoCurrency getByName(String name);
|
CryptoCurrency getByName(String name);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -7,6 +7,7 @@ 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 java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||||
|
@ -32,6 +33,9 @@ public interface TransactionDao {
|
||||||
@Query("SELECT * FROM crypto_coin_transaction WHERE id = :id")
|
@Query("SELECT * FROM crypto_coin_transaction WHERE id = :id")
|
||||||
LiveData<CryptoCoinTransaction> getById(long id);
|
LiveData<CryptoCoinTransaction> getById(long id);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM crypto_coin_transaction WHERE date = :date and 'from' = :from and 'to' = :to and amount = :amount ")
|
||||||
|
CryptoCoinTransaction getByTransaction(Date date, String from, String to, long amount);
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
public long[] insertTransaction(CryptoCoinTransaction... transactions);
|
public long[] insertTransaction(CryptoCoinTransaction... transactions);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,28 @@
|
||||||
package cy.agorise.crystalwallet.fragments;
|
package cy.agorise.crystalwallet.fragments;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
|
import android.arch.paging.PagedList;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
import cy.agorise.crystalwallet.R;
|
import cy.agorise.crystalwallet.R;
|
||||||
|
import cy.agorise.crystalwallet.models.Contact;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
|
||||||
|
import cy.agorise.crystalwallet.views.ContactListView;
|
||||||
|
|
||||||
public class ContactsFragment extends Fragment {
|
public class ContactsFragment extends Fragment {
|
||||||
|
|
||||||
|
@BindView(R.id.vContactListView)
|
||||||
|
ContactListView contactListView;
|
||||||
|
|
||||||
public ContactsFragment() {
|
public ContactsFragment() {
|
||||||
// Required empty public constructor
|
// Required empty public constructor
|
||||||
}
|
}
|
||||||
|
@ -29,6 +43,20 @@ public class ContactsFragment extends Fragment {
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
return inflater.inflate(R.layout.fragment_contacts, container, false);
|
View v = inflater.inflate(R.layout.fragment_contacts, container, false);
|
||||||
|
ButterKnife.bind(this, v);
|
||||||
|
|
||||||
|
ContactListViewModel contactListViewModel = ViewModelProviders.of(this).get(ContactListViewModel.class);
|
||||||
|
contactListViewModel.init();
|
||||||
|
LiveData<PagedList<Contact>> contactsLiveData = contactListViewModel.getContactList();
|
||||||
|
|
||||||
|
contactsLiveData.observe(this, new Observer<PagedList<Contact>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable PagedList<Contact> contacts) {
|
||||||
|
contactListView.setData(contacts);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,44 @@
|
||||||
package cy.agorise.crystalwallet.fragments;
|
package cy.agorise.crystalwallet.fragments;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Currency;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnItemSelected;
|
||||||
import cy.agorise.crystalwallet.R;
|
import cy.agorise.crystalwallet.R;
|
||||||
|
import cy.agorise.crystalwallet.models.GeneralSetting;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by xd on 12/28/17.
|
* Created by xd on 12/28/17.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class GeneralSettingsFragment extends Fragment {
|
public class GeneralSettingsFragment extends Fragment {
|
||||||
|
|
||||||
|
private HashMap<String,String> countriesMap;
|
||||||
|
private GeneralSettingListViewModel generalSettingListViewModel;
|
||||||
|
private LiveData<List<GeneralSetting>> generalSettingListLiveData;
|
||||||
|
|
||||||
|
@BindView (R.id.spTaxableCountry)
|
||||||
|
Spinner spTaxableCountry;
|
||||||
|
|
||||||
public GeneralSettingsFragment() {
|
public GeneralSettingsFragment() {
|
||||||
// Required empty public constructor
|
// Required empty public constructor
|
||||||
}
|
}
|
||||||
|
@ -37,6 +62,83 @@ public class GeneralSettingsFragment extends Fragment {
|
||||||
View v = inflater.inflate(R.layout.fragment_general_settings, container, false);
|
View v = inflater.inflate(R.layout.fragment_general_settings, container, false);
|
||||||
ButterKnife.bind(this, v);
|
ButterKnife.bind(this, v);
|
||||||
|
|
||||||
|
generalSettingListViewModel = ViewModelProviders.of(this).get(GeneralSettingListViewModel.class);
|
||||||
|
generalSettingListLiveData = generalSettingListViewModel.getGeneralSettingList();
|
||||||
|
|
||||||
|
// Initializes the countries spinner
|
||||||
|
countriesMap = new HashMap<String, String>();
|
||||||
|
String[] countryCodeList = Locale.getISOCountries();
|
||||||
|
ArrayList<String> countryAndCurrencyList = new ArrayList<String>();
|
||||||
|
String countryAndCurrencyLabel = "";
|
||||||
|
for (String countryCode : countryCodeList) {
|
||||||
|
Locale locale = new Locale("", countryCode);
|
||||||
|
try {
|
||||||
|
Currency currency = Currency.getInstance(locale);
|
||||||
|
countryAndCurrencyLabel = locale.getDisplayCountry() + " (" + currency.getCurrencyCode() + ")";
|
||||||
|
countryAndCurrencyList.add(countryAndCurrencyLabel);
|
||||||
|
countriesMap.put(countryCode, countryAndCurrencyLabel);
|
||||||
|
countriesMap.put(countryAndCurrencyLabel, countryCode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(countryAndCurrencyList);
|
||||||
|
countryAndCurrencyList.add(0,"SELECT COUNTRY");
|
||||||
|
ArrayAdapter<String> countryAdapter = new ArrayAdapter<String>(this.getContext(), android.R.layout.simple_spinner_item, countryAndCurrencyList);
|
||||||
|
spTaxableCountry.setAdapter(countryAdapter);
|
||||||
|
|
||||||
|
//Observes the general settings data
|
||||||
|
generalSettingListLiveData.observe(this, new Observer<List<GeneralSetting>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable List<GeneralSetting> generalSettings) {
|
||||||
|
loadSettings(generalSettings);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GeneralSetting getSetting(String name){
|
||||||
|
for (GeneralSetting generalSetting:this.generalSettingListLiveData.getValue()) {
|
||||||
|
if (generalSetting.getName().equals(name)) {
|
||||||
|
return generalSetting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnItemSelected(R.id.spTaxableCountry)
|
||||||
|
void onItemSelected(int position) {
|
||||||
|
if (position != 0) {
|
||||||
|
GeneralSetting generalSettingCountryCode = this.getSetting(GeneralSetting.SETTING_NAME_PREFERED_COUNTRY);
|
||||||
|
GeneralSetting generalSettingCurrency = this.getSetting(GeneralSetting.SETTING_NAME_PREFERED_CURRENCY);
|
||||||
|
|
||||||
|
if (generalSettingCountryCode == null){
|
||||||
|
generalSettingCountryCode = new GeneralSetting();
|
||||||
|
generalSettingCountryCode.setName(GeneralSetting.SETTING_NAME_PREFERED_COUNTRY);
|
||||||
|
}
|
||||||
|
if (generalSettingCurrency == null){
|
||||||
|
generalSettingCurrency = new GeneralSetting();
|
||||||
|
generalSettingCurrency.setName(GeneralSetting.SETTING_NAME_PREFERED_CURRENCY);
|
||||||
|
}
|
||||||
|
|
||||||
|
String countryCode = countriesMap.get((String) spTaxableCountry.getSelectedItem());
|
||||||
|
Locale locale = new Locale("", countryCode);
|
||||||
|
Currency currency = Currency.getInstance(locale);
|
||||||
|
|
||||||
|
generalSettingCountryCode.setValue(countryCode);
|
||||||
|
generalSettingCurrency.setValue(currency.getCurrencyCode());
|
||||||
|
this.generalSettingListViewModel.saveGeneralSettings(generalSettingCountryCode, generalSettingCurrency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadSettings(List<GeneralSetting> generalSettings){
|
||||||
|
for (GeneralSetting generalSetting:generalSettings) {
|
||||||
|
if (generalSetting.getName().equals(GeneralSetting.SETTING_NAME_PREFERED_COUNTRY)){
|
||||||
|
String preferedCountryCode = generalSetting.getValue();
|
||||||
|
spTaxableCountry.setSelection(((ArrayAdapter<String>)spTaxableCountry.getAdapter()).getPosition(countriesMap.get(preferedCountryCode)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,60 @@
|
||||||
package cy.agorise.crystalwallet.fragments;
|
package cy.agorise.crystalwallet.fragments;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.text.Editable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnTextChanged;
|
||||||
import cy.agorise.crystalwallet.R;
|
import cy.agorise.crystalwallet.R;
|
||||||
|
import cy.agorise.crystalwallet.activities.CreateSeedActivity;
|
||||||
|
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
||||||
|
import cy.agorise.crystalwallet.models.GeneralSetting;
|
||||||
|
import cy.agorise.crystalwallet.util.PasswordManager;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.PinSecurityValidator;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ValidationField;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by xd on 1/18/18.
|
* Created by xd on 1/18/18.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class PinSecurityFragment extends Fragment {
|
public class PinSecurityFragment extends Fragment implements UIValidatorListener {
|
||||||
|
|
||||||
|
@BindView(R.id.tvCurrentPin)
|
||||||
|
TextView tvCurrentPin;
|
||||||
|
@BindView(R.id.etCurrentPin)
|
||||||
|
EditText etCurrentPin;
|
||||||
|
@BindView(R.id.etNewPin)
|
||||||
|
EditText etNewPin;
|
||||||
|
@BindView(R.id.etConfirmPin)
|
||||||
|
EditText etConfirmPin;
|
||||||
|
|
||||||
|
@BindView(R.id.tvCurrentPinError)
|
||||||
|
TextView tvCurrentPinError;
|
||||||
|
@BindView(R.id.tvNewPinError)
|
||||||
|
TextView tvNewPinError;
|
||||||
|
@BindView(R.id.tvConfirmPinError)
|
||||||
|
TextView tvConfirmPinError;
|
||||||
|
|
||||||
|
GeneralSettingListViewModel generalSettingListViewModel;
|
||||||
|
GeneralSetting passwordGeneralSetting;
|
||||||
|
PinSecurityValidator pinSecurityValidator;
|
||||||
|
|
||||||
public PinSecurityFragment() {
|
public PinSecurityFragment() {
|
||||||
// Required empty public constructor
|
// Required empty public constructor
|
||||||
|
@ -33,6 +74,140 @@ public class PinSecurityFragment extends Fragment {
|
||||||
View v = inflater.inflate(R.layout.fragment_pin_security, container, false);
|
View v = inflater.inflate(R.layout.fragment_pin_security, container, false);
|
||||||
ButterKnife.bind(this, v);
|
ButterKnife.bind(this, v);
|
||||||
|
|
||||||
|
generalSettingListViewModel = ViewModelProviders.of(this).get(GeneralSettingListViewModel.class);
|
||||||
|
LiveData<List<GeneralSetting>> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList();
|
||||||
|
|
||||||
|
pinSecurityValidator = new PinSecurityValidator(this.getContext(), etCurrentPin, etNewPin, etConfirmPin);
|
||||||
|
pinSecurityValidator.setListener(this);
|
||||||
|
|
||||||
|
generalSettingsLiveData.observe(this, new Observer<List<GeneralSetting>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable List<GeneralSetting> generalSettings) {
|
||||||
|
boolean founded = false;
|
||||||
|
|
||||||
|
if (generalSettings != null){
|
||||||
|
for (GeneralSetting generalSetting:generalSettings) {
|
||||||
|
if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){
|
||||||
|
founded = true;
|
||||||
|
if (!generalSetting.getValue().isEmpty()){
|
||||||
|
passwordGeneralSetting = generalSetting;
|
||||||
|
showCurrentPinUI(true);
|
||||||
|
} else {
|
||||||
|
showCurrentPinUI(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!founded){
|
||||||
|
showCurrentPinUI(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showCurrentPinUI(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showCurrentPinUI(Boolean visible){
|
||||||
|
if (visible){
|
||||||
|
tvCurrentPin.setVisibility(View.VISIBLE);
|
||||||
|
etCurrentPin.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
tvCurrentPin.setVisibility(View.GONE);
|
||||||
|
etCurrentPin.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnTextChanged(value = R.id.etCurrentPin,
|
||||||
|
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
||||||
|
void afterCurrentPinChanged(Editable editable) {
|
||||||
|
this.pinSecurityValidator.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnTextChanged(value = R.id.etNewPin,
|
||||||
|
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
||||||
|
void afterNewPinChanged(Editable editable) {
|
||||||
|
this.pinSecurityValidator.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnTextChanged(value = R.id.etConfirmPin,
|
||||||
|
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
||||||
|
void afterConfirmPinChanged(Editable editable) {
|
||||||
|
this.pinSecurityValidator.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearFields(){
|
||||||
|
if (!this.etCurrentPin.getText().toString().equals("")) {
|
||||||
|
this.etCurrentPin.setText("");
|
||||||
|
}
|
||||||
|
if (!this.etNewPin.getText().toString().equals("")) {
|
||||||
|
this.etNewPin.setText("");
|
||||||
|
}
|
||||||
|
if (!this.etConfirmPin.getText().toString().equals("")) {
|
||||||
|
this.etConfirmPin.setText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValidationSucceeded(final ValidationField field) {
|
||||||
|
final PinSecurityFragment fragment = this;
|
||||||
|
|
||||||
|
this.getActivity().runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
if (field.getView() == etCurrentPin) {
|
||||||
|
tvCurrentPinError.setText("");
|
||||||
|
} else if (field.getView() == etNewPin){
|
||||||
|
tvNewPinError.setText("");
|
||||||
|
} else if (field.getView() == etConfirmPin){
|
||||||
|
tvConfirmPinError.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pinSecurityValidator.isValid()){
|
||||||
|
CharSequence text = "Your password has been sucessfully changed!";
|
||||||
|
int duration = Toast.LENGTH_SHORT;
|
||||||
|
|
||||||
|
Toast toast = Toast.makeText(getContext(), text, duration);
|
||||||
|
toast.show();
|
||||||
|
//showCurrentPinUI(true);
|
||||||
|
|
||||||
|
savePassword(etNewPin.getText().toString());
|
||||||
|
|
||||||
|
|
||||||
|
clearFields();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void savePassword(String password) {
|
||||||
|
String passwordEncripted = PasswordManager.encriptPassword(password);
|
||||||
|
|
||||||
|
if (passwordGeneralSetting == null) {
|
||||||
|
passwordGeneralSetting = new GeneralSetting();
|
||||||
|
passwordGeneralSetting.setName(GeneralSetting.SETTING_PASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordGeneralSetting.setValue(passwordEncripted);
|
||||||
|
generalSettingListViewModel.saveGeneralSetting(passwordGeneralSetting);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValidationFailed(final ValidationField field) {
|
||||||
|
this.getActivity().runOnUiThread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (field.getView() == etCurrentPin) {
|
||||||
|
tvCurrentPinError.setText(field.getMessage());
|
||||||
|
} else if (field.getView() == etNewPin){
|
||||||
|
tvNewPinError.setText(field.getMessage());
|
||||||
|
} else if (field.getView() == etConfirmPin){
|
||||||
|
tvConfirmPinError.setText(field.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.app.Dialog;
|
||||||
import android.app.LauncherActivity;
|
import android.app.LauncherActivity;
|
||||||
import android.arch.lifecycle.LiveData;
|
import android.arch.lifecycle.LiveData;
|
||||||
import android.arch.lifecycle.Observer;
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -31,6 +32,8 @@ import com.google.zxing.WriterException;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
|
||||||
import butterknife.OnClick;
|
import butterknife.OnClick;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountListViewModel;
|
||||||
|
import cy.agorise.crystalwallet.views.CryptoNetAccountAdapter;
|
||||||
import cy.agorise.graphenej.Invoice;
|
import cy.agorise.graphenej.Invoice;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -57,6 +60,8 @@ public class ReceiveTransactionFragment extends DialogFragment implements UIVali
|
||||||
|
|
||||||
ReceiveTransactionValidator receiveTransactionValidator;
|
ReceiveTransactionValidator receiveTransactionValidator;
|
||||||
|
|
||||||
|
@BindView(R.id.spTo)
|
||||||
|
Spinner spTo;
|
||||||
@BindView(R.id.etAmount)
|
@BindView(R.id.etAmount)
|
||||||
EditText etAmount;
|
EditText etAmount;
|
||||||
@BindView(R.id.tvAmountError)
|
@BindView(R.id.tvAmountError)
|
||||||
|
@ -145,6 +150,12 @@ public class ReceiveTransactionFragment extends DialogFragment implements UIVali
|
||||||
|
|
||||||
receiveTransactionValidator = new ReceiveTransactionValidator(this.getContext(), this.cryptoNetAccount, spAsset, etAmount);
|
receiveTransactionValidator = new ReceiveTransactionValidator(this.getContext(), this.cryptoNetAccount, spAsset, etAmount);
|
||||||
receiveTransactionValidator.setListener(this);
|
receiveTransactionValidator.setListener(this);
|
||||||
|
|
||||||
|
CryptoNetAccountListViewModel cryptoNetAccountListViewModel = ViewModelProviders.of(this).get(CryptoNetAccountListViewModel.class);
|
||||||
|
List<CryptoNetAccount> cryptoNetAccounts = cryptoNetAccountListViewModel.getCryptoNetAccountList();
|
||||||
|
CryptoNetAccountAdapter toSpinnerAdapter = new CryptoNetAccountAdapter(this.getContext(), android.R.layout.simple_spinner_item, cryptoNetAccounts);
|
||||||
|
spTo.setAdapter(toSpinnerAdapter);
|
||||||
|
spTo.setSelection(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setView(view);
|
builder.setView(view);
|
||||||
|
@ -199,6 +210,11 @@ public class ReceiveTransactionFragment extends DialogFragment implements UIVali
|
||||||
}, 400);
|
}, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnItemSelected(R.id.spTo)
|
||||||
|
public void afterToSelected(Spinner spinner, int position) {
|
||||||
|
this.receiveTransactionValidator.validate();
|
||||||
|
}
|
||||||
|
|
||||||
@OnTextChanged(value = R.id.etAmount,
|
@OnTextChanged(value = R.id.etAmount,
|
||||||
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
||||||
void afterAmountChanged(Editable editable) {
|
void afterAmountChanged(Editable editable) {
|
||||||
|
|
|
@ -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,13 +25,19 @@ 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;
|
||||||
|
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
@ -41,10 +49,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;
|
||||||
|
@ -52,6 +63,8 @@ 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.CryptoCurrencyAdapter;
|
import cy.agorise.crystalwallet.views.CryptoCurrencyAdapter;
|
||||||
import cy.agorise.crystalwallet.views.CryptoNetAccountAdapter;
|
import cy.agorise.crystalwallet.views.CryptoNetAccountAdapter;
|
||||||
|
import cy.agorise.graphenej.Invoice;
|
||||||
|
import cy.agorise.graphenej.LineItem;
|
||||||
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||||
|
|
||||||
public class SendTransactionFragment extends DialogFragment implements UIValidatorListener, ZXingScannerView.ResultHandler {
|
public class SendTransactionFragment extends DialogFragment implements UIValidatorListener, ZXingScannerView.ResultHandler {
|
||||||
|
@ -82,6 +95,9 @@ 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;
|
||||||
|
CryptoCurrencyAdapter assetAdapter;
|
||||||
|
|
||||||
Button btnScanQrCode;
|
Button btnScanQrCode;
|
||||||
|
|
||||||
|
@ -145,7 +161,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
|
||||||
}
|
}
|
||||||
List<CryptoCurrency> cryptoCurrencyList = db.cryptoCurrencyDao().getByIds(assetIds);
|
List<CryptoCurrency> cryptoCurrencyList = db.cryptoCurrencyDao().getByIds(assetIds);
|
||||||
|
|
||||||
CryptoCurrencyAdapter assetAdapter = new CryptoCurrencyAdapter(getContext(), android.R.layout.simple_spinner_item, cryptoCurrencyList);
|
assetAdapter = new CryptoCurrencyAdapter(getContext(), android.R.layout.simple_spinner_item, cryptoCurrencyList);
|
||||||
spAsset.setAdapter(assetAdapter);
|
spAsset.setAdapter(assetAdapter);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -222,6 +238,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();
|
||||||
|
@ -317,6 +377,27 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResult(Result result) {
|
public void handleResult(Result result) {
|
||||||
|
Invoice invoice = Invoice.fromQrCode(result.getText());
|
||||||
|
|
||||||
|
etTo.setText(invoice.getTo());
|
||||||
|
|
||||||
|
for (int i=0;i<assetAdapter.getCount();i++) {
|
||||||
|
if (assetAdapter.getItem(i).getName().equals(invoice.getCurrency())) {
|
||||||
|
spAsset.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
etMemo.setText(invoice.getMemo());
|
||||||
|
|
||||||
|
|
||||||
|
double amount = 0.0;
|
||||||
|
for (LineItem nextItem : invoice.getLineItems()) {
|
||||||
|
amount += nextItem.getQuantity() * nextItem.getPrice();
|
||||||
|
}
|
||||||
|
DecimalFormat df = new DecimalFormat("####.####");
|
||||||
|
df.setRoundingMode(RoundingMode.CEILING);
|
||||||
|
df.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.ENGLISH));
|
||||||
|
etAmount.setText(df.format(amount));
|
||||||
Log.i("SendFragment",result.getText());
|
Log.i("SendFragment",result.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cy.agorise.crystalwallet.manager;
|
package cy.agorise.crystalwallet.manager;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.google.common.primitives.UnsignedLong;
|
import com.google.common.primitives.UnsignedLong;
|
||||||
|
@ -31,9 +32,11 @@ import cy.agorise.crystalwallet.models.AccountSeed;
|
||||||
import cy.agorise.crystalwallet.models.BitsharesAsset;
|
import cy.agorise.crystalwallet.models.BitsharesAsset;
|
||||||
import cy.agorise.crystalwallet.models.BitsharesAssetInfo;
|
import cy.agorise.crystalwallet.models.BitsharesAssetInfo;
|
||||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||||
|
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.models.GrapheneAccountInfo;
|
import cy.agorise.crystalwallet.models.GrapheneAccountInfo;
|
||||||
|
import cy.agorise.crystalwallet.network.CryptoNetManager;
|
||||||
import cy.agorise.graphenej.Address;
|
import cy.agorise.graphenej.Address;
|
||||||
import cy.agorise.graphenej.Asset;
|
import cy.agorise.graphenej.Asset;
|
||||||
import cy.agorise.graphenej.AssetAmount;
|
import cy.agorise.graphenej.AssetAmount;
|
||||||
|
@ -54,106 +57,157 @@ import cy.agorise.graphenej.operations.TransferOperationBuilder;
|
||||||
*/
|
*/
|
||||||
public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener {
|
public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener {
|
||||||
|
|
||||||
private final static String BITSHARES_TESTNET_CHAIN_ID= "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8";
|
//private final static String BITSHARES_TESTNET_CHAIN_ID= "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8";
|
||||||
|
|
||||||
|
private final static String SIMPLE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
|
||||||
|
private final static String DEFAULT_TIME_ZONE = "GMT";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CryptoNetAccount createAccountFromSeed(CryptoNetAccount account, Context context) {
|
public void createAccountFromSeed(CryptoNetAccount account, final ManagerRequest request, final Context context) {
|
||||||
if(account instanceof GrapheneAccount) {
|
if(account instanceof GrapheneAccount) {
|
||||||
|
|
||||||
GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
final GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||||
boolean created = BitsharesFaucetApiGenerator.registerBitsharesAccount(grapheneAccount.getName(),
|
ApiRequest creationRequest = new ApiRequest(1, new ApiRequestListener() {
|
||||||
|
@Override
|
||||||
|
public void success(Object answer, int idPetition) {
|
||||||
|
getAccountInfoByName(grapheneAccount.getName(), new ManagerRequest() {
|
||||||
|
@Override
|
||||||
|
public void success(Object answer) {
|
||||||
|
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||||
|
fetch.setSeedId(grapheneAccount.getSeedId());
|
||||||
|
fetch.setCryptoNet(grapheneAccount.getCryptoNet());
|
||||||
|
fetch.setAccountIndex(grapheneAccount.getAccountIndex());
|
||||||
|
|
||||||
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||||
|
long idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(fetch)[0];
|
||||||
|
fetch.setId(idAccount);
|
||||||
|
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(fetch));
|
||||||
|
subscribeBitsharesAccount(fetch.getId(),fetch.getAccountId(),context);
|
||||||
|
request.success(fetch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail() {
|
||||||
|
//TODO get account data fail
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail(int idPetition) {
|
||||||
|
request.fail();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
BitsharesFaucetApiGenerator.registerBitsharesAccount(grapheneAccount.getName(),
|
||||||
new Address(ECKey.fromPublicOnly(grapheneAccount.getOwnerKey(context).getPubKey())).toString(),
|
new Address(ECKey.fromPublicOnly(grapheneAccount.getOwnerKey(context).getPubKey())).toString(),
|
||||||
new Address(ECKey.fromPublicOnly(grapheneAccount.getActiveKey(context).getPubKey())).toString(),
|
new Address(ECKey.fromPublicOnly(grapheneAccount.getActiveKey(context).getPubKey())).toString(),
|
||||||
new Address(ECKey.fromPublicOnly(grapheneAccount.getMemoKey(context).getPubKey())).toString(),GrapheneApiGenerator.faucetUrl);
|
new Address(ECKey.fromPublicOnly(grapheneAccount.getMemoKey(context).getPubKey())).toString(),
|
||||||
|
GrapheneApiGenerator.faucetUrl, creationRequest);
|
||||||
if(created) {
|
|
||||||
GrapheneAccount fetch = this.getAccountInfoByName(grapheneAccount.getName());
|
|
||||||
fetch.setSeedId(grapheneAccount.getSeedId());
|
|
||||||
fetch.setCryptoNet(grapheneAccount.getCryptoNet());
|
|
||||||
fetch.setAccountIndex(grapheneAccount.getAccountIndex());
|
|
||||||
|
|
||||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
|
||||||
long idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(fetch)[0];
|
|
||||||
fetch.setId(idAccount);
|
|
||||||
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(fetch));
|
|
||||||
|
|
||||||
GrapheneApiGenerator.subscribeBitsharesAccount(fetch.getId(), fetch.getAccountId(), context);
|
|
||||||
BitsharesAccountManager.refreshAccountTransactions(fetch.getId(), context);
|
|
||||||
GrapheneApiGenerator.getAccountBalance(fetch.getId(), fetch.getAccountId(), context);
|
|
||||||
return fetch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CryptoNetAccount importAccountFromSeed(CryptoNetAccount account, Context context) {
|
public void importAccountFromSeed(CryptoNetAccount account, final Context context) {
|
||||||
|
|
||||||
if(account instanceof GrapheneAccount) {
|
if(account instanceof GrapheneAccount) {
|
||||||
GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
final GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||||
|
|
||||||
if(grapheneAccount.getAccountId() == null){
|
if(grapheneAccount.getAccountId() == null){
|
||||||
GrapheneAccount fetch = this.getAccountInfoByName(grapheneAccount.getName());
|
this.getAccountInfoByName(grapheneAccount.getName(), new ManagerRequest() {
|
||||||
if(fetch == null) {
|
@Override
|
||||||
//TODO grapaheneAccount null, error fetching
|
public void success(Object answer) {
|
||||||
return null;
|
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||||
}
|
grapheneAccount.setAccountId(fetch.getAccountId());
|
||||||
grapheneAccount.setAccountId(fetch.getAccountId());
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||||
|
db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount);
|
||||||
|
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount));
|
||||||
|
subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail() {
|
||||||
|
//TODO get account data fail
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}else if(grapheneAccount.getName() == null){
|
}else if(grapheneAccount.getName() == null){
|
||||||
GrapheneAccount fetch = this.getAccountInfoById(grapheneAccount.getAccountId());
|
this.getAccountInfoById(grapheneAccount.getAccountId(), new ManagerRequest() {
|
||||||
if(fetch == null) {
|
@Override
|
||||||
//TODO grapaheneAccount null, error fetching
|
public void success(Object answer) {
|
||||||
return null;
|
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||||
}
|
grapheneAccount.setName(fetch.getName());
|
||||||
grapheneAccount.setName(fetch.getName());
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||||
|
db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount);
|
||||||
|
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount));
|
||||||
|
subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail() {
|
||||||
|
//TODO get account data fail
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else {
|
||||||
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||||
|
db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount);
|
||||||
|
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount));
|
||||||
|
subscribeBitsharesAccount(grapheneAccount.getId(), grapheneAccount.getAccountId(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
|
||||||
db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount);
|
|
||||||
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount));
|
|
||||||
|
|
||||||
GrapheneApiGenerator.subscribeBitsharesAccount(grapheneAccount.getId(), grapheneAccount.getAccountId(), context);
|
|
||||||
BitsharesAccountManager.refreshAccountTransactions(account.getId(), context);
|
|
||||||
GrapheneApiGenerator.getAccountBalance(grapheneAccount.getId(), grapheneAccount.getAccountId(), context);
|
|
||||||
return grapheneAccount;
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadAccountFromDB(CryptoNetAccount account, Context context) {
|
public void loadAccountFromDB(CryptoNetAccount account, final Context context) {
|
||||||
if(account instanceof GrapheneAccount){
|
if(account instanceof GrapheneAccount){
|
||||||
GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
final GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
final CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||||
GrapheneAccountInfo info = db.grapheneAccountInfoDao().getByAccountId(account.getId());
|
final GrapheneAccountInfo info = db.grapheneAccountInfoDao().getByAccountId(account.getId());
|
||||||
grapheneAccount.loadInfo(info);
|
grapheneAccount.loadInfo(info);
|
||||||
if(grapheneAccount.getAccountId() == null){
|
if(grapheneAccount.getAccountId() == null){
|
||||||
GrapheneAccount fetch = this.getAccountInfoByName(grapheneAccount.getName());
|
this.getAccountInfoByName(grapheneAccount.getName(), new ManagerRequest() {
|
||||||
if(fetch != null){
|
@Override
|
||||||
info.setAccountId(fetch.getAccountId());
|
public void success(Object answer) {
|
||||||
grapheneAccount.setAccountId(fetch.getAccountId());
|
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||||
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(info);
|
info.setAccountId(fetch.getAccountId());
|
||||||
}
|
grapheneAccount.setAccountId(fetch.getAccountId());
|
||||||
|
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(info);
|
||||||
|
subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail() {
|
||||||
|
//TODO account data retrieve failed
|
||||||
|
}
|
||||||
|
});
|
||||||
}else if(grapheneAccount.getName() == null){
|
}else if(grapheneAccount.getName() == null){
|
||||||
GrapheneAccount fetch = this.getAccountInfoById(grapheneAccount.getAccountId());
|
this.getAccountInfoById(grapheneAccount.getAccountId(), new ManagerRequest() {
|
||||||
if(fetch != null) {
|
@Override
|
||||||
info.setName(fetch.getName());
|
public void success(Object answer) {
|
||||||
grapheneAccount.setName(fetch.getName());
|
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||||
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(info);
|
info.setName(fetch.getName());
|
||||||
}
|
grapheneAccount.setName(fetch.getName());
|
||||||
}
|
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(info);
|
||||||
|
subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
||||||
|
}
|
||||||
|
|
||||||
if(grapheneAccount.getName() == null || grapheneAccount.getAccountId() == null) {
|
@Override
|
||||||
//TODO grapaheneAccount null, error fetching
|
public void fail() {
|
||||||
return;
|
//TODO account data retrieve failed
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrapheneApiGenerator.subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
|
||||||
BitsharesAccountManager.refreshAccountTransactions(account.getId(),context);
|
|
||||||
GrapheneApiGenerator.getAccountBalance(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void subscribeBitsharesAccount(long accountId, String accountBitsharesID, Context context){
|
||||||
|
GrapheneApiGenerator.subscribeBitsharesAccount(accountId,accountBitsharesID,context);
|
||||||
|
BitsharesAccountManager.refreshAccountTransactions(accountId,context);
|
||||||
|
GrapheneApiGenerator.getAccountBalance(accountId,accountBitsharesID,context);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the bitshares manager request
|
* Process the bitshares manager request
|
||||||
* @param request The request Object
|
* @param request The request Object
|
||||||
|
@ -172,6 +226,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
this.validateCreateAccount((ValidateCreateBitsharesAccountRequest) request);
|
this.validateCreateAccount((ValidateCreateBitsharesAccountRequest) request);
|
||||||
}else{
|
}else{
|
||||||
//TODO not implemented
|
//TODO not implemented
|
||||||
|
System.out.println("Error request not implemented " + request.getClass().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +244,6 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
if(answer != null && answer instanceof AccountProperties) {
|
if(answer != null && answer instanceof AccountProperties) {
|
||||||
AccountProperties prop = (AccountProperties) answer;
|
AccountProperties prop = (AccountProperties) answer;
|
||||||
//TODO change the way to compare keys
|
//TODO change the way to compare keys
|
||||||
|
|
||||||
BrainKey bk = new BrainKey(importRequest.getMnemonic(), 0);
|
BrainKey bk = new BrainKey(importRequest.getMnemonic(), 0);
|
||||||
System.out.println(bk.getPublicAddress("BTS").toString());
|
System.out.println(bk.getPublicAddress("BTS").toString());
|
||||||
for(PublicKey activeKey : prop.owner.getKeyAuthList()){
|
for(PublicKey activeKey : prop.owner.getKeyAuthList()){
|
||||||
|
@ -220,25 +274,34 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
GrapheneApiGenerator.getAccountIdByName(importRequest.getAccountName(),checkAccountName);
|
GrapheneApiGenerator.getAccountIdByName(importRequest.getAccountName(),checkAccountName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateCreateAccount(ValidateCreateBitsharesAccountRequest createRequest){
|
private void validateCreateAccount(final ValidateCreateBitsharesAccountRequest createRequest){
|
||||||
// Generate seed or find key
|
// Generate seed or find key
|
||||||
Context context = createRequest.getContext();
|
Context context = createRequest.getContext();
|
||||||
AccountSeed seed = AccountSeed.getAccountSeed(SeedType.BIP39, context);
|
AccountSeed seed = AccountSeed.getAccountSeed(SeedType.BIP39, context);
|
||||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||||
long idSeed = db.accountSeedDao().insertAccountSeed(seed);
|
long idSeed = db.accountSeedDao().insertAccountSeed(seed);
|
||||||
|
assert seed != null;
|
||||||
seed.setId(idSeed);
|
seed.setId(idSeed);
|
||||||
seed.setName(createRequest.getAccountName());
|
seed.setName(createRequest.getAccountName());
|
||||||
GrapheneAccount account = new GrapheneAccount();
|
GrapheneAccount account = new GrapheneAccount();
|
||||||
account.setName(createRequest.getAccountName());
|
account.setName(createRequest.getAccountName());
|
||||||
account.setSeedId(idSeed);
|
account.setSeedId(idSeed);
|
||||||
account.setAccountIndex(0);
|
account.setAccountIndex(0);
|
||||||
account.setCryptoNet(CryptoNet.BITSHARES);
|
account.setCryptoNet(CryptoNet.BITSHARES);
|
||||||
GrapheneAccount answer =(GrapheneAccount) this.createAccountFromSeed(account,context);
|
this.createAccountFromSeed(account, new ManagerRequest() {
|
||||||
if (answer != null){
|
|
||||||
createRequest.setAccountExists(false);
|
@Override
|
||||||
createRequest.setAccount(answer);;
|
public void success(Object answer) {
|
||||||
}
|
createRequest.setAccountExists(false);
|
||||||
createRequest.setAccountExists(false);
|
createRequest.setAccount((GrapheneAccount) answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail() {
|
||||||
|
createRequest.setAccountExists(true);
|
||||||
|
}
|
||||||
|
}, context);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,121 +333,127 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
/**
|
/**
|
||||||
* Broadcast a transaction request
|
* Broadcast a transaction request
|
||||||
*/
|
*/
|
||||||
private void validateSendRequest(final ValidateBitsharesSendRequest sendRequest){
|
private void validateSendRequest(final ValidateBitsharesSendRequest sendRequest) {
|
||||||
//TODO feeAsset
|
//TODO feeAsset
|
||||||
String idAsset = getAssetInfoByName(sendRequest.getAsset());
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(sendRequest.getContext());
|
||||||
Asset feeAsset = new Asset(idAsset);
|
CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(sendRequest.getAsset(), CryptoNet.BITSHARES.name());
|
||||||
UserAccount fromUserAccount =new UserAccount(sendRequest.getSourceAccount().getAccountId());
|
if (currency == null){
|
||||||
|
getAssetInfoByName(sendRequest.getAsset(), new ManagerRequest() {
|
||||||
|
@Override
|
||||||
|
public void success(Object answer) {
|
||||||
|
validateSendRequest(sendRequest, ((BitsharesAsset) answer).getBitsharesId());
|
||||||
|
}
|
||||||
|
|
||||||
GrapheneAccount toUserGrapheneAccount = this.getAccountInfoByName(sendRequest.getToAccount());
|
@Override
|
||||||
//TODO bad user to user account
|
public void fail() {
|
||||||
UserAccount toUserAccount = new UserAccount(toUserGrapheneAccount.getAccountId());
|
|
||||||
TransferOperationBuilder builder = new TransferOperationBuilder()
|
}
|
||||||
.setSource(fromUserAccount)
|
});
|
||||||
.setDestination(toUserAccount)
|
}else{
|
||||||
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(sendRequest.getAmount()), new Asset(idAsset)))
|
BitsharesAssetInfo info = db.bitsharesAssetDao().getBitsharesAssetInfo(currency.getId());
|
||||||
.setFee(new AssetAmount(UnsignedLong.valueOf(0), feeAsset));
|
if (info == null || info.getBitsharesId() == null || info.getBitsharesId().isEmpty()){
|
||||||
if(sendRequest.getMemo() != null) {
|
getAssetInfoByName(sendRequest.getAsset(), new ManagerRequest() {
|
||||||
//builder.setMemo(new Memo(fromUserAccount,toUserAccount,0,sendRequest.getMemo().getBytes()));
|
@Override
|
||||||
//TODO memo
|
public void success(Object answer) {
|
||||||
|
validateSendRequest(sendRequest, ((BitsharesAsset) answer).getBitsharesId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail() {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else {
|
||||||
|
this.validateSendRequest(sendRequest, info.getBitsharesId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
}
|
||||||
operationList.add(builder.build());
|
|
||||||
|
|
||||||
ECKey privateKey = sendRequest.getSourceAccount().getActiveKey(sendRequest.getContext());
|
private void validateSendRequest(final ValidateBitsharesSendRequest sendRequest , final String idAsset){
|
||||||
|
final Asset feeAsset = new Asset(idAsset);
|
||||||
|
final UserAccount fromUserAccount =new UserAccount(sendRequest.getSourceAccount().getAccountId());
|
||||||
|
|
||||||
Transaction transaction = new Transaction(privateKey, null, operationList);
|
//TODO cached to accounts
|
||||||
transaction.setChainId(BITSHARES_TESTNET_CHAIN_ID);
|
this.getAccountInfoByName(sendRequest.getToAccount(), new ManagerRequest() {
|
||||||
|
|
||||||
ApiRequest transactionRequest = new ApiRequest(0, new ApiRequestListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void success(Object answer, int idPetition) {
|
public void success(Object answer) {
|
||||||
sendRequest.setSend(true);
|
GrapheneAccount toUserGrapheneAccount = (GrapheneAccount) answer;
|
||||||
|
UserAccount toUserAccount = new UserAccount(toUserGrapheneAccount.getAccountId());
|
||||||
|
TransferOperationBuilder builder = new TransferOperationBuilder()
|
||||||
|
.setSource(fromUserAccount)
|
||||||
|
.setDestination(toUserAccount)
|
||||||
|
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(sendRequest.getAmount()), new Asset(idAsset)))
|
||||||
|
.setFee(new AssetAmount(UnsignedLong.valueOf(0), feeAsset));
|
||||||
|
if(sendRequest.getMemo() != null) {
|
||||||
|
//builder.setMemo(new Memo(fromUserAccount,toUserAccount,0,sendRequest.getMemo().getBytes()));
|
||||||
|
//TODO memo
|
||||||
|
System.out.println("transaction has memo");
|
||||||
|
}
|
||||||
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
||||||
|
operationList.add(builder.build());
|
||||||
|
|
||||||
|
ECKey privateKey = sendRequest.getSourceAccount().getActiveKey(sendRequest.getContext());
|
||||||
|
|
||||||
|
Transaction transaction = new Transaction(privateKey, null, operationList);
|
||||||
|
transaction.setChainId(CryptoNetManager.getChaindId(CryptoNet.BITSHARES));
|
||||||
|
|
||||||
|
ApiRequest transactionRequest = new ApiRequest(0, new ApiRequestListener() {
|
||||||
|
@Override
|
||||||
|
public void success(Object answer, int idPetition) {
|
||||||
|
sendRequest.setSend(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail(int idPetition) {
|
||||||
|
sendRequest.setSend(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
GrapheneApiGenerator.broadcastTransaction(transaction,feeAsset, transactionRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(int idPetition) {
|
public void fail() {
|
||||||
sendRequest.setSend(false);
|
//TODO bad user to user account
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
GrapheneApiGenerator.broadcastTransaction(transaction,feeAsset, transactionRequest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the account info from a graphene id
|
* Returns the account info from a graphene id
|
||||||
* @param grapheneId The graphene id of the account
|
* @param grapheneId The graphene id of the account
|
||||||
*/
|
*/
|
||||||
private GrapheneAccount getAccountInfoById(String grapheneId){
|
private void getAccountInfoById(String grapheneId, ManagerRequest request){
|
||||||
final Object SYNC = new Object();
|
|
||||||
long timeout = 60000;
|
|
||||||
|
|
||||||
AccountIdOrNameListener listener = new AccountIdOrNameListener(SYNC);
|
AccountIdOrNameListener listener = new AccountIdOrNameListener(request);
|
||||||
|
|
||||||
ApiRequest request = new ApiRequest(0, listener);
|
ApiRequest accountRequest = new ApiRequest(0, listener);
|
||||||
GrapheneApiGenerator.getAccountById(grapheneId,request);
|
GrapheneApiGenerator.getAccountById(grapheneId,accountRequest);
|
||||||
|
|
||||||
long cTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
while(!listener.ready && (System.currentTimeMillis()-cTime) < timeout){
|
|
||||||
synchronized (SYNC){
|
|
||||||
try {
|
|
||||||
SYNC.wait(100);
|
|
||||||
} catch (InterruptedException ignore) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return listener.account;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets account info by its name
|
* Gets account info by its name
|
||||||
* @param grapheneName The name of the account to retrieve
|
* @param grapheneName The name of the account to retrieve
|
||||||
*/
|
*/
|
||||||
private GrapheneAccount getAccountInfoByName(String grapheneName){
|
private void getAccountInfoByName(String grapheneName, ManagerRequest request){
|
||||||
final Object SYNC = new Object();
|
|
||||||
long timeout = 60000;
|
|
||||||
|
|
||||||
AccountIdOrNameListener listener = new AccountIdOrNameListener(SYNC);
|
AccountIdOrNameListener listener = new AccountIdOrNameListener(request);
|
||||||
|
|
||||||
ApiRequest request = new ApiRequest(0, listener);
|
ApiRequest accountRequest = new ApiRequest(0, listener);
|
||||||
GrapheneApiGenerator.getAccountByName(grapheneName,request);
|
GrapheneApiGenerator.getAccountByName(grapheneName,accountRequest);
|
||||||
|
|
||||||
long cTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
while(!listener.ready && (System.currentTimeMillis()-cTime) < timeout){
|
|
||||||
synchronized (SYNC){
|
|
||||||
try {
|
|
||||||
SYNC.wait(100);
|
|
||||||
} catch (InterruptedException ignore) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return listener.account;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO expand function to be more generic
|
//TODO expand function to be more generic
|
||||||
private String getAssetInfoByName(String assetName){
|
private void getAssetInfoByName(String assetName, ManagerRequest request){
|
||||||
final Object SYNC = new Object();
|
|
||||||
long timeout = 60000;
|
|
||||||
|
|
||||||
AssetIdOrNameListener nameListener = new AssetIdOrNameListener(SYNC);
|
AssetIdOrNameListener nameListener = new AssetIdOrNameListener(request);
|
||||||
ApiRequest request = new ApiRequest(0, nameListener);
|
ApiRequest assetRequest = new ApiRequest(0, nameListener);
|
||||||
ArrayList<String> assetNames = new ArrayList<>();
|
ArrayList<String> assetNames = new ArrayList<>();
|
||||||
assetNames.add(assetName);
|
assetNames.add(assetName);
|
||||||
GrapheneApiGenerator.getAssetByName(assetNames, request);
|
GrapheneApiGenerator.getAssetByName(assetNames, assetRequest);
|
||||||
|
|
||||||
long cTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
while(!nameListener.ready && (System.currentTimeMillis()-cTime) < timeout){
|
|
||||||
synchronized (SYNC){
|
|
||||||
try {
|
|
||||||
SYNC.wait(100);
|
|
||||||
} catch (InterruptedException ignore) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nameListener.asset.getBitsharesId();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +462,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
* @param idAccount database id of the account
|
* @param idAccount database id of the account
|
||||||
* @param context The android context of this application
|
* @param context The android context of this application
|
||||||
*/
|
*/
|
||||||
public static void refreshAccountTransactions(long idAccount, Context context){
|
private static void refreshAccountTransactions(long idAccount, Context context){
|
||||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||||
List<CryptoCoinTransaction> transactions = db.transactionDao().getByIdAccount(idAccount);
|
List<CryptoCoinTransaction> transactions = db.transactionDao().getByIdAccount(idAccount);
|
||||||
CryptoNetAccount account = db.cryptoNetAccountDao().getById(idAccount);
|
CryptoNetAccount account = db.cryptoNetAccountDao().getById(idAccount);
|
||||||
|
@ -449,23 +518,22 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the succes request of the transaction, if the amount of transaction is equal to the limit, ask for more transaction
|
* Handles the success request of the transaction, if the amount of transaction is equal to the limit, ask for more transaction
|
||||||
* @param answer The answer, this object depends on the kind of request is made to the api
|
* @param answer The answer, this object depends on the kind of request is made to the api
|
||||||
* @param idPetition the id of the ApiRequest petition
|
* @param idPetition the id of the ApiRequest petition
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void success(Object answer, int idPetition) {
|
public void success(Object answer, int idPetition) {
|
||||||
List<HistoricalTransfer> transfers = (List<HistoricalTransfer>) answer ;
|
List<HistoricalTransfer> transfers = (List<HistoricalTransfer>) answer ;
|
||||||
for(HistoricalTransfer transfer : transfers) {
|
for(final HistoricalTransfer transfer : transfers) {
|
||||||
if (transfer.getOperation() != null){
|
if (transfer.getOperation() != null){
|
||||||
CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
final CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
||||||
transaction.setAccountId(account.getId());
|
transaction.setAccountId(account.getId());
|
||||||
transaction.setAmount(transfer.getOperation().getAssetAmount().getAmount().longValue());
|
transaction.setAmount(transfer.getOperation().getAssetAmount().getAmount().longValue());
|
||||||
BitsharesAssetInfo info = db.bitsharesAssetDao().getBitsharesAssetInfoById(transfer.getOperation().getAssetAmount().getAsset().getObjectId());
|
BitsharesAssetInfo info = db.bitsharesAssetDao().getBitsharesAssetInfoById(transfer.getOperation().getAssetAmount().getAsset().getObjectId());
|
||||||
|
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
//The cryptoCurrency is not in the database, queringfor its data
|
//The cryptoCurrency is not in the database, queringfor its data
|
||||||
final Object SYNC = new Object(); //Object to syn the answer
|
|
||||||
ApiRequest assetRequest = new ApiRequest(0, new ApiRequestListener() {
|
ApiRequest assetRequest = new ApiRequest(0, new ApiRequestListener() {
|
||||||
@Override
|
@Override
|
||||||
public void success(Object answer, int idPetition) {
|
public void success(Object answer, int idPetition) {
|
||||||
|
@ -476,39 +544,24 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
info.setCryptoCurrencyId(idCryptoCurrency);
|
info.setCryptoCurrencyId(idCryptoCurrency);
|
||||||
asset.setId((int)idCryptoCurrency);
|
asset.setId((int)idCryptoCurrency);
|
||||||
db.bitsharesAssetDao().insertBitsharesAssetInfo(info);
|
db.bitsharesAssetDao().insertBitsharesAssetInfo(info);
|
||||||
|
saveTransaction(transaction,info,transfer);
|
||||||
}
|
}
|
||||||
synchronized (SYNC){
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(int idPetition) {
|
public void fail(int idPetition) {
|
||||||
synchronized (SYNC){
|
//TODO Error
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ArrayList<String> assets = new ArrayList<>();
|
ArrayList<String> assets = new ArrayList<>();
|
||||||
assets.add(transfer.getOperation().getAssetAmount().getAsset().getObjectId());
|
assets.add(transfer.getOperation().getAssetAmount().getAsset().getObjectId());
|
||||||
GrapheneApiGenerator.getAssetById(assets,assetRequest);
|
GrapheneApiGenerator.getAssetById(assets,assetRequest);
|
||||||
|
|
||||||
synchronized (SYNC){
|
}else{
|
||||||
try {SYNC.wait(60000);} catch (InterruptedException ignore) {}
|
saveTransaction(transaction,info,transfer);
|
||||||
}
|
|
||||||
info = db.bitsharesAssetDao().getBitsharesAssetInfoById(transfer.getOperation().getAssetAmount().getAsset().getObjectId());
|
|
||||||
}
|
}
|
||||||
if( info == null){
|
|
||||||
//We couldn't retrieve the cryptocurrency
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
transaction.setIdCurrency((int)info.getCryptoCurrencyId());
|
|
||||||
transaction.setConfirmed(true); //graphene transaction are always confirmed
|
|
||||||
transaction.setFrom(transfer.getOperation().getFrom().getObjectId());
|
|
||||||
transaction.setInput(!transfer.getOperation().getFrom().getObjectId().equals(account.getAccountId()));
|
|
||||||
transaction.setTo(transfer.getOperation().getTo().getObjectId());
|
|
||||||
|
|
||||||
GrapheneApiGenerator.getBlockHeaderTime(transfer.getBlockNum(), new ApiRequest(0, new GetTransactionDate(transaction, db.transactionDao())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(transfers.size()>= limit){
|
if(transfers.size()>= limit){
|
||||||
|
@ -524,6 +577,16 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
public void fail(int idPetition) {
|
public void fail(int idPetition) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveTransaction(CryptoCoinTransaction transaction, BitsharesAssetInfo info, HistoricalTransfer transfer){
|
||||||
|
transaction.setIdCurrency((int)info.getCryptoCurrencyId());
|
||||||
|
transaction.setConfirmed(true); //graphene transaction are always confirmed
|
||||||
|
transaction.setFrom(transfer.getOperation().getFrom().getObjectId());
|
||||||
|
transaction.setInput(!transfer.getOperation().getFrom().getObjectId().equals(account.getAccountId()));
|
||||||
|
transaction.setTo(transfer.getOperation().getTo().getObjectId());
|
||||||
|
|
||||||
|
GrapheneApiGenerator.getBlockHeaderTime(transfer.getBlockNum(), new ApiRequest(0, new GetTransactionDate(transaction, db.transactionDao())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -547,6 +610,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
GrapheneApiGenerator.getEquivalentValue(fromAsset.getBitsharesId(),toAsset.getBitsharesId(), getEquivalentRequest);
|
GrapheneApiGenerator.getEquivalentValue(fromAsset.getBitsharesId(),toAsset.getBitsharesId(), getEquivalentRequest);
|
||||||
}else{
|
}else{
|
||||||
//TODO error
|
//TODO error
|
||||||
|
System.out.println("Equivalen Value error ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,13 +618,12 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
* Class to retrieve the account id or the account name, if one of those is missing
|
* Class to retrieve the account id or the account name, if one of those is missing
|
||||||
*/
|
*/
|
||||||
private class AccountIdOrNameListener implements ApiRequestListener{
|
private class AccountIdOrNameListener implements ApiRequestListener{
|
||||||
final Object SYNC;
|
final ManagerRequest request;
|
||||||
boolean ready = false;
|
|
||||||
|
|
||||||
GrapheneAccount account;
|
GrapheneAccount account;
|
||||||
|
|
||||||
AccountIdOrNameListener(Object SYNC) {
|
AccountIdOrNameListener(ManagerRequest request) {
|
||||||
this.SYNC = SYNC;
|
this.request = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -572,18 +635,12 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
account.setName(props.name);
|
account.setName(props.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (SYNC){
|
request.success(account);
|
||||||
ready = true;
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(int idPetition) {
|
public void fail(int idPetition) {
|
||||||
synchronized (SYNC){
|
request.fail();
|
||||||
ready = true;
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,36 +648,27 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
* Class to retrieve the asset id or the asset name, if one of those is missing
|
* Class to retrieve the asset id or the asset name, if one of those is missing
|
||||||
*/
|
*/
|
||||||
private class AssetIdOrNameListener implements ApiRequestListener{
|
private class AssetIdOrNameListener implements ApiRequestListener{
|
||||||
final Object SYNC;
|
final ManagerRequest request;
|
||||||
boolean ready = false;
|
|
||||||
|
|
||||||
BitsharesAsset asset;
|
BitsharesAsset asset;
|
||||||
|
|
||||||
AssetIdOrNameListener(Object SYNC) {
|
AssetIdOrNameListener(ManagerRequest request) {
|
||||||
this.SYNC = SYNC;
|
this.request = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void success(Object answer, int idPetition) {
|
public void success(Object answer, int idPetition) {
|
||||||
if(answer instanceof ArrayList) {
|
if(answer instanceof ArrayList) {
|
||||||
|
|
||||||
if (((ArrayList) answer).get(0) instanceof BitsharesAsset) {
|
if (((ArrayList) answer).get(0) instanceof BitsharesAsset) {
|
||||||
asset = (BitsharesAsset) ((ArrayList) answer).get(0);
|
asset = (BitsharesAsset) ((ArrayList) answer).get(0);
|
||||||
|
request.success(asset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (SYNC){
|
|
||||||
ready = true;
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(int idPetition) {
|
public void fail(int idPetition) {
|
||||||
synchronized (SYNC){
|
//TODO fail asset retrieve
|
||||||
ready = true;
|
|
||||||
SYNC.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +685,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
*/
|
*/
|
||||||
TransactionDao transactionDao;
|
TransactionDao transactionDao;
|
||||||
|
|
||||||
public GetTransactionDate(CryptoCoinTransaction transaction, TransactionDao transactionDao) {
|
GetTransactionDate(CryptoCoinTransaction transaction, TransactionDao transactionDao) {
|
||||||
this.transaction = transaction;
|
this.transaction = transaction;
|
||||||
this.transactionDao = transactionDao;
|
this.transactionDao = transactionDao;
|
||||||
}
|
}
|
||||||
|
@ -645,11 +693,13 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
||||||
@Override
|
@Override
|
||||||
public void success(Object answer, int idPetition) {
|
public void success(Object answer, int idPetition) {
|
||||||
if(answer instanceof BlockHeader){
|
if(answer instanceof BlockHeader){
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
@SuppressLint("SimpleDateFormat") SimpleDateFormat dateFormat = new SimpleDateFormat(SIMPLE_DATE_FORMAT);
|
||||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
dateFormat.setTimeZone(TimeZone.getTimeZone(DEFAULT_TIME_ZONE));
|
||||||
try {
|
try {
|
||||||
transaction.setDate(dateFormat.parse(((BlockHeader) answer).timestamp));
|
transaction.setDate(dateFormat.parse(((BlockHeader) answer).timestamp));
|
||||||
transactionDao.insertTransaction(transaction);
|
if (transactionDao.getByTransaction(transaction.getDate(),transaction.getFrom(),transaction.getTo(),transaction.getAmount()) == null) {
|
||||||
|
transactionDao.insertTransaction(transaction);
|
||||||
|
}
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,14 @@ public interface CryptoAccountManager {
|
||||||
* @param account The values to be created,
|
* @param account The values to be created,
|
||||||
* @returnThe CruptoNetAccount created, or null if it couldn't be created
|
* @returnThe CruptoNetAccount created, or null if it couldn't be created
|
||||||
*/
|
*/
|
||||||
public CryptoNetAccount createAccountFromSeed(CryptoNetAccount account, Context context);
|
public void createAccountFromSeed(CryptoNetAccount account, ManagerRequest request, Context context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports a CryptoCoin account from a seed
|
* Imports a CryptoCoin account from a seed
|
||||||
* @param account A CryptoNetAccount with the parameters to be imported
|
* @param account A CryptoNetAccount with the parameters to be imported
|
||||||
* @returnThe CruptoNetAccount imported
|
* @returnThe CruptoNetAccount imported
|
||||||
*/
|
*/
|
||||||
public CryptoNetAccount importAccountFromSeed(CryptoNetAccount account, Context context);
|
public void importAccountFromSeed(CryptoNetAccount account, Context context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads account data from the database
|
* Loads account data from the database
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package cy.agorise.crystalwallet.manager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by henry on 28/1/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface ManagerRequest {
|
||||||
|
|
||||||
|
public void success(Object answer);
|
||||||
|
|
||||||
|
public void fail();
|
||||||
|
}
|
|
@ -10,8 +10,11 @@ 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;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a user contact
|
* Represents a user contact
|
||||||
*
|
*
|
||||||
|
@ -19,7 +22,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Entity(tableName="contact",
|
@Entity(tableName="contact",
|
||||||
indices = {@Index("id"),@Index(value = {"name"}, unique=true)})
|
indices = {@Index("id"),@Index(value = {"name"}, unique=true),@Index("email")})
|
||||||
public class Contact {
|
public class Contact {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,6 +35,9 @@ public class Contact {
|
||||||
@ColumnInfo(name="name")
|
@ColumnInfo(name="name")
|
||||||
private String mName;
|
private String mName;
|
||||||
|
|
||||||
|
@ColumnInfo(name="email")
|
||||||
|
private String mEmail;
|
||||||
|
|
||||||
@ColumnInfo(name = "gravatar")
|
@ColumnInfo(name = "gravatar")
|
||||||
private String mGravatar;
|
private String mGravatar;
|
||||||
|
|
||||||
|
@ -62,6 +68,14 @@ public class Contact {
|
||||||
this.mGravatar = gravatar;
|
this.mGravatar = gravatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return this.mEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.mEmail = email;
|
||||||
|
}
|
||||||
|
|
||||||
public int addressesCount(){
|
public int addressesCount(){
|
||||||
return this.mAddresses.size();
|
return this.mAddresses.size();
|
||||||
}
|
}
|
||||||
|
@ -70,8 +84,30 @@ 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) {
|
||||||
|
this.mAddresses = new ArrayList<ContactAddress>();
|
||||||
|
}
|
||||||
this.mAddresses.add(address);
|
this.mAddresses.add(address);
|
||||||
|
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>() {
|
||||||
|
|
|
@ -4,9 +4,12 @@ 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;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a user contact address
|
* Represents a user contact address
|
||||||
*
|
*
|
||||||
|
@ -14,19 +17,37 @@ import android.support.v7.recyclerview.extensions.DiffCallback;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Entity(tableName="contact_address",
|
@Entity(tableName="contact_address",
|
||||||
primaryKeys = {"contact_id","crypto_currency_id"},
|
indices = {@Index(value = {"id"}, unique=true),@Index(value = {"contact_id","crypto_net"}, unique=true)})
|
||||||
indices = {@Index(value = {"contact_id","crypto_currency_id"}, 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;
|
||||||
|
|
||||||
@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;
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
this.mId = id;
|
||||||
|
}
|
||||||
|
|
||||||
public long getContactId() {
|
public long getContactId() {
|
||||||
return mContactId;
|
return mContactId;
|
||||||
}
|
}
|
||||||
|
@ -35,12 +56,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 +77,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 +94,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ public class GeneralSetting {
|
||||||
|
|
||||||
public final static String SETTING_NAME_PREFERED_COUNTRY = "PREFERED_COUNTRY";
|
public final static String SETTING_NAME_PREFERED_COUNTRY = "PREFERED_COUNTRY";
|
||||||
public final static String SETTING_NAME_PREFERED_CURRENCY = "PREFERED_CURRENCY";
|
public final static String SETTING_NAME_PREFERED_CURRENCY = "PREFERED_CURRENCY";
|
||||||
|
public final static String SETTING_PASSWORD = "PASSWORD";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id on the database
|
* The id on the database
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package cy.agorise.crystalwallet.network;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||||
|
import cy.agorise.graphenej.interfaces.WitnessResponseListener;
|
||||||
|
import cy.agorise.graphenej.models.BaseResponse;
|
||||||
|
import cy.agorise.graphenej.models.WitnessResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Created by henry on 28/2/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class BitsharesCryptoNetVerifier extends CryptoNetVerifier {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO We need to change this to a type of subCryptoNet
|
||||||
|
*/
|
||||||
|
private final CryptoNet cryptoNet = CryptoNet.BITSHARES;
|
||||||
|
/**
|
||||||
|
* Todo info need to be on the SubCryptoNet
|
||||||
|
*/
|
||||||
|
private final String CHAIN_ID = "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8";//testnet
|
||||||
|
//private final String CHAIN_ID = "4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8";//mainnet
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkURL(final String url) {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
WebSocketThread thread = new WebSocketThread(new GetChainId(new WitnessResponseListener() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(WitnessResponse response) {
|
||||||
|
if(response.result instanceof String) {
|
||||||
|
if(response.result.equals(CHAIN_ID)) {
|
||||||
|
CryptoNetManager.verifiedCryptoNetURL(cryptoNet, url, System.currentTimeMillis() - startTime);
|
||||||
|
}else{
|
||||||
|
System.out.println(" BitsharesCryptoNetVerifier Error we are not in the net current chain id " + response.result + " excepted " + CHAIN_ID);
|
||||||
|
//TODO handle error bad chain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(BaseResponse.Error error) {
|
||||||
|
//TODO handle error
|
||||||
|
}
|
||||||
|
}),url);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getChainId() {
|
||||||
|
return CHAIN_ID;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
package cy.agorise.crystalwallet.network;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by henry on 6/3/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class CryptoNetManager {
|
||||||
|
/**
|
||||||
|
* This map contains the list of the urls to be tested
|
||||||
|
*/
|
||||||
|
private static HashMap<CryptoNet,HashSet<String>> CryptoNetURLs = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This map contains the list of urls been tested and ordered by the fastests
|
||||||
|
*/
|
||||||
|
private static HashMap<CryptoNet,ArrayList<TestedURL>> TestedURLs = new HashMap<>();
|
||||||
|
|
||||||
|
public static String getURL(CryptoNet crypto){
|
||||||
|
return CryptoNetManager.getURL(crypto,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String getURL(CryptoNet crypto, int index){
|
||||||
|
if(TestedURLs.containsKey(crypto) && TestedURLs.get(crypto).size()>index){
|
||||||
|
return TestedURLs.get(crypto).get(index).getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CryptoNetURLs.containsKey(crypto) && !CryptoNetURLs.get(crypto).isEmpty()){
|
||||||
|
return CryptoNetURLs.get(crypto).iterator().next();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getURLSize(CryptoNet crypto){
|
||||||
|
if(TestedURLs.containsKey(crypto)){
|
||||||
|
return TestedURLs.get(crypto).size();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addCryptoNetURL(CryptoNet crypto, String url){
|
||||||
|
if(!CryptoNetURLs.containsKey(crypto)){
|
||||||
|
CryptoNetURLs.put(crypto,new HashSet<String>());
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptoNetURLs.get(crypto).add(url);
|
||||||
|
CryptoNetVerifier verifier = CryptoNetVerifier.getNetworkVerify(crypto);
|
||||||
|
if(verifier != null) {
|
||||||
|
verifier.checkURL(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addCryptoNetURL(CryptoNet crypto, String[] urls){
|
||||||
|
if(!CryptoNetURLs.containsKey(crypto)){
|
||||||
|
CryptoNetURLs.put(crypto,new HashSet<String>());
|
||||||
|
}
|
||||||
|
CryptoNetVerifier verifier = CryptoNetVerifier.getNetworkVerify(crypto);
|
||||||
|
|
||||||
|
for(String url : urls) {
|
||||||
|
CryptoNetURLs.get(crypto).add(url);
|
||||||
|
if(verifier != null) {
|
||||||
|
verifier.checkURL(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeCryptoNetURL(CryptoNet crypto, String url){
|
||||||
|
if(CryptoNetURLs.containsKey(crypto)){
|
||||||
|
CryptoNetURLs.get(crypto).remove(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void verifiedCryptoNetURL(CryptoNet crypto, String url, long time){
|
||||||
|
if(CryptoNetURLs.containsKey(crypto) && CryptoNetURLs.get(crypto).contains(url)){
|
||||||
|
if(!TestedURLs.containsKey(crypto)){
|
||||||
|
TestedURLs.put(crypto,new ArrayList<TestedURL>());
|
||||||
|
}
|
||||||
|
TestedURL testedUrl = new TestedURL(time,url);
|
||||||
|
if(!TestedURLs.get(crypto).contains(testedUrl)){
|
||||||
|
TestedURLs.get(crypto).add(testedUrl);
|
||||||
|
Collections.sort(TestedURLs.get(crypto));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//TODO add error handler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getChaindId(CryptoNet crypto){
|
||||||
|
CryptoNetVerifier verifier = CryptoNetVerifier.getNetworkVerify(crypto);
|
||||||
|
if(verifier != null) {
|
||||||
|
return verifier.getChainId();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestedURL implements Comparable{
|
||||||
|
private long time;
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public TestedURL(long time, String url) {
|
||||||
|
this.time = time;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof TestedURL)) return false;
|
||||||
|
|
||||||
|
TestedURL testedURL = (TestedURL) o;
|
||||||
|
|
||||||
|
return getUrl().equals(testedURL.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getUrl().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NonNull Object o) {
|
||||||
|
if (this == o) return 0;
|
||||||
|
if (!(o instanceof TestedURL)) return 0;
|
||||||
|
|
||||||
|
TestedURL testedURL = (TestedURL) o;
|
||||||
|
return (int) (this.getTime() - testedURL.getTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package cy.agorise.crystalwallet.network;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to check if the connection is stable and fast.
|
||||||
|
*
|
||||||
|
* Also verifies if the connection with the server is valid.
|
||||||
|
*
|
||||||
|
* Created by henry on 28/2/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class CryptoNetVerifier {
|
||||||
|
|
||||||
|
static CryptoNetVerifier getNetworkVerify(CryptoNet cryptoNet){
|
||||||
|
if(cryptoNet.getLabel().equals(CryptoNet.BITSHARES.getLabel())){
|
||||||
|
return new BitsharesCryptoNetVerifier();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void checkURL(final String url);
|
||||||
|
|
||||||
|
public abstract String getChainId();
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package cy.agorise.crystalwallet.network;
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.neovisionaries.ws.client.WebSocket;
|
||||||
|
import com.neovisionaries.ws.client.WebSocketFrame;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import cy.agorise.graphenej.RPC;
|
||||||
|
import cy.agorise.graphenej.api.BaseGrapheneHandler;
|
||||||
|
import cy.agorise.graphenej.interfaces.WitnessResponseListener;
|
||||||
|
import cy.agorise.graphenej.models.ApiCall;
|
||||||
|
import cy.agorise.graphenej.models.WitnessResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by henry on 28/2/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class GetChainId extends BaseGrapheneHandler {
|
||||||
|
|
||||||
|
private final WitnessResponseListener mListener;
|
||||||
|
|
||||||
|
public GetChainId(WitnessResponseListener listener) {
|
||||||
|
super(listener);
|
||||||
|
this.mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
|
||||||
|
ApiCall getAccountByName = new ApiCall(0, "get_chain_id", new ArrayList<Serializable>(), RPC.VERSION, 1);
|
||||||
|
websocket.sendText(getAccountByName.toJsonString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextFrame(WebSocket websocket, WebSocketFrame frame) throws Exception {
|
||||||
|
System.out.println("<<< "+frame.getPayloadText());
|
||||||
|
String response = frame.getPayloadText();
|
||||||
|
|
||||||
|
Type GetChainIdResponse = new TypeToken<WitnessResponse<String>>(){}.getType();
|
||||||
|
GsonBuilder builder = new GsonBuilder();
|
||||||
|
WitnessResponse<List<String>> witnessResponse = builder.create().fromJson(response, GetChainIdResponse);
|
||||||
|
if(witnessResponse.error != null){
|
||||||
|
this.mListener.onError(witnessResponse.error);
|
||||||
|
}else{
|
||||||
|
this.mListener.onSuccess(witnessResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
websocket.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFrameSent(WebSocket websocket, WebSocketFrame frame) throws Exception {
|
||||||
|
if(frame.isTextFrame())
|
||||||
|
System.out.println(">>> "+frame.getPayloadText());
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,8 +109,7 @@ public class CrystalWalletService extends LifecycleService {
|
||||||
|
|
||||||
if (LoadEquivalencesThread != null) {
|
if (LoadEquivalencesThread != null) {
|
||||||
LoadEquivalencesThread.stopLoadingEquivalences();
|
LoadEquivalencesThread.stopLoadingEquivalences();
|
||||||
}
|
};
|
||||||
;
|
|
||||||
LoadEquivalencesThread = new EquivalencesThread(service, generalSetting.getValue(), bitsharesAssets);
|
LoadEquivalencesThread = new EquivalencesThread(service, generalSetting.getValue(), bitsharesAssets);
|
||||||
LoadEquivalencesThread.start();
|
LoadEquivalencesThread.start();
|
||||||
}
|
}
|
||||||
|
@ -184,14 +183,14 @@ public class CrystalWalletService extends LifecycleService {
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (LoadEquivalencesThread == null) {
|
//if (LoadEquivalencesThread == null) {
|
||||||
// LoadEquivalencesThread = new Thread() {
|
// LoadEquivalencesThread = new EquivalencesThread() {
|
||||||
// @Override
|
// @Override
|
||||||
// public void run() {
|
// public void run() {
|
||||||
loadEquivalentsValues();
|
loadEquivalentsValues();
|
||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
// LoadEquivalencesThread.start();
|
// LoadEquivalencesThread.start();
|
||||||
//}
|
// }
|
||||||
|
|
||||||
// If we get killed, after returning from here, restart
|
// If we get killed, after returning from here, restart
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package cy.agorise.crystalwallet.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 25/2/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapShader;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
|
||||||
|
import com.squareup.picasso.Transformation;
|
||||||
|
|
||||||
|
public class CircleTransformation implements Transformation {
|
||||||
|
@Override
|
||||||
|
public Bitmap transform(Bitmap source) {
|
||||||
|
int size = Math.min(source.getWidth(), source.getHeight());
|
||||||
|
|
||||||
|
int x = (source.getWidth() - size) / 2;
|
||||||
|
int y = (source.getHeight() - size) / 2;
|
||||||
|
|
||||||
|
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
|
||||||
|
if (squaredBitmap != source) {
|
||||||
|
source.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
|
||||||
|
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
Paint paint = new Paint();
|
||||||
|
BitmapShader shader = new BitmapShader(squaredBitmap,
|
||||||
|
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
|
||||||
|
paint.setShader(shader);
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
|
||||||
|
float r = size / 2f;
|
||||||
|
canvas.drawCircle(r, r, r, paint);
|
||||||
|
|
||||||
|
squaredBitmap.recycle();
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String key() {
|
||||||
|
return "CircleTransformation";
|
||||||
|
}
|
||||||
|
}
|
22
app/src/main/java/cy/agorise/crystalwallet/util/MD5Hash.java
Normal file
22
app/src/main/java/cy/agorise/crystalwallet/util/MD5Hash.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package cy.agorise.crystalwallet.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 24/2/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MD5Hash {
|
||||||
|
|
||||||
|
static public String hash(String md5) {
|
||||||
|
try {
|
||||||
|
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
||||||
|
byte[] array = md.digest(md5.getBytes());
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
for (int i = 0; i < array.length; ++i) {
|
||||||
|
sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
} catch (java.security.NoSuchAlgorithmException e) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package cy.agorise.crystalwallet.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 29/1/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class PasswordManager {
|
||||||
|
|
||||||
|
//TODO implement password checking using the encryption implemented in encriptPassword
|
||||||
|
public static boolean checkPassword(String encriptedPassword, String passwordToCheck){
|
||||||
|
if (encriptedPassword.equals(passwordToCheck)){
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO implement password encryption
|
||||||
|
public static String encriptPassword(String password){
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,7 +31,31 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean contactExists(String name){
|
||||||
|
return this.db.contactDao().existsByName(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package cy.agorise.crystalwallet.viewmodels;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.arch.lifecycle.AndroidViewModel;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.paging.PagedList;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
||||||
|
import cy.agorise.crystalwallet.models.Contact;
|
||||||
|
import cy.agorise.crystalwallet.models.ContactAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 2/4/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ContactViewModel extends AndroidViewModel {
|
||||||
|
|
||||||
|
private CrystalDatabase db;
|
||||||
|
private LiveData<Contact> contact;
|
||||||
|
private LiveData<List<ContactAddress>> contactAddresses;
|
||||||
|
|
||||||
|
public ContactViewModel(Application application) {
|
||||||
|
super(application);
|
||||||
|
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){
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ public class CryptoNetAccountViewModel extends AndroidViewModel {
|
||||||
this.db = CrystalDatabase.getAppDatabase(application.getApplicationContext());
|
this.db = CrystalDatabase.getAppDatabase(application.getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadCryptoNetAccount(int accountId){
|
public void loadCryptoNetAccount(long accountId){
|
||||||
this.cryptoNetAccount = this.db.cryptoNetAccountDao().getByIdLiveData(accountId);
|
this.cryptoNetAccount = this.db.cryptoNetAccountDao().getByIdLiveData(accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,5 +36,4 @@ public class CryptoNetAccountViewModel extends AndroidViewModel {
|
||||||
public LiveData<CryptoNetAccount> getCryptoNetAccount(){
|
public LiveData<CryptoNetAccount> getCryptoNetAccount(){
|
||||||
return this.cryptoNetAccount;
|
return this.cryptoNetAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package cy.agorise.crystalwallet.viewmodels.validators;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.BitsharesAccountNameDoesntExistsValidationField;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ContactNameValidationField;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.EmailValidationField;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.PinConfirmationValidationField;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.PinValidationField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 2/2/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CreateContactValidator extends UIValidator {
|
||||||
|
|
||||||
|
public CreateContactValidator(Context context, EditText nameEdit, EditText emailEdit){
|
||||||
|
super(context);
|
||||||
|
this.addField(new ContactNameValidationField(nameEdit));
|
||||||
|
this.addField(new EmailValidationField(emailEdit));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
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;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.EmailValidationField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 2/11/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ModifyContactValidator extends UIValidator {
|
||||||
|
|
||||||
|
public ModifyContactValidator(Context context, Contact contact, EditText nameEdit, EditText emailEdit){
|
||||||
|
super(context);
|
||||||
|
this.addField(new ContactNameValidationField(nameEdit, contact));
|
||||||
|
this.addField(new EmailValidationField(emailEdit));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package cy.agorise.crystalwallet.viewmodels.validators;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.BitsharesAccountNameDoesntExistsValidationField;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.CurrentPinValidationField;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.PinConfirmationValidationField;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.PinValidationField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 1/28/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class PinSecurityValidator extends UIValidator {
|
||||||
|
|
||||||
|
public PinSecurityValidator(Context context, EditText currentPinEdit, EditText newPinEdit, EditText newPinConfirmationEdit){
|
||||||
|
super(context);
|
||||||
|
this.addField(new CurrentPinValidationField(currentPinEdit));
|
||||||
|
this.addField(new PinValidationField(newPinEdit));
|
||||||
|
this.addField(new PinConfirmationValidationField(newPinEdit,newPinConfirmationEdit));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package cy.agorise.crystalwallet.viewmodels.validators.validationfields;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.R;
|
||||||
|
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestListener;
|
||||||
|
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests;
|
||||||
|
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateExistBitsharesAccountRequest;
|
||||||
|
import cy.agorise.crystalwallet.models.Contact;
|
||||||
|
import cy.agorise.crystalwallet.models.GeneralSetting;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 2/03/2017.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ContactNameValidationField extends ValidationField {
|
||||||
|
|
||||||
|
private EditText nameField;
|
||||||
|
private Contact contact;
|
||||||
|
|
||||||
|
public ContactNameValidationField(EditText nameField){
|
||||||
|
super(nameField);
|
||||||
|
this.nameField = nameField;
|
||||||
|
this.contact = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactNameValidationField(EditText nameField, Contact contact){
|
||||||
|
super(nameField);
|
||||||
|
this.nameField = nameField;
|
||||||
|
this.contact = contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate(){
|
||||||
|
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(this.getLastValue())) {
|
||||||
|
this.setLastValue(newValue);
|
||||||
|
this.startValidating();
|
||||||
|
|
||||||
|
ContactListViewModel contactListViewModel = ViewModelProviders.of((FragmentActivity) view.getContext()).get(ContactListViewModel.class);
|
||||||
|
if (contactListViewModel.contactExists(newValue)) {
|
||||||
|
this.setMessageForValue(newValue, "This name is already used by another contact.");
|
||||||
|
this.setValidForValue(newValue, false);
|
||||||
|
} else {
|
||||||
|
this.setValidForValue(newValue, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setLastValue("");
|
||||||
|
this.startValidating();
|
||||||
|
this.setMessageForValue("", "");
|
||||||
|
this.setValidForValue("", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package cy.agorise.crystalwallet.viewmodels.validators.validationfields;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.models.GeneralSetting;
|
||||||
|
import cy.agorise.crystalwallet.util.PasswordManager;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 1/28/2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CurrentPinValidationField extends ValidationField {
|
||||||
|
|
||||||
|
private EditText currentPinField;
|
||||||
|
String currentPassword = "";
|
||||||
|
|
||||||
|
public CurrentPinValidationField(EditText currentPinField){
|
||||||
|
super(currentPinField);
|
||||||
|
this.currentPinField = currentPinField;
|
||||||
|
GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of((FragmentActivity)view.getContext()).get(GeneralSettingListViewModel.class);
|
||||||
|
LiveData<List<GeneralSetting>> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList();
|
||||||
|
generalSettingsLiveData.observe((LifecycleOwner) this.view.getContext(), new Observer<List<GeneralSetting>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable List<GeneralSetting> generalSettings) {
|
||||||
|
for (GeneralSetting generalSetting:generalSettings) {
|
||||||
|
if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){
|
||||||
|
currentPassword = generalSetting.getValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate(){
|
||||||
|
final String newValue = currentPinField.getText().toString();
|
||||||
|
|
||||||
|
if (this.currentPassword.equals("")) {
|
||||||
|
this.setLastValue("");
|
||||||
|
this.startValidating();
|
||||||
|
setValidForValue("",true);
|
||||||
|
} else if (!newValue.equals(this.getLastValue())) {
|
||||||
|
this.setLastValue(newValue);
|
||||||
|
this.startValidating();
|
||||||
|
if (newValue.equals("")){
|
||||||
|
setMessageForValue(lastValue, "");
|
||||||
|
setValidForValue(lastValue, false);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (PasswordManager.checkPassword(this.currentPassword, newValue)) {
|
||||||
|
setValidForValue(lastValue, true);
|
||||||
|
} else {
|
||||||
|
setMessageForValue(lastValue, "Password is invalid.");
|
||||||
|
setValidForValue(lastValue, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package cy.agorise.crystalwallet.viewmodels.validators.validationfields;
|
||||||
|
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Henry Varona on 2/21/2017.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class EmailValidationField extends ValidationField {
|
||||||
|
|
||||||
|
private EditText emailField;
|
||||||
|
|
||||||
|
public EmailValidationField(EditText emailField){
|
||||||
|
super(emailField);
|
||||||
|
this.emailField = emailField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate(){
|
||||||
|
String newValue = emailField.getText().toString();
|
||||||
|
if (!newValue.equals("")) {
|
||||||
|
|
||||||
|
if (!newValue.equals(this.getLastValue())) {
|
||||||
|
this.setLastValue(newValue);
|
||||||
|
this.startValidating();
|
||||||
|
|
||||||
|
String expression = "^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z]{2,4}$";
|
||||||
|
Pattern pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
|
||||||
|
Matcher matcher = pattern.matcher(newValue);
|
||||||
|
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
this.setMessageForValue(newValue, "The email is not valid");
|
||||||
|
this.setValidForValue(newValue, false);
|
||||||
|
} else {
|
||||||
|
this.setValidForValue(newValue, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setLastValue("");
|
||||||
|
this.startValidating();
|
||||||
|
this.setMessageForValue("", "");
|
||||||
|
this.setValidForValue("", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,18 +22,24 @@ public class PinConfirmationValidationField extends ValidationField {
|
||||||
public void validate(){
|
public void validate(){
|
||||||
String newConfirmationValue = pinConfirmationField.getText().toString();
|
String newConfirmationValue = pinConfirmationField.getText().toString();
|
||||||
String newValue = pinField.getText().toString();
|
String newValue = pinField.getText().toString();
|
||||||
String mixedValue = newValue+"_"+newConfirmationValue;
|
String mixedValue = newValue + "_" + newConfirmationValue;
|
||||||
if (mixedValue != this.getLastValue()) {
|
|
||||||
this.setLastValue(mixedValue);
|
|
||||||
this.startValidating();
|
|
||||||
|
|
||||||
|
if (!newConfirmationValue.equals("")) {
|
||||||
if (!newConfirmationValue.equals(newValue)){
|
if (!mixedValue.equals(this.getLastValue())) {
|
||||||
this.setMessageForValue(mixedValue,this.validator.getContext().getResources().getString(R.string.mismatch_pin));
|
this.setLastValue(mixedValue);
|
||||||
this.setValidForValue(mixedValue,false);
|
this.startValidating();
|
||||||
} else {
|
if (!newConfirmationValue.equals(newValue)) {
|
||||||
this.setValidForValue(mixedValue, true);
|
this.setMessageForValue(mixedValue, this.validator.getContext().getResources().getString(R.string.mismatch_pin));
|
||||||
|
this.setValidForValue(mixedValue, false);
|
||||||
|
} else {
|
||||||
|
this.setValidForValue(mixedValue, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.setLastValue("");
|
||||||
|
this.startValidating();
|
||||||
|
this.setMessageForValue("", "");
|
||||||
|
this.setValidForValue("", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,16 +20,23 @@ public class PinValidationField extends ValidationField {
|
||||||
|
|
||||||
public void validate(){
|
public void validate(){
|
||||||
String newValue = pinField.getText().toString();
|
String newValue = pinField.getText().toString();
|
||||||
if (newValue != this.getLastValue()) {
|
if (!newValue.equals("")) {
|
||||||
this.setLastValue(newValue);
|
if (!newValue.equals(this.getLastValue())) {
|
||||||
this.startValidating();
|
this.setLastValue(newValue);
|
||||||
|
this.startValidating();
|
||||||
|
|
||||||
if (newValue.length() < 6) {
|
if (newValue.length() < 6) {
|
||||||
this.setMessageForValue(newValue, this.validator.getContext().getResources().getString(R.string.pin_number_warning));
|
this.setMessageForValue(newValue, this.validator.getContext().getResources().getString(R.string.pin_number_warning));
|
||||||
this.setValidForValue(newValue, false);
|
this.setValidForValue(newValue, false);
|
||||||
} else {
|
} else {
|
||||||
this.setValidForValue(newValue, true);
|
this.setValidForValue(newValue, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.setLastValue("");
|
||||||
|
this.startValidating();
|
||||||
|
this.setMessageForValue("", "");
|
||||||
|
this.setValidForValue("", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
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;
|
||||||
|
private CryptoNet[] cryptoNetArray;
|
||||||
|
private ArrayAdapter<CryptoNet> cryptoNetSpinnerAdapter;
|
||||||
|
|
||||||
|
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
|
||||||
|
cryptoNetArray = CryptoNet.values();
|
||||||
|
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 {
|
||||||
|
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() {
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,9 +12,7 @@ import android.widget.RelativeLayout;
|
||||||
|
|
||||||
import cy.agorise.crystalwallet.R;
|
import cy.agorise.crystalwallet.R;
|
||||||
import cy.agorise.crystalwallet.models.Contact;
|
import cy.agorise.crystalwallet.models.Contact;
|
||||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
|
||||||
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
|
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
|
||||||
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Henry Varona on 1/15/2018.
|
* Created by Henry Varona on 1/15/2018.
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
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 com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
|
import cy.agorise.crystalwallet.R;
|
||||||
|
import cy.agorise.crystalwallet.activities.CreateContactActivity;
|
||||||
|
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
||||||
|
import cy.agorise.crystalwallet.models.Contact;
|
||||||
|
import cy.agorise.crystalwallet.util.CircleTransformation;
|
||||||
|
import cy.agorise.crystalwallet.util.MD5Hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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");
|
||||||
|
|
||||||
|
if (contact.getEmail() != null){
|
||||||
|
String emailHash = MD5Hash.hash(contact.getEmail());
|
||||||
|
String gravatarUrl = "http://www.gravatar.com/avatar/" + emailHash + "?s=204&d=404";
|
||||||
|
|
||||||
|
Picasso.with(this.context)
|
||||||
|
.load(gravatarUrl)
|
||||||
|
.transform(new CircleTransformation())
|
||||||
|
.into(ivThumbnail);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,24 @@
|
||||||
package cy.agorise.crystalwallet.views;
|
package cy.agorise.crystalwallet.views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.provider.ContactsContract;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.ThemedSpinnerAdapter;
|
||||||
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 com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
import cy.agorise.crystalwallet.R;
|
import cy.agorise.crystalwallet.R;
|
||||||
|
import cy.agorise.crystalwallet.activities.CreateContactActivity;
|
||||||
|
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
||||||
import cy.agorise.crystalwallet.models.Contact;
|
import cy.agorise.crystalwallet.models.Contact;
|
||||||
|
import cy.agorise.crystalwallet.util.CircleTransformation;
|
||||||
|
import cy.agorise.crystalwallet.util.MD5Hash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Henry Varona on 1/17/2017.
|
* Created by Henry Varona on 1/17/2017.
|
||||||
|
@ -19,6 +30,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 +39,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 +62,47 @@ 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (contact.getEmail() != null){
|
||||||
|
String emailHash = MD5Hash.hash(contact.getEmail());
|
||||||
|
String gravatarUrl = "http://www.gravatar.com/avatar/" + emailHash + "?s=204&d=404";
|
||||||
|
|
||||||
|
Picasso.with(this.context)
|
||||||
|
.load(gravatarUrl)
|
||||||
|
.transform(new CircleTransformation())
|
||||||
|
.into(ivThumbnail);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ivDeleteContact.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
//delete the contact
|
||||||
|
new AlertDialog.Builder(context)
|
||||||
|
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||||
|
.setMessage("Are you sure you want to delete this contact?")
|
||||||
|
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
CrystalDatabase.getAppDatabase(context).contactDao().deleteContacts(contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.setNegativeButton("No", null)
|
||||||
|
.show();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,16 +17,22 @@ import cy.agorise.crystalwallet.models.CryptoCoinBalance;
|
||||||
|
|
||||||
public class CryptoCoinBalanceListAdapter extends ListAdapter<CryptoCoinBalance, CryptoCoinBalanceViewHolder> {
|
public class CryptoCoinBalanceListAdapter extends ListAdapter<CryptoCoinBalance, CryptoCoinBalanceViewHolder> {
|
||||||
|
|
||||||
|
CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder;
|
||||||
|
|
||||||
public CryptoCoinBalanceListAdapter() {
|
public CryptoCoinBalanceListAdapter() {
|
||||||
super(CryptoCoinBalance.DIFF_CALLBACK);
|
super(CryptoCoinBalance.DIFF_CALLBACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCryptoNetBalanceViewHolder(CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder){
|
||||||
|
this.cryptoNetBalanceViewHolder = cryptoNetBalanceViewHolder;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CryptoCoinBalanceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public CryptoCoinBalanceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.crypto_coin_balance_list_item,parent,false);
|
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.crypto_coin_balance_list_item,parent,false);
|
||||||
|
|
||||||
|
|
||||||
return new CryptoCoinBalanceViewHolder(v);
|
return new CryptoCoinBalanceViewHolder(v, cryptoNetBalanceViewHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class CryptoCoinBalanceListView extends RelativeLayout {
|
||||||
*
|
*
|
||||||
* @param data the list of crypto coin balances that will be show to the user
|
* @param data the list of crypto coin balances that will be show to the user
|
||||||
*/
|
*/
|
||||||
public void setData(List<CryptoCoinBalance> data){
|
public void setData(List<CryptoCoinBalance> data, CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder){
|
||||||
//initializes the list adapter
|
//initializes the list adapter
|
||||||
if (this.listAdapter == null) {
|
if (this.listAdapter == null) {
|
||||||
this.listAdapter = new CryptoCoinBalanceListAdapter();
|
this.listAdapter = new CryptoCoinBalanceListAdapter();
|
||||||
|
@ -92,6 +92,7 @@ public class CryptoCoinBalanceListView extends RelativeLayout {
|
||||||
|
|
||||||
//sets the data of the list adapter
|
//sets the data of the list adapter
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
|
this.listAdapter.setCryptoNetBalanceViewHolder(cryptoNetBalanceViewHolder);
|
||||||
this.listAdapter.setList(data);
|
this.listAdapter.setList(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,12 +39,15 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
public CryptoCoinBalanceViewHolder(View itemView) {
|
private CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder;
|
||||||
|
|
||||||
|
public CryptoCoinBalanceViewHolder(View itemView, CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
//TODO: use ButterKnife to load this
|
//TODO: use ButterKnife to load this
|
||||||
cryptoCoinName = (TextView) itemView.findViewById(R.id.tvCryptoCoinName);
|
cryptoCoinName = (TextView) itemView.findViewById(R.id.tvCryptoCoinName);
|
||||||
cryptoCoinBalance = (TextView) itemView.findViewById(R.id.tvCryptoCoinBalanceAmount);
|
cryptoCoinBalance = (TextView) itemView.findViewById(R.id.tvCryptoCoinBalanceAmount);
|
||||||
cryptoCoinBalanceEquivalence = (TextView) itemView.findViewById(R.id.tvCryptoCoinBalanceEquivalence);
|
cryptoCoinBalanceEquivalence = (TextView) itemView.findViewById(R.id.tvCryptoCoinBalanceEquivalence);
|
||||||
|
this.cryptoNetBalanceViewHolder = cryptoNetBalanceViewHolder;
|
||||||
this.context = itemView.getContext();
|
this.context = itemView.getContext();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -80,30 +83,41 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder {
|
||||||
public void onChanged(@Nullable GeneralSetting generalSetting) {
|
public void onChanged(@Nullable GeneralSetting generalSetting) {
|
||||||
if (generalSetting != null) {
|
if (generalSetting != null) {
|
||||||
//Gets the currency object of the preferred currency
|
//Gets the currency object of the preferred currency
|
||||||
CryptoCurrency currencyTo = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getByName(generalSetting.getValue());
|
LiveData<CryptoCurrency> currencyToLiveData = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getLiveDataByName(generalSetting.getValue());
|
||||||
|
|
||||||
//Retrieves the equivalent value of this balance using the "From" currency and the "To" currency
|
currencyToLiveData.observe((LifecycleOwner) context, new Observer<CryptoCurrency>() {
|
||||||
LiveData<CryptoCurrencyEquivalence> currencyEquivalenceLiveData = CrystalDatabase.getAppDatabase(context)
|
|
||||||
.cryptoCurrencyEquivalenceDao().getByFromTo(
|
|
||||||
currencyTo.getId(),
|
|
||||||
currencyFrom.getId()
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
//Observes the equivalent value. If the equivalent value changes, this will keep the value showed correct
|
|
||||||
currencyEquivalenceLiveData.observe((LifecycleOwner) context, new Observer<CryptoCurrencyEquivalence>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onChanged(@Nullable CryptoCurrencyEquivalence cryptoCurrencyEquivalence) {
|
public void onChanged(@Nullable CryptoCurrency cryptoCurrency) {
|
||||||
if (cryptoCurrencyEquivalence != null) {
|
if (cryptoCurrency != null) {
|
||||||
CryptoCurrency toCurrency = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getById(cryptoCurrencyEquivalence.getFromCurrencyId());
|
CryptoCurrency currencyTo = cryptoCurrency;
|
||||||
String equivalenceString = String.format(
|
|
||||||
"%.2f",
|
|
||||||
(balance.getBalance()/Math.pow(10,currencyFrom.getPrecision()))/
|
|
||||||
(cryptoCurrencyEquivalence.getValue()/Math.pow(10,toCurrency.getPrecision()))
|
|
||||||
);
|
|
||||||
|
|
||||||
cryptoCoinBalanceEquivalence.setText(
|
//Retrieves the equivalent value of this balance using the "From" currency and the "To" currency
|
||||||
equivalenceString + " " + toCurrency.getName());
|
LiveData<CryptoCurrencyEquivalence> currencyEquivalenceLiveData = CrystalDatabase.getAppDatabase(context)
|
||||||
|
.cryptoCurrencyEquivalenceDao().getByFromTo(
|
||||||
|
currencyTo.getId(),
|
||||||
|
currencyFrom.getId()
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
//Observes the equivalent value. If the equivalent value changes, this will keep the value showed correct
|
||||||
|
currencyEquivalenceLiveData.observe((LifecycleOwner) context, new Observer<CryptoCurrencyEquivalence>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable CryptoCurrencyEquivalence cryptoCurrencyEquivalence) {
|
||||||
|
if (cryptoCurrencyEquivalence != null) {
|
||||||
|
CryptoCurrency toCurrency = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getById(cryptoCurrencyEquivalence.getFromCurrencyId());
|
||||||
|
double equivalentValue = (balance.getBalance() / Math.pow(10, currencyFrom.getPrecision())) /
|
||||||
|
(cryptoCurrencyEquivalence.getValue() / Math.pow(10, toCurrency.getPrecision()));
|
||||||
|
String equivalenceString = String.format(
|
||||||
|
"%.2f",
|
||||||
|
equivalentValue
|
||||||
|
);
|
||||||
|
|
||||||
|
cryptoNetBalanceViewHolder.setEquivalentBalance(balance,equivalentValue);
|
||||||
|
cryptoCoinBalanceEquivalence.setText(
|
||||||
|
equivalenceString + " " + toCurrency.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,6 +16,7 @@ import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
|
@ -48,11 +49,18 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
||||||
*/
|
*/
|
||||||
TextView cryptoNetName;
|
TextView cryptoNetName;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the view holding the equivalent total of the crypto net user account
|
||||||
|
*/
|
||||||
|
TextView cryptoNetEquivalentTotal;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The list view of the crypto coins balances of this crypto net balance
|
* The list view of the crypto coins balances of this crypto net balance
|
||||||
*/
|
*/
|
||||||
CryptoCoinBalanceListView cryptoCoinBalanceListView;
|
CryptoCoinBalanceListView cryptoCoinBalanceListView;
|
||||||
|
|
||||||
|
HashMap<CryptoCoinBalance, Double> equivalentTotalHashMap;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The button for sending transactions from this crypto net balance account
|
* The button for sending transactions from this crypto net balance account
|
||||||
*/
|
*/
|
||||||
|
@ -86,6 +94,7 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
||||||
//TODO: use ButterKnife to load the views
|
//TODO: use ButterKnife to load the views
|
||||||
cryptoNetIcon = (ImageView) itemView.findViewById(R.id.ivCryptoNetIcon);
|
cryptoNetIcon = (ImageView) itemView.findViewById(R.id.ivCryptoNetIcon);
|
||||||
cryptoNetName = (TextView) itemView.findViewById(R.id.tvCryptoNetName);
|
cryptoNetName = (TextView) itemView.findViewById(R.id.tvCryptoNetName);
|
||||||
|
cryptoNetEquivalentTotal = (TextView) itemView.findViewById(R.id.tvCryptoNetEquivalentTotal);
|
||||||
cryptoCoinBalanceListView = (CryptoCoinBalanceListView) itemView.findViewById(R.id.cryptoCoinBalancesListView);
|
cryptoCoinBalanceListView = (CryptoCoinBalanceListView) itemView.findViewById(R.id.cryptoCoinBalancesListView);
|
||||||
btnSendFromThisAccount = (Button) itemView.findViewById(R.id.btnSendFromThisAccount);
|
btnSendFromThisAccount = (Button) itemView.findViewById(R.id.btnSendFromThisAccount);
|
||||||
btnReceiveToThisAccount = (Button) itemView.findViewById(R.id.btnReceiveWithThisAccount);
|
btnReceiveToThisAccount = (Button) itemView.findViewById(R.id.btnReceiveWithThisAccount);
|
||||||
|
@ -157,6 +166,23 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
||||||
newFragment.show(ft, "ReceiveDialog");
|
newFragment.show(ft, "ReceiveDialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEquivalentBalance(CryptoCoinBalance cryptoCoinBalance, double equivalentValue){
|
||||||
|
if (this.equivalentTotalHashMap == null){
|
||||||
|
this.equivalentTotalHashMap = new HashMap<CryptoCoinBalance, Double>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cryptoCoinBalance != null) {
|
||||||
|
this.equivalentTotalHashMap.put(cryptoCoinBalance, equivalentValue);
|
||||||
|
float totalEquivalent = 0;
|
||||||
|
|
||||||
|
for (Double nextEquivalent : this.equivalentTotalHashMap.values()){
|
||||||
|
totalEquivalent += nextEquivalent;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cryptoNetEquivalentTotal.setText(""+totalEquivalent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Binds this view with the data of an element of the list
|
* Binds this view with the data of an element of the list
|
||||||
*/
|
*/
|
||||||
|
@ -164,6 +190,7 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
||||||
if (balance == null){
|
if (balance == null){
|
||||||
cryptoNetName.setText("loading...");
|
cryptoNetName.setText("loading...");
|
||||||
} else {
|
} else {
|
||||||
|
final CryptoNetBalanceViewHolder thisViewHolder = this;
|
||||||
this.cryptoNetAccountId = balance.getAccountId();
|
this.cryptoNetAccountId = balance.getAccountId();
|
||||||
cryptoNetName.setText(balance.getCryptoNet().getLabel());
|
cryptoNetName.setText(balance.getCryptoNet().getLabel());
|
||||||
|
|
||||||
|
@ -172,13 +199,15 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
||||||
cryptoCoinBalanceListViewModel.init(balance.getAccountId());
|
cryptoCoinBalanceListViewModel.init(balance.getAccountId());
|
||||||
LiveData<List<CryptoCoinBalance>> cryptoCoinBalanceData = cryptoCoinBalanceListViewModel.getCryptoCoinBalanceList();
|
LiveData<List<CryptoCoinBalance>> cryptoCoinBalanceData = cryptoCoinBalanceListViewModel.getCryptoCoinBalanceList();
|
||||||
|
|
||||||
cryptoCoinBalanceListView.setData(null);
|
cryptoCoinBalanceListView.setData(null, this);
|
||||||
|
|
||||||
//Observes the livedata, so any of its changes on the database will be reloaded here
|
//Observes the livedata, so any of its changes on the database will be reloaded here
|
||||||
cryptoCoinBalanceData.observe((LifecycleOwner)this.itemView.getContext(), new Observer<List<CryptoCoinBalance>>() {
|
cryptoCoinBalanceData.observe((LifecycleOwner)this.itemView.getContext(), new Observer<List<CryptoCoinBalance>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onChanged(List<CryptoCoinBalance> cryptoCoinBalances) {
|
public void onChanged(List<CryptoCoinBalance> cryptoCoinBalances) {
|
||||||
cryptoCoinBalanceListView.setData(cryptoCoinBalances);
|
cryptoCoinBalanceListView.setData(cryptoCoinBalances, thisViewHolder);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,30 @@
|
||||||
package cy.agorise.crystalwallet.views;
|
package cy.agorise.crystalwallet.views;
|
||||||
|
|
||||||
import android.arch.lifecycle.LifecycleOwner;
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
import android.arch.lifecycle.ViewModelProviders;
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import cy.agorise.crystalwallet.R;
|
import cy.agorise.crystalwallet.R;
|
||||||
import cy.agorise.crystalwallet.activities.CryptoCoinTransactionReceiptActivity;
|
import cy.agorise.crystalwallet.activities.CryptoCoinTransactionReceiptActivity;
|
||||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||||
import cy.agorise.crystalwallet.models.CryptoCurrency;
|
import cy.agorise.crystalwallet.models.CryptoCurrency;
|
||||||
|
import cy.agorise.crystalwallet.models.CryptoNetAccount;
|
||||||
import cy.agorise.crystalwallet.viewmodels.CryptoCurrencyViewModel;
|
import cy.agorise.crystalwallet.viewmodels.CryptoCurrencyViewModel;
|
||||||
|
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountViewModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Henry Varona on 17/9/2017.
|
* Created by Henry Varona on 17/9/2017.
|
||||||
|
@ -26,16 +36,18 @@ public class TransactionViewHolder extends RecyclerView.ViewHolder {
|
||||||
/*
|
/*
|
||||||
* The view holding the transaction "from"
|
* The view holding the transaction "from"
|
||||||
*/
|
*/
|
||||||
private TextView transactionFrom;
|
private TextView tvFrom;
|
||||||
/*
|
/*
|
||||||
* The view holding the transaction "to"
|
* The view holding the transaction "to"
|
||||||
*/
|
*/
|
||||||
private TextView transactionTo;
|
private TextView tvTo;
|
||||||
/*
|
/*
|
||||||
* The view holding the transaction amount
|
* The view holding the transaction amount
|
||||||
*/
|
*/
|
||||||
private TextView transactionAmount;
|
private TextView tvAmount;
|
||||||
|
private TextView tvEquivalent;
|
||||||
private TextView tvTransactionDate;
|
private TextView tvTransactionDate;
|
||||||
|
private TextView tvTransactionHour;
|
||||||
private View rootView;
|
private View rootView;
|
||||||
|
|
||||||
private Fragment fragment;
|
private Fragment fragment;
|
||||||
|
@ -48,10 +60,12 @@ public class TransactionViewHolder extends RecyclerView.ViewHolder {
|
||||||
this.cryptoCoinTransactionId = -1;
|
this.cryptoCoinTransactionId = -1;
|
||||||
|
|
||||||
rootView = itemView.findViewById(R.id.rlTransactionItem);
|
rootView = itemView.findViewById(R.id.rlTransactionItem);
|
||||||
transactionFrom = (TextView) itemView.findViewById(R.id.fromText);
|
tvFrom = (TextView) itemView.findViewById(R.id.fromText);
|
||||||
transactionTo = (TextView) itemView.findViewById(R.id.toText);
|
tvTo = (TextView) itemView.findViewById(R.id.toText);
|
||||||
transactionAmount = (TextView) itemView.findViewById(R.id.amountText);
|
tvAmount = (TextView) itemView.findViewById(R.id.tvAmount);
|
||||||
|
tvEquivalent = (TextView) itemView.findViewById(R.id.tvEquivalent);
|
||||||
tvTransactionDate = (TextView) itemView.findViewById(R.id.tvTransactionDate);
|
tvTransactionDate = (TextView) itemView.findViewById(R.id.tvTransactionDate);
|
||||||
|
tvTransactionHour = (TextView) itemView.findViewById(R.id.tvTransactionHour);
|
||||||
this.fragment = fragment;
|
this.fragment = fragment;
|
||||||
|
|
||||||
rootView.setOnClickListener(new View.OnClickListener() {
|
rootView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@ -85,9 +99,12 @@ public class TransactionViewHolder extends RecyclerView.ViewHolder {
|
||||||
* Clears all info in this element view
|
* Clears all info in this element view
|
||||||
*/
|
*/
|
||||||
public void clear(){
|
public void clear(){
|
||||||
transactionFrom.setText("loading...");
|
tvFrom.setText("loading...");
|
||||||
transactionTo.setText("");
|
tvTo.setText("");
|
||||||
transactionAmount.setText("");
|
tvAmount.setText("");
|
||||||
|
tvEquivalent.setText("");
|
||||||
|
tvTransactionDate.setText("");
|
||||||
|
tvTransactionHour.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -95,28 +112,53 @@ public class TransactionViewHolder extends RecyclerView.ViewHolder {
|
||||||
*/
|
*/
|
||||||
public void bindTo(final CryptoCoinTransaction transaction/*, final OnTransactionClickListener listener*/) {
|
public void bindTo(final CryptoCoinTransaction transaction/*, final OnTransactionClickListener listener*/) {
|
||||||
if (transaction == null){
|
if (transaction == null){
|
||||||
transactionFrom.setText("loading...");
|
clear();
|
||||||
transactionTo.setText("");
|
|
||||||
transactionAmount.setText("");
|
|
||||||
} else {
|
} else {
|
||||||
this.cryptoCoinTransactionId = transaction.getId();
|
this.cryptoCoinTransactionId = transaction.getId();
|
||||||
CryptoCurrencyViewModel cryptoCurrencyViewModel = ViewModelProviders.of(this.fragment).get(CryptoCurrencyViewModel.class);
|
CryptoCurrencyViewModel cryptoCurrencyViewModel = ViewModelProviders.of(this.fragment).get(CryptoCurrencyViewModel.class);
|
||||||
CryptoCurrency cryptoCurrency = cryptoCurrencyViewModel.getCryptoCurrencyById(transaction.getIdCurrency());
|
CryptoCurrency cryptoCurrency = cryptoCurrencyViewModel.getCryptoCurrencyById(transaction.getIdCurrency());
|
||||||
|
CryptoNetAccountViewModel cryptoNetAccountViewModel = ViewModelProviders.of(this.fragment).get(CryptoNetAccountViewModel.class);
|
||||||
|
cryptoNetAccountViewModel.loadCryptoNetAccount(transaction.getAccountId());
|
||||||
|
|
||||||
String amountString = String.format("%.2f",transaction.getAmount()/Math.pow(10,cryptoCurrency.getPrecision()));
|
String amountString = String.format("%.2f",transaction.getAmount()/Math.pow(10,cryptoCurrency.getPrecision()));
|
||||||
|
|
||||||
tvTransactionDate.setText(transaction.getDate().toString());
|
DateFormat dateFormat = new SimpleDateFormat("dd MMM");
|
||||||
transactionFrom.setText(transaction.getFrom());
|
dateFormat.setTimeZone(TimeZone.getTimeZone("cet"));
|
||||||
transactionTo.setText(transaction.getTo());
|
DateFormat hourFormat = new SimpleDateFormat("HH:mm:ss");
|
||||||
|
hourFormat.setTimeZone(TimeZone.getTimeZone("cet"));
|
||||||
|
|
||||||
|
tvTransactionDate.setText(dateFormat.format(transaction.getDate()));
|
||||||
|
tvTransactionHour.setText(hourFormat.format(transaction.getDate())+" CET");
|
||||||
|
|
||||||
|
tvFrom.setText(transaction.getFrom());
|
||||||
|
tvTo.setText(transaction.getTo());
|
||||||
|
|
||||||
|
LiveData<CryptoNetAccount> cryptoNetAccountLiveData = cryptoNetAccountViewModel.getCryptoNetAccount();
|
||||||
|
|
||||||
|
cryptoNetAccountLiveData.observe(this.fragment, new Observer<CryptoNetAccount>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable CryptoNetAccount cryptoNetAccount) {
|
||||||
|
if (transaction.getInput()){
|
||||||
|
tvTo.setText(cryptoNetAccount.getName());
|
||||||
|
} else {
|
||||||
|
tvFrom.setText(cryptoNetAccount.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
String finalAmountText = "";
|
||||||
if (transaction.getInput()) {
|
if (transaction.getInput()) {
|
||||||
transactionAmount.setTextColor(itemView.getContext().getResources().getColor(R.color.green));
|
tvAmount.setTextColor(itemView.getContext().getResources().getColor(R.color.green));
|
||||||
|
finalAmountText = "+ "+amountString
|
||||||
|
+ " "
|
||||||
|
+ cryptoCurrency.getName();
|
||||||
} else {
|
} else {
|
||||||
transactionAmount.setTextColor(itemView.getContext().getResources().getColor(R.color.red));
|
tvAmount.setTextColor(itemView.getContext().getResources().getColor(R.color.red));
|
||||||
|
finalAmountText = amountString
|
||||||
|
+ " "
|
||||||
|
+ cryptoCurrency.getName();
|
||||||
}
|
}
|
||||||
transactionAmount.setText(
|
tvAmount.setText(finalAmountText);
|
||||||
amountString
|
|
||||||
+ " "
|
|
||||||
+ cryptoCurrency.getName());
|
|
||||||
//This will load the transaction receipt when the user clicks this view
|
//This will load the transaction receipt when the user clicks this view
|
||||||
/*itemView.setOnClickListener(new View.OnClickListener() {
|
/*itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<stroke android:color="#5FBD8A" android:width="4dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:left="3dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
174
app/src/main/res/layout/activity_create_contact.xml
Normal file
174
app/src/main/res/layout/activity_create_contact.xml
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="0dp"
|
||||||
|
android:paddingLeft="0dp"
|
||||||
|
android:paddingRight="0dp"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="Contact Name"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:background="@drawable/edittext_bg"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/black" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvNameError"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/red" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="Email"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:background="@drawable/edittext_bg"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/black" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEmailError"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:maxLines="1"
|
||||||
|
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
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnCancel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:background="@color/pink"
|
||||||
|
android:text="@string/cancel"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnCreate"
|
||||||
|
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="Create Contact"
|
||||||
|
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
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/black"></LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="35dp"
|
||||||
|
android:background="@color/bottomBarColor"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAppVersion_brain_key_activity"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/v_1_0_beta" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvBlockNumberHead_brain_key_activity"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/block_number" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivSocketConnected_brain_key_activity"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="0.5" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="0.5"
|
||||||
|
android:src="@drawable/icon_setting"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
28
app/src/main/res/layout/activity_pin_request.xml
Normal file
28
app/src/main/res/layout/activity_pin_request.xml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:background="@color/colorPrimary">
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="30dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:text="Enter Pin:"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="numberPassword" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
|
@ -14,7 +14,7 @@
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentTop="true">
|
android:layout_alignParentTop="true">
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
android:id="@+id/cryptoNetBalanceTitleBarLayout"
|
android:id="@+id/cryptoNetBalanceTitleBarLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -31,20 +31,30 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:ems="10"
|
android:ems="10"
|
||||||
|
android:layout_toRightOf="@id/ivCryptoNetIcon"
|
||||||
android:text="unknown coin" />
|
android:text="unknown coin" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCryptoNetEquivalentTotal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:text="0.003€" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btnSendFromThisAccount"
|
android:id="@+id/btnSendFromThisAccount"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="send"/>
|
android:text="send"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btnReceiveWithThisAccount"
|
android:id="@+id/btnReceiveWithThisAccount"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="receive"/>
|
android:text="receive"
|
||||||
</LinearLayout>
|
android:visibility="gone" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<cy.agorise.crystalwallet.views.CryptoCoinBalanceListView
|
<cy.agorise.crystalwallet.views.CryptoCoinBalanceListView
|
||||||
android:id="@+id/cryptoCoinBalancesListView"
|
android:id="@+id/cryptoCoinBalancesListView"
|
||||||
|
|
30
app/src/main/res/layout/contact_address_list_item.xml
Normal file
30
app/src/main/res/layout/contact_address_list_item.xml
Normal 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>
|
|
@ -34,6 +34,14 @@
|
||||||
android:layout_below="@+id/tvContactName"
|
android:layout_below="@+id/tvContactName"
|
||||||
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"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<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>
|
39
app/src/main/res/layout/contact_selection_list_item.xml
Normal file
39
app/src/main/res/layout/contact_selection_list_item.xml
Normal 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>
|
|
@ -56,9 +56,9 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/tvTaxableCountry"
|
app:layout_constraintEnd_toEndOf="@id/spBackupAsset"
|
||||||
app:layout_constraintStart_toStartOf="@id/spBackupAsset"
|
app:layout_constraintStart_toStartOf="@id/spBackupAsset"
|
||||||
app:layout_constraintEnd_toEndOf="@id/spBackupAsset"/>
|
app:layout_constraintTop_toBottomOf="@+id/tvTaxableCountry" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/vTaxableCountry"
|
android:id="@+id/vTaxableCountry"
|
||||||
|
|
|
@ -28,6 +28,13 @@
|
||||||
app:layout_constraintTop_toBottomOf="@+id/tvCurrentPin"
|
app:layout_constraintTop_toBottomOf="@+id/tvCurrentPin"
|
||||||
tools:ignore="LabelFor" />
|
tools:ignore="LabelFor" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCurrentPinError"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/red"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/etCurrentPin" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/etNewPin"
|
android:id="@+id/etNewPin"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -39,7 +46,13 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/etCurrentPin" />
|
app:layout_constraintTop_toBottomOf="@+id/tvCurrentPinError" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvNewPinError"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/red"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/etNewPin" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/etConfirmPin"
|
android:id="@+id/etConfirmPin"
|
||||||
|
@ -52,6 +65,11 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/etNewPin" />
|
app:layout_constraintTop_toBottomOf="@+id/tvNewPinError" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvConfirmPinError"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/red"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/etConfirmPin" />
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
|
@ -4,9 +4,22 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="cy.agorise.crystalwallet.fragments.TransactionsFragment">
|
tools:context="cy.agorise.crystalwallet.fragments.TransactionsFragment">
|
||||||
|
|
||||||
<cy.agorise.crystalwallet.views.TransactionListView
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:id="@+id/vTransactionListView" />
|
|
||||||
|
|
||||||
|
<!--<TextView
|
||||||
|
android:id="@+id/tvTransactionSearch"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android: />
|
||||||
|
<Spinner
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"></Spinner>
|
||||||
|
-->
|
||||||
|
<cy.agorise.crystalwallet.views.TransactionListView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/vTransactionListView" />
|
||||||
|
</RelativeLayout>
|
||||||
</android.support.v4.widget.NestedScrollView>
|
</android.support.v4.widget.NestedScrollView>
|
||||||
|
|
|
@ -1,59 +1,111 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
android:paddingLeft="10dp"
|
android:paddingLeft="10dp"
|
||||||
android:paddingRight="10dp"
|
android:paddingRight="10dp"
|
||||||
android:paddingTop="10dp">
|
android:paddingTop="5dp">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/rlTransactionItem"
|
android:id="@+id/rlTransactionItem"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentTop="true">
|
android:layout_alignParentTop="true"
|
||||||
|
android:background="@drawable/transaction_list_item_background">
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTransactionDate"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:ems="10"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="date" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/fromText"
|
android:id="@+id/fromText"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/tvTransactionDate"
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_toStartOf="@+id/ivArrowFromTo"
|
||||||
android:ems="10"
|
android:ems="10"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:text="from" />
|
android:text="from" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivArrowFromTo"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:tint="@color/black"
|
||||||
|
app:srcCompat="@drawable/ic_arrow_forward" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/toText"
|
android:id="@+id/toText"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/tvTransactionDate"
|
|
||||||
android:layout_alignParentBottom="false"
|
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_toEndOf="@+id/ivArrowFromTo"
|
||||||
android:ems="10"
|
android:ems="10"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:text="to"
|
android:text="to"
|
||||||
android:textAlignment="textEnd" />
|
android:textAlignment="textEnd" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:id="@+id/sAfterFromTo"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/fromText"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/amountText"
|
android:id="@+id/tvTransactionDate"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/sAfterFromTo"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_toStartOf="@+id/ivArrowFromTo"
|
||||||
|
android:ems="10"
|
||||||
|
android:text="02 Oct"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTransactionHour"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/tvTransactionDate"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_toStartOf="@+id/ivArrowFromTo"
|
||||||
|
android:ems="10"
|
||||||
|
android:text="15:01:18 CET" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAmount"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignWithParentIfMissing="false"
|
android:layout_alignWithParentIfMissing="false"
|
||||||
android:layout_below="@+id/fromText"
|
android:layout_below="@id/sAfterFromTo"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_toEndOf="@+id/ivArrowFromTo"
|
||||||
android:ems="10"
|
android:ems="10"
|
||||||
android:gravity="center"
|
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:text="amount" />
|
android:text="+ 1 BTS"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEquivalent"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignWithParentIfMissing="false"
|
||||||
|
android:layout_below="@id/tvAmount"
|
||||||
|
android:layout_toEndOf="@+id/ivArrowFromTo"
|
||||||
|
android:ems="10"
|
||||||
|
android:inputType="text"
|
||||||
|
android:text="0.005€"
|
||||||
|
android:textAlignment="textEnd" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
Loading…
Reference in a new issue