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.persistence.room:compiler:1.0.0'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
||||
|
||||
compile 'com.squareup.picasso:picasso:2.5.2'
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "a44ccb96c8213951403ed2a283fb3367",
|
||||
"identityHash": "22cb2a56b28a9f7088ec98d6a72f9f67",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "account_seed",
|
||||
|
@ -235,7 +235,7 @@
|
|||
},
|
||||
{
|
||||
"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": [
|
||||
{
|
||||
"fieldPath": "mId",
|
||||
|
@ -249,6 +249,12 @@
|
|||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mEmail",
|
||||
"columnName": "email",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mGravatar",
|
||||
"columnName": "gravatar",
|
||||
|
@ -278,6 +284,70 @@
|
|||
"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": []
|
||||
|
@ -622,7 +692,7 @@
|
|||
],
|
||||
"setupQueries": [
|
||||
"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"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cy.agorise.crystalwallet">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:name="cy.agorise.crystalwallet.application.CrystalApplication"
|
||||
android:name=".application.CrystalApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="Crystal"
|
||||
|
@ -21,7 +22,7 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<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 android:name=".activities.AccountSeedsManagementActivity" >
|
||||
</activity>
|
||||
|
@ -37,20 +38,27 @@
|
|||
</activity>
|
||||
<activity android:name=".activities.BackupSeedActivity" >
|
||||
</activity>
|
||||
<activity android:name=".activities.SettingsActivity"
|
||||
<activity android:name=".activities.PinRequestActivity">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.SettingsActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
</activity>
|
||||
<activity android:name=".activities.AccountsActivity"
|
||||
android:theme="@style/ActivityDialog"
|
||||
android:parentActivityName=".activities.BoardActivity" >
|
||||
<activity
|
||||
android:name=".activities.AccountsActivity"
|
||||
android:parentActivityName=".activities.BoardActivity"
|
||||
android:theme="@style/ActivityDialog">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.BoardActivity" />
|
||||
</activity>
|
||||
|
||||
<service android:name=".service.CrystalWalletService"
|
||||
<service
|
||||
android:name=".service.CrystalWalletService"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name=".activities.CreateContactActivity"></activity>
|
||||
</application>
|
||||
|
||||
</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
|
||||
*/
|
||||
|
@ -215,8 +221,16 @@ public class BoardActivity extends AppCompatActivity {
|
|||
}
|
||||
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.
|
||||
ReceiveTransactionFragment newFragment = ReceiveTransactionFragment.newInstance(this.cryptoNetAccountId);
|
||||
ReceiveTransactionFragment newFragment = ReceiveTransactionFragment.newInstance(receiveCryptoNetAccountId);
|
||||
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;
|
||||
|
||||
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.paging.PagedList;
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
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.RandomSeedGenerator;
|
||||
import cy.agorise.crystalwallet.randomdatagenerators.RandomTransactionsGenerator;
|
||||
import cy.agorise.crystalwallet.application.CrystalSecurityMonitor;
|
||||
import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel;
|
||||
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
|
||||
import cy.agorise.crystalwallet.views.TransactionListView;
|
||||
|
||||
import static cy.agorise.crystalwallet.R.string.transactions;
|
||||
|
||||
public class IntroActivity extends AppCompatActivity {
|
||||
|
||||
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
|
||||
/*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
|
||||
* @return The bitshares id of the registered account, or null
|
||||
*/
|
||||
public static boolean registerBitsharesAccount(String accountName, String ownerKey,
|
||||
String activeKey, String memoKey, String url){
|
||||
public static void registerBitsharesAccount(String accountName, String ownerKey,
|
||||
String activeKey, String memoKey, String url,
|
||||
final ApiRequest request){
|
||||
CreateAccountPetition petition = new CreateAccountPetition();
|
||||
final Account account = new Account();
|
||||
account.name=accountName;
|
||||
|
@ -62,8 +63,7 @@ public abstract class BitsharesFaucetApiGenerator {
|
|||
|
||||
HashMap<String, HashMap> hashMap = new HashMap<>();
|
||||
hashMap.put("account", hm);
|
||||
final boolean[] answer = {false};
|
||||
final Object SYNC = new Object();
|
||||
|
||||
try {
|
||||
ServiceGenerator sg = new ServiceGenerator(url);
|
||||
IWebService service = sg.getService(IWebService.class);
|
||||
|
@ -78,56 +78,36 @@ public abstract class BitsharesFaucetApiGenerator {
|
|||
if (resp.account != null) {
|
||||
try {
|
||||
if(resp.account.name.equals(account.name)) {
|
||||
synchronized (SYNC){
|
||||
answer[0] = true;
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
request.getListener().success(true,request.getId());
|
||||
}else{
|
||||
System.out.println("ERROR account name different" + resp.account.name);
|
||||
//ERROR
|
||||
synchronized (SYNC) {
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
synchronized (SYNC) {
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}else{
|
||||
System.out.println("ERROR response doesn't have account " + response.message());
|
||||
//ERROR
|
||||
synchronized (SYNC) {
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
request.getListener().fail(request.getId());
|
||||
|
||||
}
|
||||
}else{
|
||||
System.out.println("ERROR fetching info");
|
||||
//ERROR
|
||||
synchronized (SYNC) {
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<RegisterAccountResponse> call, Throwable t) {
|
||||
t.printStackTrace();
|
||||
synchronized (SYNC) {
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
});
|
||||
synchronized (SYNC) {
|
||||
SYNC.wait(60000);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
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.CryptoCurrencyDao;
|
||||
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
||||
import cy.agorise.crystalwallet.dao.TransactionDao;
|
||||
import cy.agorise.crystalwallet.manager.BitsharesAccountManager;
|
||||
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||
import cy.agorise.crystalwallet.models.BitsharesAsset;
|
||||
import cy.agorise.crystalwallet.models.BitsharesAssetInfo;
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinBalance;
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||
import cy.agorise.crystalwallet.models.CryptoCurrency;
|
||||
import cy.agorise.crystalwallet.models.CryptoCurrencyEquivalence;
|
||||
import cy.agorise.crystalwallet.network.CryptoNetManager;
|
||||
import cy.agorise.crystalwallet.network.WebSocketThread;
|
||||
import cy.agorise.graphenej.Address;
|
||||
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.SubscriptionListener;
|
||||
import cy.agorise.graphenej.interfaces.WitnessResponseListener;
|
||||
import cy.agorise.graphenej.models.AccountBalanceUpdate;
|
||||
import cy.agorise.graphenej.models.AccountProperties;
|
||||
import cy.agorise.graphenej.models.BaseResponse;
|
||||
import cy.agorise.graphenej.models.BroadcastedTransaction;
|
||||
import cy.agorise.graphenej.models.HistoricalTransfer;
|
||||
import cy.agorise.graphenej.models.SubscriptionResponse;
|
||||
import cy.agorise.graphenej.models.WitnessResponse;
|
||||
import cy.agorise.graphenej.operations.TransferOperation;
|
||||
|
@ -62,12 +60,8 @@ public abstract class GrapheneApiGenerator {
|
|||
|
||||
//TODO network connections
|
||||
//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";
|
||||
private static String equivalentUrl = "http://185.208.208.147:8090";
|
||||
//public static String url = "wss://bitshares.openledger.info/ws";
|
||||
//private static Str ing equivalentUrl = "wss://bitshares.openledger.info/ws";
|
||||
|
||||
private static String equivalentUrl = "wss://bitshares.openledger.info/ws";
|
||||
|
||||
// The message broker for bitshares
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
@ -114,7 +108,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
@ -142,7 +136,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
|
||||
thread.start();
|
||||
}
|
||||
|
@ -169,7 +163,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
@ -196,7 +190,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
@ -223,7 +217,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
@ -247,7 +241,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
@ -292,7 +286,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
@ -340,7 +334,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
@ -353,12 +347,10 @@ public abstract class GrapheneApiGenerator {
|
|||
*/
|
||||
public static void subscribeBitsharesAccount(final long accountId, final String accountBitsharesId,
|
||||
final Context context){
|
||||
System.out.println("GrapheneAPI subscribe to account balance update");
|
||||
if(!currentBitsharesListener.containsKey(accountId)){
|
||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||
final BitsharesAssetDao bitsharesAssetDao = db.bitsharesAssetDao();
|
||||
final CryptoCurrencyDao cryptoCurrencyDao = db.cryptoCurrencyDao();
|
||||
final TransactionDao transactionDao = db.transactionDao();
|
||||
SubscriptionListener balanceListener = new SubscriptionListener() {
|
||||
@Override
|
||||
public ObjectType getInterestObjectType() {
|
||||
|
@ -374,16 +366,15 @@ public abstract class GrapheneApiGenerator {
|
|||
BroadcastedTransaction transactionUpdate = (BroadcastedTransaction) update;
|
||||
for(BaseOperation operation : transactionUpdate.getTransaction().getOperations()){
|
||||
if(operation instanceof TransferOperation){
|
||||
TransferOperation tOperation = (TransferOperation) operation;
|
||||
final TransferOperation tOperation = (TransferOperation) operation;
|
||||
if(tOperation.getFrom().getObjectId().equals(accountBitsharesId) || tOperation.getTo().getObjectId().equals(accountBitsharesId)){
|
||||
GrapheneApiGenerator.getAccountBalance(accountId,accountBitsharesId,context);
|
||||
CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
||||
final CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
||||
transaction.setAccountId(accountId);
|
||||
transaction.setAmount(tOperation.getAssetAmount().getAmount().longValue());
|
||||
BitsharesAssetInfo info = bitsharesAssetDao.getBitsharesAssetInfoById(tOperation.getAssetAmount().getAsset().getObjectId());
|
||||
if (info == null) {
|
||||
//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() {
|
||||
@Override
|
||||
public void success(Object answer, int idPetition) {
|
||||
|
@ -394,40 +385,21 @@ public abstract class GrapheneApiGenerator {
|
|||
info.setCryptoCurrencyId(idCryptoCurrency);
|
||||
asset.setId((int)idCryptoCurrency);
|
||||
bitsharesAssetDao.insertBitsharesAssetInfo(info);
|
||||
}
|
||||
synchronized (SYNC){
|
||||
SYNC.notifyAll();
|
||||
saveTransaction(transaction,(int)info.getCryptoCurrencyId(),accountBitsharesId,tOperation,context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail(int idPetition) {
|
||||
synchronized (SYNC){
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
//TODO error retrieving asset
|
||||
}
|
||||
});
|
||||
ArrayList<String> assets = new ArrayList<>();
|
||||
assets.add(tOperation.getAssetAmount().getAsset().getObjectId());
|
||||
GrapheneApiGenerator.getAssetById(assets,assetRequest);
|
||||
|
||||
synchronized (SYNC){
|
||||
try {SYNC.wait(60000);} catch (InterruptedException ignore) {}
|
||||
}else{
|
||||
saveTransaction(transaction,(int)info.getCryptoCurrencyId(),accountBitsharesId,tOperation,context);
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
@ -515,7 +507,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
|
||||
thread.start();
|
||||
|
||||
|
@ -542,7 +534,7 @@ public abstract class GrapheneApiGenerator {
|
|||
public void onError(BaseResponse.Error error) {
|
||||
request.getListener().fail(request.getId());
|
||||
}
|
||||
}),url);
|
||||
}),CryptoNetManager.getURL(CryptoNet.BITSHARES));
|
||||
thread.start();
|
||||
|
||||
}
|
||||
|
@ -674,7 +666,7 @@ public abstract class GrapheneApiGenerator {
|
|||
Converter converter = new Converter();
|
||||
order.getSellPrice().base.getAsset().setPrecision(baseAsset.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());
|
||||
CrystalDatabase.getAppDatabase(context).cryptoCurrencyEquivalenceDao().insertCryptoCurrencyEquivalence(equivalence);
|
||||
break;
|
||||
|
|
|
@ -6,6 +6,11 @@ import android.content.Intent;
|
|||
import com.idescout.sql.SqlScoutServer;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -15,6 +20,25 @@ import cy.agorise.crystalwallet.service.CrystalWalletService;
|
|||
*/
|
||||
|
||||
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
|
||||
public void onCreate() {
|
||||
|
@ -24,6 +48,36 @@ public class CrystalApplication extends Application {
|
|||
CrystalDatabase db = CrystalDatabase.getAppDatabase(this.getApplicationContext());
|
||||
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);
|
||||
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.paging.LivePagedListProvider;
|
||||
import android.arch.persistence.room.Dao;
|
||||
import android.arch.persistence.room.Delete;
|
||||
import android.arch.persistence.room.Insert;
|
||||
import android.arch.persistence.room.OnConflictStrategy;
|
||||
import android.arch.persistence.room.Query;
|
||||
import android.arch.persistence.room.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cy.agorise.crystalwallet.models.Contact;
|
||||
import cy.agorise.crystalwallet.models.ContactAddress;
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||
|
||||
/**
|
||||
|
@ -24,6 +27,33 @@ public interface ContactDao {
|
|||
@Query("SELECT * FROM contact ORDER BY name ASC")
|
||||
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")
|
||||
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;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.persistence.room.Dao;
|
||||
import android.arch.persistence.room.Insert;
|
||||
import android.arch.persistence.room.OnConflictStrategy;
|
||||
|
@ -28,6 +29,9 @@ public interface CryptoCurrencyDao {
|
|||
@Query("SELECT * FROM crypto_currency WHERE id IN (: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")
|
||||
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.BitsharesAssetInfo;
|
||||
import cy.agorise.crystalwallet.models.Contact;
|
||||
import cy.agorise.crystalwallet.models.ContactAddress;
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinBalance;
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||
import cy.agorise.crystalwallet.models.CryptoCurrency;
|
||||
|
@ -28,6 +29,7 @@ import cy.agorise.crystalwallet.models.GrapheneAccountInfo;
|
|||
CryptoNetAccount.class,
|
||||
CryptoCoinTransaction.class,
|
||||
Contact.class,
|
||||
ContactAddress.class,
|
||||
CryptoCurrency.class,
|
||||
CryptoCoinBalance.class,
|
||||
GrapheneAccountInfo.class,
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.arch.persistence.room.Insert;
|
|||
import android.arch.persistence.room.OnConflictStrategy;
|
||||
import android.arch.persistence.room.Query;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||
|
@ -32,6 +33,9 @@ public interface TransactionDao {
|
|||
@Query("SELECT * FROM crypto_coin_transaction WHERE id = :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)
|
||||
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;
|
||||
|
||||
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.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
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 {
|
||||
|
||||
@BindView(R.id.vContactListView)
|
||||
ContactListView contactListView;
|
||||
|
||||
public ContactsFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
@ -29,6 +43,20 @@ public class ContactsFragment extends Fragment {
|
|||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// 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;
|
||||
|
||||
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.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
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.OnItemSelected;
|
||||
import cy.agorise.crystalwallet.R;
|
||||
import cy.agorise.crystalwallet.models.GeneralSetting;
|
||||
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
|
||||
|
||||
/**
|
||||
* Created by xd on 12/28/17.
|
||||
*/
|
||||
|
||||
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() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
@ -37,6 +62,83 @@ public class GeneralSettingsFragment extends Fragment {
|
|||
View v = inflater.inflate(R.layout.fragment_general_settings, container, false);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
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.OnTextChanged;
|
||||
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.
|
||||
*/
|
||||
|
||||
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() {
|
||||
// Required empty public constructor
|
||||
|
@ -33,6 +74,140 @@ public class PinSecurityFragment extends Fragment {
|
|||
View v = inflater.inflate(R.layout.fragment_pin_security, container, false);
|
||||
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;
|
||||
}
|
||||
|
||||
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.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
|
@ -31,6 +32,8 @@ import com.google.zxing.WriterException;
|
|||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import butterknife.OnClick;
|
||||
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountListViewModel;
|
||||
import cy.agorise.crystalwallet.views.CryptoNetAccountAdapter;
|
||||
import cy.agorise.graphenej.Invoice;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -57,6 +60,8 @@ public class ReceiveTransactionFragment extends DialogFragment implements UIVali
|
|||
|
||||
ReceiveTransactionValidator receiveTransactionValidator;
|
||||
|
||||
@BindView(R.id.spTo)
|
||||
Spinner spTo;
|
||||
@BindView(R.id.etAmount)
|
||||
EditText etAmount;
|
||||
@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.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);
|
||||
|
@ -199,6 +210,11 @@ public class ReceiveTransactionFragment extends DialogFragment implements UIVali
|
|||
}, 400);
|
||||
}
|
||||
|
||||
@OnItemSelected(R.id.spTo)
|
||||
public void afterToSelected(Spinner spinner, int position) {
|
||||
this.receiveTransactionValidator.validate();
|
||||
}
|
||||
|
||||
@OnTextChanged(value = R.id.etAmount,
|
||||
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
|
||||
void afterAmountChanged(Editable editable) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.arch.lifecycle.LiveData;
|
|||
import android.arch.lifecycle.Observer;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
|
@ -12,6 +13,7 @@ import android.support.annotation.Nullable;
|
|||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.Editable;
|
||||
|
@ -23,13 +25,19 @@ import android.view.Window;
|
|||
import android.view.animation.LinearInterpolator;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.zxing.Result;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
@ -41,10 +49,13 @@ import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestListen
|
|||
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequests;
|
||||
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateBitsharesSendRequest;
|
||||
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.CryptoCurrency;
|
||||
import cy.agorise.crystalwallet.models.CryptoNetAccount;
|
||||
import cy.agorise.crystalwallet.models.GrapheneAccount;
|
||||
import cy.agorise.crystalwallet.viewmodels.ContactViewModel;
|
||||
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountListViewModel;
|
||||
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountViewModel;
|
||||
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.views.CryptoCurrencyAdapter;
|
||||
import cy.agorise.crystalwallet.views.CryptoNetAccountAdapter;
|
||||
import cy.agorise.graphenej.Invoice;
|
||||
import cy.agorise.graphenej.LineItem;
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||
|
||||
public class SendTransactionFragment extends DialogFragment implements UIValidatorListener, ZXingScannerView.ResultHandler {
|
||||
|
@ -82,6 +95,9 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
|
|||
FloatingActionButton btnSend;
|
||||
@BindView(R.id.btnCancel)
|
||||
TextView btnCancel;
|
||||
@BindView(R.id.ivPeople)
|
||||
ImageView ivPeople;
|
||||
CryptoCurrencyAdapter assetAdapter;
|
||||
|
||||
Button btnScanQrCode;
|
||||
|
||||
|
@ -145,7 +161,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
|
|||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
@ -222,6 +238,50 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
|
|||
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)
|
||||
public void cancel(){
|
||||
this.dismiss();
|
||||
|
@ -317,6 +377,27 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
|
|||
|
||||
@Override
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cy.agorise.crystalwallet.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
|
||||
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.BitsharesAssetInfo;
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||
import cy.agorise.crystalwallet.models.CryptoCurrency;
|
||||
import cy.agorise.crystalwallet.models.CryptoNetAccount;
|
||||
import cy.agorise.crystalwallet.models.GrapheneAccount;
|
||||
import cy.agorise.crystalwallet.models.GrapheneAccountInfo;
|
||||
import cy.agorise.crystalwallet.network.CryptoNetManager;
|
||||
import cy.agorise.graphenej.Address;
|
||||
import cy.agorise.graphenej.Asset;
|
||||
import cy.agorise.graphenej.AssetAmount;
|
||||
|
@ -54,20 +57,23 @@ import cy.agorise.graphenej.operations.TransferOperationBuilder;
|
|||
*/
|
||||
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
|
||||
public CryptoNetAccount createAccountFromSeed(CryptoNetAccount account, Context context) {
|
||||
public void createAccountFromSeed(CryptoNetAccount account, final ManagerRequest request, final Context context) {
|
||||
if(account instanceof GrapheneAccount) {
|
||||
|
||||
GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||
boolean created = BitsharesFaucetApiGenerator.registerBitsharesAccount(grapheneAccount.getName(),
|
||||
new Address(ECKey.fromPublicOnly(grapheneAccount.getOwnerKey(context).getPubKey())).toString(),
|
||||
new Address(ECKey.fromPublicOnly(grapheneAccount.getActiveKey(context).getPubKey())).toString(),
|
||||
new Address(ECKey.fromPublicOnly(grapheneAccount.getMemoKey(context).getPubKey())).toString(),GrapheneApiGenerator.faucetUrl);
|
||||
|
||||
if(created) {
|
||||
GrapheneAccount fetch = this.getAccountInfoByName(grapheneAccount.getName());
|
||||
final GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||
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());
|
||||
|
@ -76,82 +82,130 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
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;
|
||||
subscribeBitsharesAccount(fetch.getId(),fetch.getAccountId(),context);
|
||||
request.success(fetch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CryptoNetAccount importAccountFromSeed(CryptoNetAccount account, Context context) {
|
||||
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.getActiveKey(context).getPubKey())).toString(),
|
||||
new Address(ECKey.fromPublicOnly(grapheneAccount.getMemoKey(context).getPubKey())).toString(),
|
||||
GrapheneApiGenerator.faucetUrl, creationRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importAccountFromSeed(CryptoNetAccount account, final Context context) {
|
||||
|
||||
if(account instanceof GrapheneAccount) {
|
||||
GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||
final GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||
|
||||
if(grapheneAccount.getAccountId() == null){
|
||||
GrapheneAccount fetch = this.getAccountInfoByName(grapheneAccount.getName());
|
||||
if(fetch == null) {
|
||||
//TODO grapaheneAccount null, error fetching
|
||||
return null;
|
||||
}
|
||||
this.getAccountInfoByName(grapheneAccount.getName(), new ManagerRequest() {
|
||||
@Override
|
||||
public void success(Object answer) {
|
||||
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||
grapheneAccount.setAccountId(fetch.getAccountId());
|
||||
}else if(grapheneAccount.getName() == null){
|
||||
GrapheneAccount fetch = this.getAccountInfoById(grapheneAccount.getAccountId());
|
||||
if(fetch == null) {
|
||||
//TODO grapaheneAccount null, error fetching
|
||||
return null;
|
||||
}
|
||||
grapheneAccount.setName(fetch.getName());
|
||||
}
|
||||
|
||||
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;
|
||||
subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAccountFromDB(CryptoNetAccount account, Context context) {
|
||||
if(account instanceof GrapheneAccount){
|
||||
GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||
public void fail() {
|
||||
//TODO get account data fail
|
||||
}
|
||||
});
|
||||
|
||||
}else if(grapheneAccount.getName() == null){
|
||||
this.getAccountInfoById(grapheneAccount.getAccountId(), new ManagerRequest() {
|
||||
@Override
|
||||
public void success(Object answer) {
|
||||
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||
grapheneAccount.setName(fetch.getName());
|
||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||
GrapheneAccountInfo info = db.grapheneAccountInfoDao().getByAccountId(account.getId());
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAccountFromDB(CryptoNetAccount account, final Context context) {
|
||||
if(account instanceof GrapheneAccount){
|
||||
final GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
||||
final CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||
final GrapheneAccountInfo info = db.grapheneAccountInfoDao().getByAccountId(account.getId());
|
||||
grapheneAccount.loadInfo(info);
|
||||
if(grapheneAccount.getAccountId() == null){
|
||||
GrapheneAccount fetch = this.getAccountInfoByName(grapheneAccount.getName());
|
||||
if(fetch != null){
|
||||
this.getAccountInfoByName(grapheneAccount.getName(), new ManagerRequest() {
|
||||
@Override
|
||||
public void success(Object answer) {
|
||||
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||
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){
|
||||
GrapheneAccount fetch = this.getAccountInfoById(grapheneAccount.getAccountId());
|
||||
if(fetch != null) {
|
||||
this.getAccountInfoById(grapheneAccount.getAccountId(), new ManagerRequest() {
|
||||
@Override
|
||||
public void success(Object answer) {
|
||||
GrapheneAccount fetch = (GrapheneAccount) answer;
|
||||
info.setName(fetch.getName());
|
||||
grapheneAccount.setName(fetch.getName());
|
||||
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(info);
|
||||
subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail() {
|
||||
//TODO account data retrieve failed
|
||||
}
|
||||
});
|
||||
}else{
|
||||
subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(grapheneAccount.getName() == null || grapheneAccount.getAccountId() == null) {
|
||||
//TODO grapaheneAccount null, error fetching
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,6 +226,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
this.validateCreateAccount((ValidateCreateBitsharesAccountRequest) request);
|
||||
}else{
|
||||
//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) {
|
||||
AccountProperties prop = (AccountProperties) answer;
|
||||
//TODO change the way to compare keys
|
||||
|
||||
BrainKey bk = new BrainKey(importRequest.getMnemonic(), 0);
|
||||
System.out.println(bk.getPublicAddress("BTS").toString());
|
||||
for(PublicKey activeKey : prop.owner.getKeyAuthList()){
|
||||
|
@ -220,12 +274,13 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
GrapheneApiGenerator.getAccountIdByName(importRequest.getAccountName(),checkAccountName);
|
||||
}
|
||||
|
||||
private void validateCreateAccount(ValidateCreateBitsharesAccountRequest createRequest){
|
||||
private void validateCreateAccount(final ValidateCreateBitsharesAccountRequest createRequest){
|
||||
// Generate seed or find key
|
||||
Context context = createRequest.getContext();
|
||||
AccountSeed seed = AccountSeed.getAccountSeed(SeedType.BIP39, context);
|
||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
||||
long idSeed = db.accountSeedDao().insertAccountSeed(seed);
|
||||
assert seed != null;
|
||||
seed.setId(idSeed);
|
||||
seed.setName(createRequest.getAccountName());
|
||||
GrapheneAccount account = new GrapheneAccount();
|
||||
|
@ -233,12 +288,20 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
account.setSeedId(idSeed);
|
||||
account.setAccountIndex(0);
|
||||
account.setCryptoNet(CryptoNet.BITSHARES);
|
||||
GrapheneAccount answer =(GrapheneAccount) this.createAccountFromSeed(account,context);
|
||||
if (answer != null){
|
||||
this.createAccountFromSeed(account, new ManagerRequest() {
|
||||
|
||||
@Override
|
||||
public void success(Object answer) {
|
||||
createRequest.setAccountExists(false);
|
||||
createRequest.setAccount(answer);;
|
||||
createRequest.setAccount((GrapheneAccount) answer);
|
||||
}
|
||||
createRequest.setAccountExists(false);
|
||||
|
||||
@Override
|
||||
public void fail() {
|
||||
createRequest.setAccountExists(true);
|
||||
}
|
||||
}, context);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -272,12 +335,50 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
*/
|
||||
private void validateSendRequest(final ValidateBitsharesSendRequest sendRequest) {
|
||||
//TODO feeAsset
|
||||
String idAsset = getAssetInfoByName(sendRequest.getAsset());
|
||||
Asset feeAsset = new Asset(idAsset);
|
||||
UserAccount fromUserAccount =new UserAccount(sendRequest.getSourceAccount().getAccountId());
|
||||
CrystalDatabase db = CrystalDatabase.getAppDatabase(sendRequest.getContext());
|
||||
CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(sendRequest.getAsset(), CryptoNet.BITSHARES.name());
|
||||
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());
|
||||
//TODO bad user to user account
|
||||
@Override
|
||||
public void fail() {
|
||||
|
||||
}
|
||||
});
|
||||
}else{
|
||||
BitsharesAssetInfo info = db.bitsharesAssetDao().getBitsharesAssetInfo(currency.getId());
|
||||
if (info == null || info.getBitsharesId() == null || info.getBitsharesId().isEmpty()){
|
||||
getAssetInfoByName(sendRequest.getAsset(), new ManagerRequest() {
|
||||
@Override
|
||||
public void success(Object answer) {
|
||||
validateSendRequest(sendRequest, ((BitsharesAsset) answer).getBitsharesId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail() {
|
||||
|
||||
}
|
||||
});
|
||||
}else {
|
||||
this.validateSendRequest(sendRequest, info.getBitsharesId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateSendRequest(final ValidateBitsharesSendRequest sendRequest , final String idAsset){
|
||||
final Asset feeAsset = new Asset(idAsset);
|
||||
final UserAccount fromUserAccount =new UserAccount(sendRequest.getSourceAccount().getAccountId());
|
||||
|
||||
//TODO cached to accounts
|
||||
this.getAccountInfoByName(sendRequest.getToAccount(), new ManagerRequest() {
|
||||
|
||||
@Override
|
||||
public void success(Object answer) {
|
||||
GrapheneAccount toUserGrapheneAccount = (GrapheneAccount) answer;
|
||||
UserAccount toUserAccount = new UserAccount(toUserGrapheneAccount.getAccountId());
|
||||
TransferOperationBuilder builder = new TransferOperationBuilder()
|
||||
.setSource(fromUserAccount)
|
||||
|
@ -287,6 +388,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
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());
|
||||
|
@ -294,7 +396,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
ECKey privateKey = sendRequest.getSourceAccount().getActiveKey(sendRequest.getContext());
|
||||
|
||||
Transaction transaction = new Transaction(privateKey, null, operationList);
|
||||
transaction.setChainId(BITSHARES_TESTNET_CHAIN_ID);
|
||||
transaction.setChainId(CryptoNetManager.getChaindId(CryptoNet.BITSHARES));
|
||||
|
||||
ApiRequest transactionRequest = new ApiRequest(0, new ApiRequestListener() {
|
||||
@Override
|
||||
|
@ -311,80 +413,47 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
GrapheneApiGenerator.broadcastTransaction(transaction,feeAsset, transactionRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail() {
|
||||
//TODO bad user to user account
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the account info from a graphene id
|
||||
* @param grapheneId The graphene id of the account
|
||||
*/
|
||||
private GrapheneAccount getAccountInfoById(String grapheneId){
|
||||
final Object SYNC = new Object();
|
||||
long timeout = 60000;
|
||||
private void getAccountInfoById(String grapheneId, ManagerRequest request){
|
||||
|
||||
AccountIdOrNameListener listener = new AccountIdOrNameListener(SYNC);
|
||||
AccountIdOrNameListener listener = new AccountIdOrNameListener(request);
|
||||
|
||||
ApiRequest request = new ApiRequest(0, listener);
|
||||
GrapheneApiGenerator.getAccountById(grapheneId,request);
|
||||
|
||||
long cTime = System.currentTimeMillis();
|
||||
|
||||
while(!listener.ready && (System.currentTimeMillis()-cTime) < timeout){
|
||||
synchronized (SYNC){
|
||||
try {
|
||||
SYNC.wait(100);
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
return listener.account;
|
||||
ApiRequest accountRequest = new ApiRequest(0, listener);
|
||||
GrapheneApiGenerator.getAccountById(grapheneId,accountRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets account info by its name
|
||||
* @param grapheneName The name of the account to retrieve
|
||||
*/
|
||||
private GrapheneAccount getAccountInfoByName(String grapheneName){
|
||||
final Object SYNC = new Object();
|
||||
long timeout = 60000;
|
||||
private void getAccountInfoByName(String grapheneName, ManagerRequest request){
|
||||
|
||||
AccountIdOrNameListener listener = new AccountIdOrNameListener(SYNC);
|
||||
AccountIdOrNameListener listener = new AccountIdOrNameListener(request);
|
||||
|
||||
ApiRequest request = new ApiRequest(0, listener);
|
||||
GrapheneApiGenerator.getAccountByName(grapheneName,request);
|
||||
ApiRequest accountRequest = new ApiRequest(0, listener);
|
||||
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
|
||||
private String getAssetInfoByName(String assetName){
|
||||
final Object SYNC = new Object();
|
||||
long timeout = 60000;
|
||||
private void getAssetInfoByName(String assetName, ManagerRequest request){
|
||||
|
||||
AssetIdOrNameListener nameListener = new AssetIdOrNameListener(SYNC);
|
||||
ApiRequest request = new ApiRequest(0, nameListener);
|
||||
AssetIdOrNameListener nameListener = new AssetIdOrNameListener(request);
|
||||
ApiRequest assetRequest = new ApiRequest(0, nameListener);
|
||||
ArrayList<String> assetNames = new ArrayList<>();
|
||||
assetNames.add(assetName);
|
||||
GrapheneApiGenerator.getAssetByName(assetNames, request);
|
||||
|
||||
long cTime = System.currentTimeMillis();
|
||||
|
||||
while(!nameListener.ready && (System.currentTimeMillis()-cTime) < timeout){
|
||||
synchronized (SYNC){
|
||||
try {
|
||||
SYNC.wait(100);
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
return nameListener.asset.getBitsharesId();
|
||||
GrapheneApiGenerator.getAssetByName(assetNames, assetRequest);
|
||||
|
||||
}
|
||||
|
||||
|
@ -393,7 +462,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
* @param idAccount database id of the account
|
||||
* @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);
|
||||
List<CryptoCoinTransaction> transactions = db.transactionDao().getByIdAccount(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 idPetition the id of the ApiRequest petition
|
||||
*/
|
||||
@Override
|
||||
public void success(Object answer, int idPetition) {
|
||||
List<HistoricalTransfer> transfers = (List<HistoricalTransfer>) answer ;
|
||||
for(HistoricalTransfer transfer : transfers) {
|
||||
for(final HistoricalTransfer transfer : transfers) {
|
||||
if (transfer.getOperation() != null){
|
||||
CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
||||
final CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
||||
transaction.setAccountId(account.getId());
|
||||
transaction.setAmount(transfer.getOperation().getAssetAmount().getAmount().longValue());
|
||||
BitsharesAssetInfo info = db.bitsharesAssetDao().getBitsharesAssetInfoById(transfer.getOperation().getAssetAmount().getAsset().getObjectId());
|
||||
|
||||
if (info == null) {
|
||||
//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() {
|
||||
@Override
|
||||
public void success(Object answer, int idPetition) {
|
||||
|
@ -476,39 +544,24 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
info.setCryptoCurrencyId(idCryptoCurrency);
|
||||
asset.setId((int)idCryptoCurrency);
|
||||
db.bitsharesAssetDao().insertBitsharesAssetInfo(info);
|
||||
saveTransaction(transaction,info,transfer);
|
||||
}
|
||||
synchronized (SYNC){
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail(int idPetition) {
|
||||
synchronized (SYNC){
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
//TODO Error
|
||||
}
|
||||
});
|
||||
ArrayList<String> assets = new ArrayList<>();
|
||||
assets.add(transfer.getOperation().getAssetAmount().getAsset().getObjectId());
|
||||
GrapheneApiGenerator.getAssetById(assets,assetRequest);
|
||||
|
||||
synchronized (SYNC){
|
||||
try {SYNC.wait(60000);} catch (InterruptedException ignore) {}
|
||||
}else{
|
||||
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){
|
||||
|
@ -524,6 +577,16 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
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);
|
||||
}else{
|
||||
//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
|
||||
*/
|
||||
private class AccountIdOrNameListener implements ApiRequestListener{
|
||||
final Object SYNC;
|
||||
boolean ready = false;
|
||||
final ManagerRequest request;
|
||||
|
||||
GrapheneAccount account;
|
||||
|
||||
AccountIdOrNameListener(Object SYNC) {
|
||||
this.SYNC = SYNC;
|
||||
AccountIdOrNameListener(ManagerRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -572,18 +635,12 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
account.setName(props.name);
|
||||
}
|
||||
|
||||
synchronized (SYNC){
|
||||
ready = true;
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
request.success(account);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail(int idPetition) {
|
||||
synchronized (SYNC){
|
||||
ready = true;
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
request.fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
private class AssetIdOrNameListener implements ApiRequestListener{
|
||||
final Object SYNC;
|
||||
boolean ready = false;
|
||||
final ManagerRequest request;
|
||||
|
||||
BitsharesAsset asset;
|
||||
|
||||
AssetIdOrNameListener(Object SYNC) {
|
||||
this.SYNC = SYNC;
|
||||
AssetIdOrNameListener(ManagerRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void success(Object answer, int idPetition) {
|
||||
if(answer instanceof ArrayList) {
|
||||
|
||||
if (((ArrayList) answer).get(0) instanceof BitsharesAsset) {
|
||||
asset = (BitsharesAsset) ((ArrayList) answer).get(0);
|
||||
request.success(asset);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (SYNC){
|
||||
ready = true;
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail(int idPetition) {
|
||||
synchronized (SYNC){
|
||||
ready = true;
|
||||
SYNC.notifyAll();
|
||||
}
|
||||
//TODO fail asset retrieve
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -637,7 +685,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
*/
|
||||
TransactionDao transactionDao;
|
||||
|
||||
public GetTransactionDate(CryptoCoinTransaction transaction, TransactionDao transactionDao) {
|
||||
GetTransactionDate(CryptoCoinTransaction transaction, TransactionDao transactionDao) {
|
||||
this.transaction = transaction;
|
||||
this.transactionDao = transactionDao;
|
||||
}
|
||||
|
@ -645,11 +693,13 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
|
|||
@Override
|
||||
public void success(Object answer, int idPetition) {
|
||||
if(answer instanceof BlockHeader){
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
@SuppressLint("SimpleDateFormat") SimpleDateFormat dateFormat = new SimpleDateFormat(SIMPLE_DATE_FORMAT);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(DEFAULT_TIME_ZONE));
|
||||
try {
|
||||
transaction.setDate(dateFormat.parse(((BlockHeader) answer).timestamp));
|
||||
if (transactionDao.getByTransaction(transaction.getDate(),transaction.getFrom(),transaction.getTo(),transaction.getAmount()) == null) {
|
||||
transactionDao.insertTransaction(transaction);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -18,14 +18,14 @@ public interface CryptoAccountManager {
|
|||
* @param account The values to 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
|
||||
* @param account A CryptoNetAccount with the parameters to be imported
|
||||
* @returnThe CruptoNetAccount imported
|
||||
*/
|
||||
public CryptoNetAccount importAccountFromSeed(CryptoNetAccount account, Context context);
|
||||
public void importAccountFromSeed(CryptoNetAccount account, Context context);
|
||||
|
||||
/**
|
||||
* 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.v7.recyclerview.extensions.DiffCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||
|
||||
/**
|
||||
* Represents a user contact
|
||||
*
|
||||
|
@ -19,7 +22,7 @@ import java.util.List;
|
|||
*/
|
||||
|
||||
@Entity(tableName="contact",
|
||||
indices = {@Index("id"),@Index(value = {"name"}, unique=true)})
|
||||
indices = {@Index("id"),@Index(value = {"name"}, unique=true),@Index("email")})
|
||||
public class Contact {
|
||||
|
||||
/**
|
||||
|
@ -32,6 +35,9 @@ public class Contact {
|
|||
@ColumnInfo(name="name")
|
||||
private String mName;
|
||||
|
||||
@ColumnInfo(name="email")
|
||||
private String mEmail;
|
||||
|
||||
@ColumnInfo(name = "gravatar")
|
||||
private String mGravatar;
|
||||
|
||||
|
@ -62,6 +68,14 @@ public class Contact {
|
|||
this.mGravatar = gravatar;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return this.mEmail;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.mEmail = email;
|
||||
}
|
||||
|
||||
public int addressesCount(){
|
||||
return this.mAddresses.size();
|
||||
}
|
||||
|
@ -70,8 +84,30 @@ public class Contact {
|
|||
return this.mAddresses.get(index);
|
||||
}
|
||||
|
||||
public void clearAddresses(){
|
||||
if (this.mAddresses != null) {
|
||||
this.mAddresses.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void addAddress(ContactAddress address){
|
||||
if (this.mAddresses == null) {
|
||||
this.mAddresses = new ArrayList<ContactAddress>();
|
||||
}
|
||||
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>() {
|
||||
|
|
|
@ -4,9 +4,12 @@ package cy.agorise.crystalwallet.models;
|
|||
import android.arch.persistence.room.ColumnInfo;
|
||||
import android.arch.persistence.room.Entity;
|
||||
import android.arch.persistence.room.Index;
|
||||
import android.arch.persistence.room.PrimaryKey;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.recyclerview.extensions.DiffCallback;
|
||||
|
||||
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||
|
||||
/**
|
||||
* Represents a user contact address
|
||||
*
|
||||
|
@ -14,19 +17,37 @@ import android.support.v7.recyclerview.extensions.DiffCallback;
|
|||
*/
|
||||
|
||||
@Entity(tableName="contact_address",
|
||||
primaryKeys = {"contact_id","crypto_currency_id"},
|
||||
indices = {@Index(value = {"contact_id","crypto_currency_id"}, unique=true)})
|
||||
indices = {@Index(value = {"id"}, unique=true),@Index(value = {"contact_id","crypto_net"}, unique=true)})
|
||||
public class ContactAddress {
|
||||
|
||||
/**
|
||||
* The id on the database
|
||||
*/
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = "id")
|
||||
private long mId;
|
||||
|
||||
@ColumnInfo(name = "contact_id")
|
||||
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")
|
||||
private String mAddress;
|
||||
|
||||
public long getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.mId = id;
|
||||
}
|
||||
|
||||
public long getContactId() {
|
||||
return mContactId;
|
||||
}
|
||||
|
@ -35,12 +56,12 @@ public class ContactAddress {
|
|||
this.mContactId = contactId;
|
||||
}
|
||||
|
||||
public long getCryptoCurrencyId() {
|
||||
return mCryptoCurrencyId;
|
||||
public CryptoNet getCryptoNet() {
|
||||
return mCryptoNet;
|
||||
}
|
||||
|
||||
public void setCryptoCurrencyId(long cryptoCurrencyId) {
|
||||
this.mCryptoCurrencyId = cryptoCurrencyId;
|
||||
public void setCryptoNet(CryptoNet cryptoNet) {
|
||||
this.mCryptoNet = cryptoNet;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
|
@ -56,7 +77,7 @@ public class ContactAddress {
|
|||
public boolean areItemsTheSame(
|
||||
@NonNull ContactAddress oldContactAddress, @NonNull ContactAddress newContactAddress) {
|
||||
return (oldContactAddress.getContactId() == newContactAddress.getContactId())
|
||||
&& (oldContactAddress.getCryptoCurrencyId() == newContactAddress.getCryptoCurrencyId());
|
||||
&& (oldContactAddress.getCryptoNet() == newContactAddress.getCryptoNet());
|
||||
}
|
||||
@Override
|
||||
public boolean areContentsTheSame(
|
||||
|
@ -73,7 +94,7 @@ public class ContactAddress {
|
|||
ContactAddress that = (ContactAddress) o;
|
||||
|
||||
if (mContactId != that.mContactId) return false;
|
||||
if (mCryptoCurrencyId != that.mCryptoCurrencyId) return false;
|
||||
if (mCryptoNet != that.mCryptoNet) return false;
|
||||
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_CURRENCY = "PREFERED_CURRENCY";
|
||||
public final static String SETTING_PASSWORD = "PASSWORD";
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
LoadEquivalencesThread.stopLoadingEquivalences();
|
||||
}
|
||||
;
|
||||
};
|
||||
LoadEquivalencesThread = new EquivalencesThread(service, generalSetting.getValue(), bitsharesAssets);
|
||||
LoadEquivalencesThread.start();
|
||||
}
|
||||
|
@ -184,7 +183,7 @@ public class CrystalWalletService extends LifecycleService {
|
|||
}
|
||||
|
||||
//if (LoadEquivalencesThread == null) {
|
||||
// LoadEquivalencesThread = new Thread() {
|
||||
// LoadEquivalencesThread = new EquivalencesThread() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
loadEquivalentsValues();
|
||||
|
|
|
@ -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 cy.agorise.crystalwallet.dao.CrystalDatabase;
|
||||
import cy.agorise.crystalwallet.enums.CryptoNet;
|
||||
import cy.agorise.crystalwallet.models.Contact;
|
||||
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(){
|
||||
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());
|
||||
}
|
||||
|
||||
public void loadCryptoNetAccount(int accountId){
|
||||
public void loadCryptoNetAccount(long accountId){
|
||||
this.cryptoNetAccount = this.db.cryptoNetAccountDao().getByIdLiveData(accountId);
|
||||
}
|
||||
|
||||
|
@ -36,5 +36,4 @@ public class CryptoNetAccountViewModel extends AndroidViewModel {
|
|||
public LiveData<CryptoNetAccount> getCryptoNetAccount(){
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,11 +23,11 @@ public class PinConfirmationValidationField extends ValidationField {
|
|||
String newConfirmationValue = pinConfirmationField.getText().toString();
|
||||
String newValue = pinField.getText().toString();
|
||||
String mixedValue = newValue + "_" + newConfirmationValue;
|
||||
if (mixedValue != this.getLastValue()) {
|
||||
|
||||
if (!newConfirmationValue.equals("")) {
|
||||
if (!mixedValue.equals(this.getLastValue())) {
|
||||
this.setLastValue(mixedValue);
|
||||
this.startValidating();
|
||||
|
||||
|
||||
if (!newConfirmationValue.equals(newValue)) {
|
||||
this.setMessageForValue(mixedValue, this.validator.getContext().getResources().getString(R.string.mismatch_pin));
|
||||
this.setValidForValue(mixedValue, false);
|
||||
|
@ -35,5 +35,11 @@ public class PinConfirmationValidationField extends ValidationField {
|
|||
this.setValidForValue(mixedValue, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.setLastValue("");
|
||||
this.startValidating();
|
||||
this.setMessageForValue("", "");
|
||||
this.setValidForValue("", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ public class PinValidationField extends ValidationField {
|
|||
|
||||
public void validate(){
|
||||
String newValue = pinField.getText().toString();
|
||||
if (newValue != this.getLastValue()) {
|
||||
if (!newValue.equals("")) {
|
||||
if (!newValue.equals(this.getLastValue())) {
|
||||
this.setLastValue(newValue);
|
||||
this.startValidating();
|
||||
|
||||
|
@ -31,5 +32,11 @@ public class PinValidationField extends ValidationField {
|
|||
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.models.Contact;
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||
import cy.agorise.crystalwallet.viewmodels.ContactListViewModel;
|
||||
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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.ThemedSpinnerAdapter;
|
||||
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 1/17/2017.
|
||||
|
@ -19,6 +30,7 @@ public class ContactViewHolder extends RecyclerView.ViewHolder {
|
|||
private TextView tvName;
|
||||
private ImageView ivThumbnail;
|
||||
private TextView tvLastPaid;
|
||||
private ImageView ivDeleteContact;
|
||||
private Context context;
|
||||
|
||||
public ContactViewHolder(View itemView) {
|
||||
|
@ -27,6 +39,7 @@ public class ContactViewHolder extends RecyclerView.ViewHolder {
|
|||
tvName = (TextView) itemView.findViewById(R.id.tvContactName);
|
||||
ivThumbnail = (ImageView) itemView.findViewById(R.id.ivContactThumbnail);
|
||||
tvLastPaid = (TextView) itemView.findViewById(R.id.tvLastPaid);
|
||||
ivDeleteContact = (ImageView) itemView.findViewById(R.id.ivDeleteContact);
|
||||
this.context = itemView.getContext();
|
||||
|
||||
}
|
||||
|
@ -49,6 +62,47 @@ public class ContactViewHolder extends RecyclerView.ViewHolder {
|
|||
} else {
|
||||
tvName.setText(contact.getName());
|
||||
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> {
|
||||
|
||||
CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder;
|
||||
|
||||
public CryptoCoinBalanceListAdapter() {
|
||||
super(CryptoCoinBalance.DIFF_CALLBACK);
|
||||
}
|
||||
|
||||
public void setCryptoNetBalanceViewHolder(CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder){
|
||||
this.cryptoNetBalanceViewHolder = cryptoNetBalanceViewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CryptoCoinBalanceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
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
|
||||
|
|
|
@ -83,7 +83,7 @@ public class CryptoCoinBalanceListView extends RelativeLayout {
|
|||
*
|
||||
* @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
|
||||
if (this.listAdapter == null) {
|
||||
this.listAdapter = new CryptoCoinBalanceListAdapter();
|
||||
|
@ -92,6 +92,7 @@ public class CryptoCoinBalanceListView extends RelativeLayout {
|
|||
|
||||
//sets the data of the list adapter
|
||||
if (data != null) {
|
||||
this.listAdapter.setCryptoNetBalanceViewHolder(cryptoNetBalanceViewHolder);
|
||||
this.listAdapter.setList(data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,12 +39,15 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
private Context context;
|
||||
|
||||
public CryptoCoinBalanceViewHolder(View itemView) {
|
||||
private CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder;
|
||||
|
||||
public CryptoCoinBalanceViewHolder(View itemView, CryptoNetBalanceViewHolder cryptoNetBalanceViewHolder) {
|
||||
super(itemView);
|
||||
//TODO: use ButterKnife to load this
|
||||
cryptoCoinName = (TextView) itemView.findViewById(R.id.tvCryptoCoinName);
|
||||
cryptoCoinBalance = (TextView) itemView.findViewById(R.id.tvCryptoCoinBalanceAmount);
|
||||
cryptoCoinBalanceEquivalence = (TextView) itemView.findViewById(R.id.tvCryptoCoinBalanceEquivalence);
|
||||
this.cryptoNetBalanceViewHolder = cryptoNetBalanceViewHolder;
|
||||
this.context = itemView.getContext();
|
||||
|
||||
}
|
||||
|
@ -80,7 +83,13 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder {
|
|||
public void onChanged(@Nullable GeneralSetting generalSetting) {
|
||||
if (generalSetting != null) {
|
||||
//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());
|
||||
|
||||
currencyToLiveData.observe((LifecycleOwner) context, new Observer<CryptoCurrency>() {
|
||||
@Override
|
||||
public void onChanged(@Nullable CryptoCurrency cryptoCurrency) {
|
||||
if (cryptoCurrency != null) {
|
||||
CryptoCurrency currencyTo = cryptoCurrency;
|
||||
|
||||
//Retrieves the equivalent value of this balance using the "From" currency and the "To" currency
|
||||
LiveData<CryptoCurrencyEquivalence> currencyEquivalenceLiveData = CrystalDatabase.getAppDatabase(context)
|
||||
|
@ -96,12 +105,14 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder {
|
|||
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",
|
||||
(balance.getBalance()/Math.pow(10,currencyFrom.getPrecision()))/
|
||||
(cryptoCurrencyEquivalence.getValue()/Math.pow(10,toCurrency.getPrecision()))
|
||||
equivalentValue
|
||||
);
|
||||
|
||||
cryptoNetBalanceViewHolder.setEquivalentBalance(balance,equivalentValue);
|
||||
cryptoCoinBalanceEquivalence.setText(
|
||||
equivalenceString + " " + toCurrency.getName());
|
||||
}
|
||||
|
@ -112,4 +123,7 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder {
|
|||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.widget.Button;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
@ -48,11 +49,18 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
|||
*/
|
||||
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
|
||||
*/
|
||||
CryptoCoinBalanceListView cryptoCoinBalanceListView;
|
||||
|
||||
HashMap<CryptoCoinBalance, Double> equivalentTotalHashMap;
|
||||
|
||||
/*
|
||||
* 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
|
||||
cryptoNetIcon = (ImageView) itemView.findViewById(R.id.ivCryptoNetIcon);
|
||||
cryptoNetName = (TextView) itemView.findViewById(R.id.tvCryptoNetName);
|
||||
cryptoNetEquivalentTotal = (TextView) itemView.findViewById(R.id.tvCryptoNetEquivalentTotal);
|
||||
cryptoCoinBalanceListView = (CryptoCoinBalanceListView) itemView.findViewById(R.id.cryptoCoinBalancesListView);
|
||||
btnSendFromThisAccount = (Button) itemView.findViewById(R.id.btnSendFromThisAccount);
|
||||
btnReceiveToThisAccount = (Button) itemView.findViewById(R.id.btnReceiveWithThisAccount);
|
||||
|
@ -157,6 +166,23 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
|||
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
|
||||
*/
|
||||
|
@ -164,6 +190,7 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
|||
if (balance == null){
|
||||
cryptoNetName.setText("loading...");
|
||||
} else {
|
||||
final CryptoNetBalanceViewHolder thisViewHolder = this;
|
||||
this.cryptoNetAccountId = balance.getAccountId();
|
||||
cryptoNetName.setText(balance.getCryptoNet().getLabel());
|
||||
|
||||
|
@ -172,13 +199,15 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
|
|||
cryptoCoinBalanceListViewModel.init(balance.getAccountId());
|
||||
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
|
||||
cryptoCoinBalanceData.observe((LifecycleOwner)this.itemView.getContext(), new Observer<List<CryptoCoinBalance>>() {
|
||||
@Override
|
||||
public void onChanged(List<CryptoCoinBalance> cryptoCoinBalances) {
|
||||
cryptoCoinBalanceListView.setData(cryptoCoinBalances);
|
||||
cryptoCoinBalanceListView.setData(cryptoCoinBalances, thisViewHolder);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,20 +1,30 @@
|
|||
package cy.agorise.crystalwallet.views;
|
||||
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
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.activities.CryptoCoinTransactionReceiptActivity;
|
||||
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
||||
import cy.agorise.crystalwallet.models.CryptoCurrency;
|
||||
import cy.agorise.crystalwallet.models.CryptoNetAccount;
|
||||
import cy.agorise.crystalwallet.viewmodels.CryptoCurrencyViewModel;
|
||||
import cy.agorise.crystalwallet.viewmodels.CryptoNetAccountViewModel;
|
||||
|
||||
/**
|
||||
* Created by Henry Varona on 17/9/2017.
|
||||
|
@ -26,16 +36,18 @@ public class TransactionViewHolder extends RecyclerView.ViewHolder {
|
|||
/*
|
||||
* The view holding the transaction "from"
|
||||
*/
|
||||
private TextView transactionFrom;
|
||||
private TextView tvFrom;
|
||||
/*
|
||||
* The view holding the transaction "to"
|
||||
*/
|
||||
private TextView transactionTo;
|
||||
private TextView tvTo;
|
||||
/*
|
||||
* The view holding the transaction amount
|
||||
*/
|
||||
private TextView transactionAmount;
|
||||
private TextView tvAmount;
|
||||
private TextView tvEquivalent;
|
||||
private TextView tvTransactionDate;
|
||||
private TextView tvTransactionHour;
|
||||
private View rootView;
|
||||
|
||||
private Fragment fragment;
|
||||
|
@ -48,10 +60,12 @@ public class TransactionViewHolder extends RecyclerView.ViewHolder {
|
|||
this.cryptoCoinTransactionId = -1;
|
||||
|
||||
rootView = itemView.findViewById(R.id.rlTransactionItem);
|
||||
transactionFrom = (TextView) itemView.findViewById(R.id.fromText);
|
||||
transactionTo = (TextView) itemView.findViewById(R.id.toText);
|
||||
transactionAmount = (TextView) itemView.findViewById(R.id.amountText);
|
||||
tvFrom = (TextView) itemView.findViewById(R.id.fromText);
|
||||
tvTo = (TextView) itemView.findViewById(R.id.toText);
|
||||
tvAmount = (TextView) itemView.findViewById(R.id.tvAmount);
|
||||
tvEquivalent = (TextView) itemView.findViewById(R.id.tvEquivalent);
|
||||
tvTransactionDate = (TextView) itemView.findViewById(R.id.tvTransactionDate);
|
||||
tvTransactionHour = (TextView) itemView.findViewById(R.id.tvTransactionHour);
|
||||
this.fragment = fragment;
|
||||
|
||||
rootView.setOnClickListener(new View.OnClickListener() {
|
||||
|
@ -85,9 +99,12 @@ public class TransactionViewHolder extends RecyclerView.ViewHolder {
|
|||
* Clears all info in this element view
|
||||
*/
|
||||
public void clear(){
|
||||
transactionFrom.setText("loading...");
|
||||
transactionTo.setText("");
|
||||
transactionAmount.setText("");
|
||||
tvFrom.setText("loading...");
|
||||
tvTo.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*/) {
|
||||
if (transaction == null){
|
||||
transactionFrom.setText("loading...");
|
||||
transactionTo.setText("");
|
||||
transactionAmount.setText("");
|
||||
clear();
|
||||
} else {
|
||||
this.cryptoCoinTransactionId = transaction.getId();
|
||||
CryptoCurrencyViewModel cryptoCurrencyViewModel = ViewModelProviders.of(this.fragment).get(CryptoCurrencyViewModel.class);
|
||||
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()));
|
||||
|
||||
tvTransactionDate.setText(transaction.getDate().toString());
|
||||
transactionFrom.setText(transaction.getFrom());
|
||||
transactionTo.setText(transaction.getTo());
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMM");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("cet"));
|
||||
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()){
|
||||
transactionAmount.setTextColor(itemView.getContext().getResources().getColor(R.color.green));
|
||||
tvTo.setText(cryptoNetAccount.getName());
|
||||
} else {
|
||||
transactionAmount.setTextColor(itemView.getContext().getResources().getColor(R.color.red));
|
||||
tvFrom.setText(cryptoNetAccount.getName());
|
||||
}
|
||||
transactionAmount.setText(
|
||||
amountString
|
||||
}
|
||||
});
|
||||
|
||||
String finalAmountText = "";
|
||||
if (transaction.getInput()) {
|
||||
tvAmount.setTextColor(itemView.getContext().getResources().getColor(R.color.green));
|
||||
finalAmountText = "+ "+amountString
|
||||
+ " "
|
||||
+ cryptoCurrency.getName());
|
||||
+ cryptoCurrency.getName();
|
||||
} else {
|
||||
tvAmount.setTextColor(itemView.getContext().getResources().getColor(R.color.red));
|
||||
finalAmountText = amountString
|
||||
+ " "
|
||||
+ cryptoCurrency.getName();
|
||||
}
|
||||
tvAmount.setText(finalAmountText);
|
||||
//This will load the transaction receipt when the user clicks this view
|
||||
/*itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@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_alignParentTop="true">
|
||||
|
||||
<LinearLayout
|
||||
<RelativeLayout
|
||||
android:id="@+id/cryptoNetBalanceTitleBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -31,20 +31,30 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:layout_toRightOf="@id/ivCryptoNetIcon"
|
||||
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
|
||||
android:id="@+id/btnSendFromThisAccount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="send"/>
|
||||
android:text="send"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnReceiveWithThisAccount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="receive"/>
|
||||
</LinearLayout>
|
||||
android:text="receive"
|
||||
android:visibility="gone" />
|
||||
</RelativeLayout>
|
||||
|
||||
<cy.agorise.crystalwallet.views.CryptoCoinBalanceListView
|
||||
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_toRightOf="@+id/ivContactThumbnail"
|
||||
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>
|
||||
</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_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTaxableCountry"
|
||||
app:layout_constraintEnd_toEndOf="@id/spBackupAsset"
|
||||
app:layout_constraintStart_toStartOf="@id/spBackupAsset"
|
||||
app:layout_constraintEnd_toEndOf="@id/spBackupAsset"/>
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTaxableCountry" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vTaxableCountry"
|
||||
|
|
|
@ -28,6 +28,13 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/tvCurrentPin"
|
||||
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
|
||||
android:id="@+id/etNewPin"
|
||||
android:layout_width="0dp"
|
||||
|
@ -39,7 +46,13 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
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
|
||||
android:id="@+id/etConfirmPin"
|
||||
|
@ -52,6 +65,11 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
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>
|
|
@ -4,9 +4,22 @@
|
|||
android:layout_height="match_parent"
|
||||
tools:context="cy.agorise.crystalwallet.fragments.TransactionsFragment">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!--<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>
|
||||
|
|
|
@ -1,59 +1,111 @@
|
|||
<?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:paddingBottom="5dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingTop="10dp">
|
||||
android:paddingTop="5dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rlTransactionItem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true">
|
||||
|
||||
<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" />
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="@drawable/transaction_list_item_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fromText"
|
||||
android:layout_width="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:inputType="text"
|
||||
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
|
||||
android:id="@+id/toText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/tvTransactionDate"
|
||||
android:layout_alignParentBottom="false"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_toEndOf="@+id/ivArrowFromTo"
|
||||
android:ems="10"
|
||||
android:inputType="text"
|
||||
android:text="to"
|
||||
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
|
||||
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_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignWithParentIfMissing="false"
|
||||
android:layout_below="@+id/fromText"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_below="@id/sAfterFromTo"
|
||||
android:layout_toEndOf="@+id/ivArrowFromTo"
|
||||
android:ems="10"
|
||||
android:gravity="center"
|
||||
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>
|
||||
</LinearLayout>
|
Loading…
Reference in a new issue