Merge pull request #6 from davidtadeovargas/feat_ui_improvements

Feat ui improvements
This commit is contained in:
Severiano Jaramillo Quintanar 2018-08-27 09:50:10 -05:00 committed by GitHub
commit c3bd0a5f53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
70 changed files with 3490 additions and 395 deletions

View file

@ -1,5 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
kapt {
generateStubs = true
javacOptions {
option("-Xmaxerrs", 500)
}
}
android {
compileSdkVersion 27
@ -44,15 +52,20 @@ dependencies {
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'com.jaredrummler:material-spinner:1.2.5'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
//testCompile 'com.android.support.test:runner:1.0.1'
implementation 'com.afollestad.material-dialogs:core:0.9.6.0' //DTVV Thrusday 31 July 2018
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.github.bumptech.glide:glide:4.7.1'
// Glide v4 uses this new annotation processor -- see https://bumptech.github.io/glide/doc/generatedapi.html
annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'android.arch.lifecycle:runtime:1.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'android.arch.persistence.room:runtime:1.1.0'
implementation 'android.arch.paging:runtime:1.0.0'
implementation 'com.idescout.sql:sqlscout-server:2.0'
implementation 'com.google.code.gson:gson:2.8.0'
@ -72,8 +85,15 @@ dependencies {
//testCompile 'junit:junit: 4.12'
testImplementation 'org.mockito:mockito-core:1.10.19'
implementation 'android.arch.persistence.room:runtime:1.1.0'
kapt 'android.arch.persistence.room:runtime:1.1.0'
annotationProcessor 'android.arch.lifecycle:compiler:1.1.1'
kapt 'android.arch.lifecycle:compiler:1.1.1'
annotationProcessor 'android.arch.lifecycle:compiler:1.1.1'
kapt 'android.arch.persistence.room:compiler:1.1.0'
annotationProcessor 'android.arch.persistence.room:compiler:1.1.0'
kapt 'com.jakewharton:butterknife-compiler:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'com.squareup.picasso:picasso:2.5.2'

View file

@ -0,0 +1,704 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "5aa4eae5c7cf7e77a2ebc1d7a9dc7070",
"entities": [
{
"tableName": "account_seed",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `master_seed` TEXT, `type` TEXT)",
"fields": [
{
"fieldPath": "mId",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mName",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mMasterSeed",
"columnName": "master_seed",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "crypto_net_account",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `seed_id` INTEGER NOT NULL, `account_index` INTEGER NOT NULL, `crypto_net` TEXT, `name` TEXT, FOREIGN KEY(`seed_id`) REFERENCES `account_seed`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "mId",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mSeedId",
"columnName": "seed_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mAccountIndex",
"columnName": "account_index",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mCryptoNet",
"columnName": "crypto_net",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mName",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_crypto_net_account_id",
"unique": false,
"columnNames": [
"id"
],
"createSql": "CREATE INDEX `index_crypto_net_account_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "index_crypto_net_account_seed_id",
"unique": false,
"columnNames": [
"seed_id"
],
"createSql": "CREATE INDEX `index_crypto_net_account_seed_id` ON `${TABLE_NAME}` (`seed_id`)"
},
{
"name": "index_crypto_net_account_seed_id_crypto_net_account_index",
"unique": true,
"columnNames": [
"seed_id",
"crypto_net",
"account_index"
],
"createSql": "CREATE UNIQUE INDEX `index_crypto_net_account_seed_id_crypto_net_account_index` ON `${TABLE_NAME}` (`seed_id`, `crypto_net`, `account_index`)"
}
],
"foreignKeys": [
{
"table": "account_seed",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"seed_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "crypto_coin_transaction",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` INTEGER, `is_input` INTEGER NOT NULL, `account_id` INTEGER NOT NULL, `amount` INTEGER NOT NULL, `id_currency` INTEGER NOT NULL, `is_confirmed` INTEGER NOT NULL, `from` TEXT, `to` TEXT, FOREIGN KEY(`account_id`) REFERENCES `crypto_net_account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`id_currency`) REFERENCES `crypto_currency`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "date",
"columnName": "date",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isInput",
"columnName": "is_input",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accountId",
"columnName": "account_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "amount",
"columnName": "amount",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "idCurrency",
"columnName": "id_currency",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isConfirmed",
"columnName": "is_confirmed",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "from",
"columnName": "from",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "to",
"columnName": "to",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_crypto_coin_transaction_account_id",
"unique": false,
"columnNames": [
"account_id"
],
"createSql": "CREATE INDEX `index_crypto_coin_transaction_account_id` ON `${TABLE_NAME}` (`account_id`)"
},
{
"name": "index_crypto_coin_transaction_id_currency",
"unique": false,
"columnNames": [
"id_currency"
],
"createSql": "CREATE INDEX `index_crypto_coin_transaction_id_currency` ON `${TABLE_NAME}` (`id_currency`)"
}
],
"foreignKeys": [
{
"table": "crypto_net_account",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"account_id"
],
"referencedColumns": [
"id"
]
},
{
"table": "crypto_currency",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"id_currency"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "contact",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `email` TEXT, `gravatar` TEXT)",
"fields": [
{
"fieldPath": "mId",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mName",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mEmail",
"columnName": "email",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mGravatar",
"columnName": "gravatar",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_contact_id",
"unique": false,
"columnNames": [
"id"
],
"createSql": "CREATE INDEX `index_contact_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "index_contact_name",
"unique": true,
"columnNames": [
"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": []
},
{
"tableName": "crypto_currency",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `crypto_net` TEXT, `precision` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "mId",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mName",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mCryptoNet",
"columnName": "crypto_net",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mPrecision",
"columnName": "precision",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_crypto_currency_crypto_net_name",
"unique": true,
"columnNames": [
"crypto_net",
"name"
],
"createSql": "CREATE UNIQUE INDEX `index_crypto_currency_crypto_net_name` ON `${TABLE_NAME}` (`crypto_net`, `name`)"
}
],
"foreignKeys": []
},
{
"tableName": "crypto_coin_balance",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account_id` INTEGER NOT NULL, `crypto_currency_id` INTEGER NOT NULL, `balance` INTEGER NOT NULL, FOREIGN KEY(`account_id`) REFERENCES `crypto_net_account`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "mId",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mAccountId",
"columnName": "account_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mCryptoCurrencyId",
"columnName": "crypto_currency_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mBalance",
"columnName": "balance",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_crypto_coin_balance_id",
"unique": false,
"columnNames": [
"id"
],
"createSql": "CREATE INDEX `index_crypto_coin_balance_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "index_crypto_coin_balance_account_id",
"unique": false,
"columnNames": [
"account_id"
],
"createSql": "CREATE INDEX `index_crypto_coin_balance_account_id` ON `${TABLE_NAME}` (`account_id`)"
},
{
"name": "index_crypto_coin_balance_account_id_crypto_currency_id",
"unique": true,
"columnNames": [
"account_id",
"crypto_currency_id"
],
"createSql": "CREATE UNIQUE INDEX `index_crypto_coin_balance_account_id_crypto_currency_id` ON `${TABLE_NAME}` (`account_id`, `crypto_currency_id`)"
}
],
"foreignKeys": [
{
"table": "crypto_net_account",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"account_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "graphene_account",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`crypto_net_account_id` INTEGER NOT NULL, `account_name` TEXT, `account_id` TEXT, `upgraded_to_ltm` INTEGER NOT NULL, PRIMARY KEY(`crypto_net_account_id`), FOREIGN KEY(`crypto_net_account_id`) REFERENCES `crypto_net_account`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "cryptoNetAccountId",
"columnName": "crypto_net_account_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "account_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "accountId",
"columnName": "account_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upgradedToLtm",
"columnName": "upgraded_to_ltm",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"crypto_net_account_id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": [
{
"table": "crypto_net_account",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"crypto_net_account_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "bitshares_asset",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`crypto_curreny_id` INTEGER NOT NULL, `bitshares_id` TEXT, `asset_type` TEXT, PRIMARY KEY(`crypto_curreny_id`), FOREIGN KEY(`crypto_curreny_id`) REFERENCES `crypto_currency`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "cryptoCurrencyId",
"columnName": "crypto_curreny_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "bitsharesId",
"columnName": "bitshares_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "assetType",
"columnName": "asset_type",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"crypto_curreny_id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": [
{
"table": "crypto_currency",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"crypto_curreny_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "crypto_currency_equivalence",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `from_crypto_currency_id` INTEGER NOT NULL, `to_crypto_currency_id` INTEGER NOT NULL, `value` INTEGER NOT NULL, `last_checked` INTEGER, FOREIGN KEY(`from_crypto_currency_id`) REFERENCES `crypto_currency`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`to_crypto_currency_id`) REFERENCES `crypto_currency`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "fromCurrencyId",
"columnName": "from_crypto_currency_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "toCurrencyId",
"columnName": "to_crypto_currency_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastChecked",
"columnName": "last_checked",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_crypto_currency_equivalence_from_crypto_currency_id_to_crypto_currency_id",
"unique": true,
"columnNames": [
"from_crypto_currency_id",
"to_crypto_currency_id"
],
"createSql": "CREATE UNIQUE INDEX `index_crypto_currency_equivalence_from_crypto_currency_id_to_crypto_currency_id` ON `${TABLE_NAME}` (`from_crypto_currency_id`, `to_crypto_currency_id`)"
},
{
"name": "index_crypto_currency_equivalence_from_crypto_currency_id",
"unique": false,
"columnNames": [
"from_crypto_currency_id"
],
"createSql": "CREATE INDEX `index_crypto_currency_equivalence_from_crypto_currency_id` ON `${TABLE_NAME}` (`from_crypto_currency_id`)"
},
{
"name": "index_crypto_currency_equivalence_to_crypto_currency_id",
"unique": false,
"columnNames": [
"to_crypto_currency_id"
],
"createSql": "CREATE INDEX `index_crypto_currency_equivalence_to_crypto_currency_id` ON `${TABLE_NAME}` (`to_crypto_currency_id`)"
}
],
"foreignKeys": [
{
"table": "crypto_currency",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"from_crypto_currency_id"
],
"referencedColumns": [
"id"
]
},
{
"table": "crypto_currency",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"to_crypto_currency_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "general_setting",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `value` TEXT)",
"fields": [
{
"fieldPath": "mId",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mName",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mValue",
"columnName": "value",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"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, \"5aa4eae5c7cf7e77a2ebc1d7a9dc7070\")"
]
}
}

View file

@ -31,13 +31,15 @@
<activity android:name=".activities.BoardActivity"
android:theme="@style/AppTheme.NoActionBar" >
</activity>
<activity android:name=".activities.CreateSeedActivity" >
</activity>
<activity android:name=".activities.LoadingActivity"
android:theme="@style/ActivityDialog">
</activity>
<activity android:name=".activities.AccountSeedsManagementActivity" >
</activity>
<activity android:name=".activities.ImportSeedActivity" >
</activity>
<activity android:name=".activities.CreateSeedActivity"
android:noHistory="true">
</activity>
<activity android:name=".activities.SendTransactionActivity" >
</activity>
<activity android:name=".activities.GeneralSettingsActivity" >
@ -100,6 +102,22 @@
<activity android:name=".activities.CreateContactActivity">
</activity>
<!--Test activities-->
<activity android:name=".tests.activities.dialogs.Test_DialogMaterialActivity">
</activity>
<activity android:name=".tests.activities.dialogs.Test_LoadingActivity">
</activity>
<activity android:name=".tests.activities.dialogs.Test_CrystalDialogActivity">
</activity>
<activity android:name=".tests.activities.dialogs.Test_GIFActivity">
</activity>
<activity android:name=".tests.activities.dialogs.Test_ToastActivity">
</activity>
<activity android:name=".tests.activities.dialogs.Test_VideoActivity">
</activity>
</application>
</manifest>

View file

@ -3,12 +3,16 @@ package cy.agorise.crystalwallet.activities;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import butterknife.BindView;
import butterknife.ButterKnife;
@ -17,19 +21,28 @@ import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.viewmodels.AccountSeedViewModel;
//tvBrainKey
public class BackupSeedActivity extends AppCompatActivity {
AccountSeedViewModel accountSeedViewModel;
@BindView(R.id.tvMnemonic)
TextView tvMnemonic;
@BindView(R.id.tvBrainKey)
TextView textfieldBrainkey;
@BindView(R.id.btnOk)
Button btnOk;
@BindView(R.id.btnCopy)
Button btnCopy;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.backup_seed);
//Note: Test porpouses
/*final TextView textView = findViewById(R.id.tvBrainKey);
textView.setText("sakk902909321o p3k21kldsa0'dsa90'e930eidakdñsakdñlsakdi90i03 2i90idopsasakk902909321op3k21 kldsa0'dsa90'e930eid akdñsakdñlsakdi90i032i90idopsa");
*/
ButterKnife.bind(this);
long seedId = getIntent().getLongExtra("SEED_ID",-1);
@ -41,7 +54,7 @@ public class BackupSeedActivity extends AppCompatActivity {
liveDataAccountSeed.observe(this, new Observer<AccountSeed>() {
@Override
public void onChanged(@Nullable AccountSeed accountSeed) {
tvMnemonic.setText(accountSeed.getMasterSeed());
textfieldBrainkey.setText(accountSeed.getMasterSeed());
}
});
accountSeedViewModel.loadSeed(seedId);
@ -56,4 +69,23 @@ public class BackupSeedActivity extends AppCompatActivity {
Intent intent = new Intent(this, IntroActivity.class);
startActivity(intent);
}
/*
* Clic on button copy to clipboard
* */
@OnClick(R.id.btnCopy)
public void btnCopyClick(){
/*
* Save to clipboard the brainkey chain
* */
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(textfieldBrainkey.getText(), textfieldBrainkey.getText().toString());
clipboard.setPrimaryClip(clip);
/*
* Success message
* */
Toast.makeText(this.getBaseContext(),getResources().getString(R.string.window_seed_toast_clipboard), Toast.LENGTH_SHORT).show();
}
}

View file

@ -8,6 +8,8 @@ import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
@ -17,16 +19,22 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Pair;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.sjaramillo10.animatedtablayout.AnimatedTabLayout;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import java.io.File;
@ -39,6 +47,7 @@ import cy.agorise.crystalwallet.fragments.ContactsFragment;
import cy.agorise.crystalwallet.fragments.ReceiveTransactionFragment;
import cy.agorise.crystalwallet.fragments.SendTransactionFragment;
import cy.agorise.crystalwallet.fragments.TransactionsFragment;
import cy.agorise.crystalwallet.views.natives.GIFView;
import de.hdodenhof.circleimageview.CircleImageView;
import cy.agorise.crystalwallet.viewmodels.CryptoNetBalanceListViewModel;
@ -47,7 +56,7 @@ import cy.agorise.crystalwallet.viewmodels.CryptoNetBalanceListViewModel;
*
*/
public class BoardActivity extends AppCompatActivity {
public class BoardActivity extends CustomActivity {
@BindView(R.id.tabLayout)
public TabLayout tabLayout;
@ -64,6 +73,9 @@ public class BoardActivity extends AppCompatActivity {
@BindView(R.id.fabAddContact)
public FloatingActionButton fabAddContact;
@BindView(R.id.imagevieGIF)
public GIFView imagevieGIF;
public BoardPagerAdapter boardAdapter;
/*
@ -98,6 +110,61 @@ public class BoardActivity extends AppCompatActivity {
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
/*
* Set the bubbles animation
* */
imagevieGIF.centerCrop();
imagevieGIF.load(R.raw.burbujas);
/*
* Listener tabLayout to resalt text when clicked
* */
final TabLayout tabLayoutFinal = tabLayout;
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(final TabLayout.Tab tab) {
globalActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
LinearLayout tabLayout = (LinearLayout)((ViewGroup) tabLayoutFinal.getChildAt(0)).getChildAt(tab.getPosition());
tabLayout.setBackgroundColor(Color.TRANSPARENT);
TextView tabTextView = (TextView) tabLayout.getChildAt(1);
//tabTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP ,50);
Spannable WordtoSpan = new SpannableString(tabTextView.getText());
WordtoSpan.setSpan(new ForegroundColorSpan(Color.WHITE), 0, tabTextView.getText().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tabTextView.setText(WordtoSpan);
tabTextView.setTypeface(tabTextView.getTypeface(), Typeface.BOLD);
}
});
}
@Override
public void onTabUnselected(final TabLayout.Tab tab) {
globalActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
LinearLayout tabLayout = (LinearLayout)((ViewGroup) tabLayoutFinal.getChildAt(0)).getChildAt(tab.getPosition());
TextView tabTextView = (TextView) tabLayout.getChildAt(1);
//tabTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP ,50);
Spannable WordtoSpan = new SpannableString(tabTextView.getText());
WordtoSpan.setSpan(new ForegroundColorSpan(globalActivity.getResources().getColor(R.color.lightGrayClear)), 0, tabTextView.getText().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tabTextView.setText(WordtoSpan);
tabTextView.setTypeface(tabTextView.getTypeface(), Typeface.NORMAL);
}
});
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
// Appbar animation
mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override

View file

@ -1,204 +0,0 @@
package cy.agorise.crystalwallet.activities;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.view.ViewGroup;
import android.widget.Button;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnTextChanged;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestListener;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.requestmanagers.ValidateCreateBitsharesAccountRequest;
import cy.agorise.crystalwallet.models.GrapheneAccount;
import cy.agorise.crystalwallet.viewmodels.AccountSeedViewModel;
import cy.agorise.crystalwallet.viewmodels.validators.CreateSeedValidator;
import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener;
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ValidationField;
public class CreateSeedActivity extends AppCompatActivity implements UIValidatorListener {
AccountSeedViewModel accountSeedViewModel;
CreateSeedValidator createSeedValidator;
@BindView(R.id.tilPin)
TextInputLayout tilPin;
@BindView(R.id.tietPin)
TextInputEditText tietPin;
@BindView(R.id.tilPinConfirmation)
TextInputLayout tilPinConfirmation;
@BindView(R.id.tietPinConfirmation)
TextInputEditText tietPinConfirmation;
//@BindView(R.id.tvSeedWords)
//TextView tvSeedWords;
@BindView(R.id.tilAccountName)
TextInputLayout tilAccountName;
@BindView (R.id.tietAccountName)
TextInputEditText tietAccountName;
@BindView(R.id.btnCreate)
Button btnCreate;
@BindView(R.id.btnCancel)
Button btnCancel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.create_seed);
ButterKnife.bind(this);
tilPin.setErrorEnabled(true);
tilPinConfirmation.setErrorEnabled(true);
tilAccountName.setErrorEnabled(true);
btnCreate.setEnabled(false);
accountSeedViewModel = ViewModelProviders.of(this).get(AccountSeedViewModel.class);
createSeedValidator = new CreateSeedValidator(this.getApplicationContext(),tietPin,tietPinConfirmation,tietAccountName);
createSeedValidator.setListener(this);
}
@OnTextChanged(value = R.id.tietPin,
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterPinChanged(Editable editable) {
this.createSeedValidator.validate();
}
@OnTextChanged(value = R.id.tietPinConfirmation,
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterPinConfirmationChanged(Editable editable) {
this.createSeedValidator.validate();
}
/*@OnTextChanged(value = R.id.etSeedWords,
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterSeedWordsChanged(Editable editable) {
this.createSeedValidator.validate();
}
*/
@OnTextChanged(value = R.id.tietAccountName,
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterAccountNameChanged(Editable editable) {
this.createSeedValidator.validate();
}
@OnClick(R.id.btnCancel)
public void cancel(){
this.finish();
}
@OnClick(R.id.btnCreate)
public void createSeed(){
if (this.createSeedValidator.isValid()) {
// Make request to create a bitshare account
final ValidateCreateBitsharesAccountRequest request =
new ValidateCreateBitsharesAccountRequest(tietAccountName.getText().toString(), getApplicationContext());
//Makes dialog to tell the user that the account is been created
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(CreateSeedActivity.this,R.style.AppTheme);
alertBuilder.setView(R.layout.progress_creating_account);
//alertBuilder.setTitle("Processing");
//alertBuilder.setMessage("Creating Bitshares Account");
final AlertDialog processDialog = alertBuilder.create();
CreateSeedActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
processDialog.setCancelable(false);
processDialog.show();
processDialog.getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
});
request.setListener(new CryptoNetInfoRequestListener() {
@Override
public void onCarryOut() {
processDialog.dismiss();
if (request.getStatus().equals(ValidateCreateBitsharesAccountRequest.StatusCode.SUCCEEDED)) {
GrapheneAccount accountSeed = request.getAccount();
Intent intent = new Intent(getApplicationContext(), BackupSeedActivity.class);
intent.putExtra("SEED_ID", accountSeed.getId());
startActivity(intent);
} else {
createSeedValidator.validate();
}
}
});
Thread thread = new Thread() {
@Override
public void run() {
CryptoNetInfoRequests.getInstance().addRequest(request);
}
};
thread.start();
//this.finish();
}
}
@Override
public void onValidationSucceeded(final ValidationField field) {
final CreateSeedActivity activity = this;
activity.runOnUiThread(new Runnable() {
public void run() {
if (field.getView() == tietPin) {
tilPin.setError("");
} else if (field.getView() == tietPinConfirmation){
tilPinConfirmation.setError("");
} else if (field.getView() == tietAccountName){
tilAccountName.setError("");
} //else if (field.getView() == etSeedWords){
// tvSeedWordsError.setText("");
//}
if (activity.createSeedValidator.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() == tietPin) {
tilPin.setError(field.getMessage());
} else if (field.getView() == tietPinConfirmation){
tilPinConfirmation.setError(field.getMessage());
} else if (field.getView() == tietAccountName){
tilAccountName.setError(field.getMessage());
} //else if (field.getView() == etSeedWords){
// tvSeedWordsError.setText(field.getMessage());
//}
}
});
}
}

View file

@ -0,0 +1,245 @@
package cy.agorise.crystalwallet.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import butterknife.ButterKnife
import butterknife.OnClick
import butterknife.OnTextChanged
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.dialogs.material.CrystalDialog
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests
import cy.agorise.crystalwallet.requestmanagers.ValidateCreateBitsharesAccountRequest
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidatorListener
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.validationFields.BitsharesAccountNameValidation
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.validationFields.BitsharesAccountNameValidation.OnAccountExist
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.validationFields.CustomValidationField
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.validationFields.PinDoubleConfirmationValidationField
import cy.agorise.crystalwallet.views.natives.CustomTextInputEditText
import kotlinx.android.synthetic.main.create_seed.*
/*
* This activity creates a new account with some security concerns
* */
class CreateSeedActivity : CustomActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*
* Assign the view to this controller
* */
setContentView(R.layout.create_seed)
/*
* Initialice butterknife MVC
* */
ButterKnife.bind(this)
/*
* Add the controls to the validator
* */
this.fieldsValidator.add(tietPin)
this.fieldsValidator.add(tietPinConfirmation)
this.fieldsValidator.add(tietAccountName)
/*
* Validations listener
* */
val uiValidatorListener = object : UIValidatorListener {
override fun onValidationSucceeded(customValidationField: CustomValidationField) {
try {
/*
* Remove error
* */
runOnUiThread {
val customTextInputEditText = customValidationField.currentView as CustomTextInputEditText
customTextInputEditText.error = null
}
} catch (e: Exception) {
e.printStackTrace()
}
/*
* Validate if can continue
* */
validateFieldsToContinue()
}
override fun onValidationFailed(customValidationField: CustomValidationField) {
/*
* Set error label
* */
runOnUiThread {
val customTextInputEditText = customValidationField.currentView as CustomTextInputEditText
customTextInputEditText.error = customTextInputEditText.fieldValidatorModel.message
}
}
}
/*
* Create the pin double validation
* */
val pinDoubleConfirmationValidationField = PinDoubleConfirmationValidationField(this, tietPin, tietPinConfirmation, uiValidatorListener)
/*
* Listener for the validation for success or fail
* */
tietPin?.setUiValidator(pinDoubleConfirmationValidationField) //Validator for the field
tietPinConfirmation?.setUiValidator(pinDoubleConfirmationValidationField) //Validator for the field
/*
* Account name validator
* */
val bitsharesAccountNameValidation = BitsharesAccountNameValidation(this, tietAccountName, uiValidatorListener)
val onAccountExist = object : OnAccountExist {
override fun onAccountExists() {
runOnUiThread { Toast.makeText(globalActivity, resources.getString(R.string.account_name_already_exist), Toast.LENGTH_LONG).show() }
}
}
bitsharesAccountNameValidation.setOnAccountExist(onAccountExist)
tietAccountName?.setUiValidator(bitsharesAccountNameValidation)
/*This button should not be enabled till all the fields be correctly filled*/
disableCreate()
/*
* Set the focus on the fisrt field and show keyboard
* */
tilPin?.requestFocus()
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(tilPin, InputMethodManager.SHOW_IMPLICIT)
}
@OnTextChanged(value = R.id.tietPin, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
internal fun afterPinChanged(editable: Editable) {
this.fieldsValidator.validate()
/*
* Validate continue to create account
* */
validateFieldsToContinue()
}
@OnTextChanged(value = R.id.tietPinConfirmation, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
internal fun afterPinConfirmationChanged(editable: Editable) {
this.fieldsValidator.validate()
/*
* Validate continue to create account
* */
validateFieldsToContinue()
}
@OnTextChanged(value = R.id.tietAccountName, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
internal fun afterAccountNameChanged(editable: Editable) {
this.fieldsValidator.validate()
/*
* Always disable till the server response comes
* */
disableCreate()
}
@OnClick(R.id.btnCancel)
fun cancel() {
/*
* Exit of the activity
* */
this.finish()
}
@OnClick(R.id.btnCreate)
fun createSeed() {
// Make request to create a bitshare account
val request = ValidateCreateBitsharesAccountRequest(tietAccountName?.getText().toString(), applicationContext)
//DTVV: Friday 27 July 2018
//Makes dialog to tell the user that the account is been created
val creatingAccountMaterialDialog = CrystalDialog(this)
creatingAccountMaterialDialog.setText(this.resources.getString(R.string.window_create_seed_DialogMessage))
creatingAccountMaterialDialog.build()
this@CreateSeedActivity.runOnUiThread { creatingAccountMaterialDialog.show() }
request.setListener {
creatingAccountMaterialDialog.dismiss()
if (request.status == ValidateCreateBitsharesAccountRequest.StatusCode.SUCCEEDED) {
val accountSeed = request.account
val intent = Intent(applicationContext, BackupSeedActivity::class.java)
intent.putExtra("SEED_ID", accountSeed.id)
startActivity(intent)
} else {
fieldsValidator.validate()
}
}
val thread = object : Thread() {
override fun run() {
/*
*
* Run thread*/
CryptoNetInfoRequests.getInstance().addRequest(request)
}
}
thread.start()
}
/*
* Validate that all is complete to continue to create
* */
private fun validateFieldsToContinue() {
var result = false //Contains the final result
val pinValid: Boolean? = this.tietPin?.getFieldValidatorModel()?.isValid
val pinConfirmationValid = this.tietPinConfirmation?.getFieldValidatorModel()?.isValid
val pinAccountNameValid = this.tietAccountName?.getFieldValidatorModel()?.isValid
if (pinValid!! &&
pinConfirmationValid!! &&
pinAccountNameValid!!) {
result = true //Validation is correct
}
/*
* If the result is true so the user can continue to the creation of the account
* */
if (result) {
enableCreate()
} else {
disableCreate()
}
}
/*
* Enable create button
* */
private fun enableCreate() {
btnCreate?.setEnabled(true)
btnCreate?.setBackgroundColor(resources.getColor(R.color.colorPrimary))
}
/*
* Disable create button
* */
private fun disableCreate() {
btnCreate?.setEnabled(false)
btnCreate?.setBackground(resources.getDrawable(R.drawable.disable_style))
}
}

View file

@ -0,0 +1,35 @@
package cy.agorise.crystalwallet.activities
import android.app.Activity
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import cy.agorise.crystalwallet.util.FieldsValidator
/*
* Custom implementaion of the activity
* */
open class CustomActivity : AppCompatActivity() {
/*
* Contains the validator for general fields
* */
@JvmField protected var fieldsValidator = FieldsValidator()
/*
* Contains the global activity
* */
protected lateinit var globalActivity: Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*
* Save the current activity for further reference
* */
this.globalActivity = this
}
}

View file

@ -12,6 +12,7 @@ import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.List;
@ -19,23 +20,29 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator;
import cy.agorise.crystalwallet.application.CrystalApplication;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.dialogs.material.ToastIt;
import cy.agorise.crystalwallet.enums.CryptoNet;
import cy.agorise.crystalwallet.fragments.ImportAccountOptionsFragment;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.models.CryptoCoinBalance;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.models.GeneralSetting;
import cy.agorise.crystalwallet.network.CryptoNetManager;
import cy.agorise.crystalwallet.randomdatagenerators.RandomCryptoCoinBalanceGenerator;
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.util.NetworkUtility;
import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel;
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
import cy.agorise.crystalwallet.views.TransactionListView;
public class IntroActivity extends AppCompatActivity {
public class IntroActivity extends CustomActivity {
TransactionListViewModel transactionListViewModel;
TransactionListView transactionListView;
@ -53,8 +60,14 @@ public class IntroActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intro);
ButterKnife.bind(this);
/*
* Test connection with server
* */
NetworkUtility.testServerConnnection(this);
// Appbar animation
mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
@ -137,12 +150,40 @@ public class IntroActivity extends AppCompatActivity {
@OnClick(R.id.btnCreateAccount)
public void createAccount() {
Intent intent = new Intent(this, CreateSeedActivity.class);
/*
* Test connection with server, if no conection user can not continue
*
* */
final GrapheneApiGenerator.OnResponsesWebSocket onResponsesWebSocket = new GrapheneApiGenerator.OnResponsesWebSocket() {
@Override
public void onSuccess() {
/*
* Open the window to create seed and account
* */
Intent intent = new Intent(globalActivity, CreateSeedActivity.class);
startActivity(intent);
}
@Override
public void onError(Exception exception) {
//Nothing to implement, internally the user will see a toast
}
};
NetworkUtility.testServerConnnectionNormalError(this,onResponsesWebSocket);
}
@OnClick(R.id.btnImportAccount)
public void importAccount() {
/*
* Test connection with server, if no conection user can not continue
*
* */
final GrapheneApiGenerator.OnResponsesWebSocket onResponsesWebSocket = new GrapheneApiGenerator.OnResponsesWebSocket() {
@Override
public void onSuccess() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("importAccountOptions");
if (prev != null) {
@ -154,4 +195,11 @@ public class IntroActivity extends AppCompatActivity {
ImportAccountOptionsFragment newFragment = ImportAccountOptionsFragment.newInstance();
newFragment.show(ft, "importAccountOptions");
}
@Override
public void onError(Exception exception) {
//Nothing to implement, internally the user will see a toast
}
};
NetworkUtility.testServerConnnectionNormalError(this,onResponsesWebSocket);
}
}

View file

@ -10,8 +10,11 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.application.CrystalApplication;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.enums.CryptoNet;
import cy.agorise.crystalwallet.models.GeneralSetting;
import cy.agorise.crystalwallet.network.CryptoNetManager;
public class LicenseActivity extends AppCompatActivity {
@ -23,6 +26,7 @@ public class LicenseActivity extends AppCompatActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_license);
ButterKnife.bind(this);
// TODO check if license has been agreed

View file

@ -0,0 +1,263 @@
package cy.agorise.crystalwallet.activities
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import butterknife.ButterKnife
import kotlinx.android.synthetic.main.loading_activity.*
import android.view.animation.AnimationUtils
import android.widget.ImageView
import butterknife.BindView
import cy.agorise.crystalwallet.R
/*
* This activity is to show a loading window when it is needed
* */
class LoadingActivity : CustomActivity() {
@BindView(R.id.imageviewLoading)
lateinit var imageviewLoading:ImageView
override fun onCreate(savedInstanceState: Bundle?) {
/*
* Construct the parent
* */
super.onCreate(savedInstanceState)
/*
* If the window was closed before be created so finish it
* */
if(destroyWindow!!){
finish()
}
/*
* Assign the view to this controller
* */
setContentView(cy.agorise.crystalwallet.R.layout.loading_activity)
/*
* Save the current activity
* */
currentActivity = this
/*
* If has to manage timer
* */
if(LoadingActivity.seconds != -1){
/*
* */
Handler().postDelayed({
/*
* Reset flag
* */
LoadingActivity.seconds = -1
finish() //Finish the current window
}, (LoadingActivity.seconds * 1000).toLong())
}
/*
* Initialice butterknife MVC
* */
ButterKnife.bind(this)
/*
* If has to change the loading sizes so
* */
if(loadinIconChangeSize){
imageviewLoading.layoutParams.width = loadingIconWidth
imageviewLoading.layoutParams.height = loadingIconHeigt
}
/*
* Rotate the image
* */
val rotation = AnimationUtils.loadAnimation(this, cy.agorise.crystalwallet.R.anim.rotate360)
imageviewLoading.startAnimation(rotation)
/*
* If listener is set deliver response
* */
if(onLoadingReady != null){
onLoadingReady!!.onLoadingReady()
}
}
/*
* This events hires when the window is destroyed
* */
override fun onDestroy() {
super.onDestroy()
/*
* If listener is set deliver response
* */
if(onLoadingClosed != null){
onLoadingClosed?.onLoadingClosed()
}
}
override fun onResume() {
super.onResume()
/*
* If the window was closed before be created so finish it
* */
if(destroyWindow!!){
finish()
}
}
/*
* Static methods
* */
companion object {
/*
* Contains the activity shown
* */
private var currentActivity: Activity? = null
/*
* Flag to validate if the window has to finish or not
* */
private var destroyWindow:Boolean? = false
/*
* Listener when the loading window is closed
* */
private var onLoadingClosed:LoadingClosed? = null
/*
* Listener when the loading window is resume
* */
private var onLoadingReady:LoadingReady? = null
/*
* Contains the seconds to finish the window in case of timer
* */
private var seconds:Int = -1
/*
* Contains the icon loading size
* */
private var loadingIconWidth:Int = -1
private var loadingIconHeigt:Int = -1
private var loadinIconChangeSize:Boolean = false
/*
* Show the loading activity
* */
@JvmStatic
open fun show(activity: Activity) {
if(activity!=null){
/*
* If it is not visible
* */
if(currentActivity==null){
/*
* Reset flags
* */
destroyWindow = false
/*
* Show the loading activity
* */
val intent = Intent(activity, LoadingActivity::class.java)
activity.startActivity(intent)
}
}
}
/*
* Dismiss the loading activity
* */
@JvmStatic
open fun dismiss() {
if(currentActivity!=null){
/*
* Close the activity
* */
currentActivity?.finish()
/*
* Reset flags
* */
loadinIconChangeSize = false
currentActivity = null
destroyWindow = true
}
}
/*
* Change the loading icon size
* */
@JvmStatic
open fun loadingIconSize(width:Int,heigth:Int) {
/*
* The loading icon size wil change
* */
loadinIconChangeSize = true
/*
* Save the sizes
* */
loadingIconWidth = width
loadingIconHeigt = heigth
}
/*
* When the loading window is closed
* */
@JvmStatic
open fun onLoadingClosed(onLoadingClose: LoadingClosed) {
this.onLoadingClosed = onLoadingClose
}
/*
* When the loading window is up and visible
* */
@JvmStatic
open fun onLoadingReady(onLoadingResume:LoadingReady) {
this.onLoadingReady = onLoadingResume
}
/*
* Timer to close the window
* */
@JvmStatic
open fun closeOnTime(seconds:Int) {
LoadingActivity.seconds = seconds
}
}
/*
* Interface for all the events
* */
interface LoadingClosed{
fun onLoadingClosed()
}
interface LoadingReady{
fun onLoadingReady()
}
}

View file

@ -7,22 +7,18 @@ 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.application.CrystalSecurityMonitor;
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 {

View file

@ -1,5 +1,6 @@
package cy.agorise.crystalwallet.apigenerator;
import android.app.Activity;
import android.content.Context;
import java.io.Serializable;
@ -81,6 +82,30 @@ public abstract class GrapheneApiGenerator {
*/
private static HashMap<Long, SubscriptionListener> currentBitsharesListener = new HashMap<>();
/*
*
* To present erros to user
* */
private static Activity activity;
/*
*
* Interface to catch only errors in connection with sockets
* */
private static OnErrorWebSocket onErrorWebSocket;
/*
*
* Interface to catch both errors and success in connection with sockets
* */
private static OnResponsesWebSocket onResponsesWebSocker;
/**
* Retrieves the data of an account searching by it's id
*
@ -221,6 +246,8 @@ public abstract class GrapheneApiGenerator {
request.getListener().fail(request.getId());
}
}), CryptoNetManager.getURL(CryptoNet.BITSHARES));
thread.setActivity(activity); //To catch websocket errors to user interface
thread.setOnErrorWebSocker(onErrorWebSocket); //To deliver websocket errors to user interface
thread.start();
}
@ -703,4 +730,35 @@ public abstract class GrapheneApiGenerator {
}
}
public static void setActivity(Activity activity) {
GrapheneApiGenerator.activity = activity;
}
public static void setOnResponsesWebSocker(OnResponsesWebSocket onResponsesWebSocker) {
GrapheneApiGenerator.onResponsesWebSocker = onResponsesWebSocker;
}
public static void setOnErrorWebSocket(OnErrorWebSocket onErrorWebSocket) {
GrapheneApiGenerator.onErrorWebSocket = onErrorWebSocket;
}
/*
*
* Interface to catch errors in connection with sockets
* */
public interface OnErrorWebSocket {
void onError(Exception exception);
}
/*
*
* Interface to catch succesfully connection with sockets
* */
public interface OnResponsesWebSocket {
void onSuccess();
void onError(Exception exception);
}
}

View file

@ -1,5 +1,6 @@
package cy.agorise.crystalwallet.application;
import android.app.Activity;
import android.app.Application;
import android.content.Intent;
import android.content.res.Configuration;
@ -11,6 +12,7 @@ import com.idescout.sql.SqlScoutServer;
import java.util.Locale;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.enums.CryptoNet;
import cy.agorise.crystalwallet.models.BitsharesAsset;

View file

@ -0,0 +1,31 @@
package cy.agorise.crystalwallet.dialogs.material
import android.app.Activity
import cy.agorise.crystalwallet.R
import kotlinx.android.synthetic.main.account_seed_list.view.*
/*
* Dialog material that shows loading gif and and explicit message
* */
open class CrystalDialog : DialogMaterial{
constructor(activity: Activity) : super(activity) {
/*
* Prepare the dialog
* */
this.builder.title("")
this.builder.content("")
}
}
/*
* Internal interfaces
* */
interface PositiveResponse{
fun onPositive()
}
interface NegativeResponse{
fun onNegative()
}

View file

@ -0,0 +1,154 @@
package cy.agorise.crystalwallet.dialogs.material
import android.app.Activity
import com.afollestad.materialdialogs.MaterialDialog
import cy.agorise.crystalwallet.R
/*
*
* Controls the custom implementarion for all kind of material dialogs
* Reference in: https://github.com/afollestad/material-dialogs
*
* */
open abstract class DialogMaterial{
protected var builder: MaterialDialog.Builder //Contains the builder
protected lateinit var materialDialog: MaterialDialog //Contains the controller for the dialog
/*
* Contains the activity
* */
protected var activity:Activity;
/*
* Contains the response for positive button click
* */
var positiveResponse:PositiveResponse? = null
/*
* Contains the response for negative button click
* */
var negativeResponse:NegativeResponse? = null
constructor(activity: Activity) {
/*
* Save the activity
* */
this.activity = activity
/*
* Init the builder
* */
builder = MaterialDialog.Builder(activity)
}
/*
* Show the dialog
* */
fun show() {
/*
* If user wants positive and negative
* */
if(positiveResponse != null && negativeResponse != null){
/*
* Add positve
* */
builder.positiveText(activity.resources.getString(R.string.ok))
builder.onPositive { dialog, which ->
/*
* If response is not null deliver response
* */
if(positiveResponse != null){
positiveResponse!!.onPositive()
}
}
/*
* Add negative
* */
builder.negativeText(activity.resources.getString(R.string.cancel))
builder.onNegative { dialog, which ->
/*
* If response is not null deliver response
* */
if(negativeResponse != null){
negativeResponse!!.onNegative()
}
}
}
/*
* If user wants positive button
* */
if(positiveResponse != null){
builder.positiveText(activity.resources.getString(R.string.ok))
builder.onPositive { dialog, which ->
/*
* If response is not null deliver response
* */
if(positiveResponse != null){
positiveResponse!!.onPositive()
}
}
}
/*
* Build internal material dialog, this lets to show it
* */
this.build()
/*
* Show the dialog
* */
materialDialog.show()
}
/*
* Close the dialog
* */
fun dismiss() {
this.materialDialog.dismiss()
}
/*
* After the class is completed as needed, we need to call this method to join all together after show the
* childs implementations
* */
open fun build() {
this.materialDialog = this.builder.build()
}
/*
* Set indeterminate progress
*
* */
open fun progress(){
this.builder.progress(true, 0)
}
/*
* Setters and getters
* */
fun setText(message: String) {
this.builder.content(message)
}
fun setTitle(title: String) {
this.builder.title(title)
}
/*
* End of setters and getters
* */
}

View file

@ -0,0 +1,31 @@
package cy.agorise.crystalwallet.dialogs.material
import android.app.Activity
import android.widget.Toast
/*
* This class is an implementation of toast
* */
class ToastIt {
/*
* Satitic methods
* */
companion object {
/*
* Show long toast
* */
@JvmStatic fun showLongToast(activity: Activity, message:String) {
Toast.makeText(activity, message, Toast.LENGTH_LONG).show()
}
/*
* Show short toast
* */
@JvmStatic fun showShortToast(activity: Activity, message:String) {
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
}
}
}

View file

@ -1,16 +1,13 @@
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;
@ -21,9 +18,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnTextChanged;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.activities.CreateSeedActivity;
import cy.agorise.crystalwallet.application.CrystalSecurityMonitor;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.GeneralSetting;
import cy.agorise.crystalwallet.util.PasswordManager;
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;

View file

@ -32,6 +32,7 @@ import android.widget.Spinner;
import android.widget.TextView;
import com.google.zxing.Result;
import com.jaredrummler.materialspinner.MaterialSpinner;
import java.io.File;
import java.math.RoundingMode;
@ -73,7 +74,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
SendTransactionValidator sendTransactionValidator;
@BindView(R.id.spFrom)
Spinner spFrom;
MaterialSpinner spFrom;
@BindView(R.id.tvFromError)
TextView tvFromError;
@BindView(R.id.etTo)
@ -176,8 +177,27 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
CryptoNetAccountListViewModel cryptoNetAccountListViewModel = ViewModelProviders.of(this).get(CryptoNetAccountListViewModel.class);
List<CryptoNetAccount> cryptoNetAccounts = cryptoNetAccountListViewModel.getCryptoNetAccountList();
CryptoNetAccountAdapter fromSpinnerAdapter = new CryptoNetAccountAdapter(this.getContext(), android.R.layout.simple_spinner_item, cryptoNetAccounts);
spFrom.setAdapter(fromSpinnerAdapter);
spFrom.setSelection(0);
//spFrom.setAdapter(fromSpinnerAdapter);
//spFrom.setSelection(0);
/*
* Custom material spinner implementation
* */
spFrom.setItems(cryptoNetAccounts);
spFrom.setSelectedIndex(0);
spFrom.setOnItemSelectedListener(new MaterialSpinner.OnItemSelectedListener<CryptoNetAccount>() {
@Override
public void onItemSelected(MaterialSpinner view, int position, long id, CryptoNetAccount item) {
sendTransactionValidator.validate();
}
});
spFrom.setOnNothingSelectedListener(new MaterialSpinner.OnNothingSelectedListener() {
@Override public void onNothingSelected(MaterialSpinner spinner) {
}
});
// etFrom.setText(this.grapheneAccount.getName());
}
@ -230,10 +250,10 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
}
}
@OnItemSelected(R.id.spFrom)
/*@OnItemSelected(R.id.spFrom)
public void afterFromSelected(Spinner spinner, int position) {
this.sendTransactionValidator.validate();
}
}*/
@OnTextChanged(value = R.id.etTo,
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
@ -311,7 +331,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
@OnClick(R.id.btnSend)
public void sendTransaction(){
if (this.sendTransactionValidator.isValid()) {
CryptoNetAccount fromAccountSelected = (CryptoNetAccount) spFrom.getSelectedItem();
CryptoNetAccount fromAccountSelected = (CryptoNetAccount) spFrom.getItems().get(spFrom.getSelectedIndex());
/*

View file

@ -0,0 +1,56 @@
package cy.agorise.crystalwallet.models;
import android.view.View;
public class FieldValidatorModel {
/*
* Determine if the field is valid
* */
private boolean valid;
/*
* Contains the message of the error
* */
private String message;
/*
* Setters and getters
* */
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/*
* End of setters and getters
* */
/*
* Set tha the field is invalid
* */
final public void setInvalid(){
this.valid = false;
}
/*
* Set tha the field is valid
* */
final public void setValid(){
this.valid = true;
}
}

View file

@ -1,5 +1,6 @@
package cy.agorise.crystalwallet.network;
import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator;
import cy.agorise.crystalwallet.enums.CryptoNet;
import cy.agorise.graphenej.interfaces.WitnessResponseListener;
import cy.agorise.graphenej.models.BaseResponse;
@ -23,15 +24,21 @@ public class BitsharesCryptoNetVerifier extends CryptoNetVerifier {
private final String CHAIN_ID = "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8";//testnet
//private final String CHAIN_ID = "4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8";//mainnet
@Override
public void checkURL(final String url) {
public BitsharesCryptoNetVerifier(){
/**/
final long startTime = System.currentTimeMillis();
WebSocketThread thread = new WebSocketThread(new GetChainId(new WitnessResponseListener() {
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);
CryptoNetManager.verifiedCryptoNetURL(cryptoNet, null, 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
@ -43,8 +50,15 @@ public class BitsharesCryptoNetVerifier extends CryptoNetVerifier {
public void onError(BaseResponse.Error error) {
//TODO handle error
}
}),url);
thread.start();
}),null);
}
@Override
public void checkURL(final String url) {
thread.setmUrl(url); //Set the url
thread.start(); //Run the thread connection
}
@Override

View file

@ -1,14 +1,14 @@
package cy.agorise.crystalwallet.network;
import android.app.Activity;
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.apigenerator.GrapheneApiGenerator;
import cy.agorise.crystalwallet.enums.CryptoNet;
/**
@ -61,11 +61,51 @@ public abstract class CryptoNetManager {
}
}
public static void addCryptoNetURL(CryptoNet crypto, String[] urls){
/*
* Add url with listener on error only for sockets
* */
public static void addCryptoNetURL(CryptoNet crypto,
String[] urls,
final Activity activity,
final GrapheneApiGenerator.OnErrorWebSocket onErrorWebSocker,
final boolean showNormalError){
addCryptoNetURL(crypto,urls,activity,onErrorWebSocker,null,showNormalError);
}
/*
* Add url with listener on error and response for sockets
* */
public static void addCryptoNetURL(CryptoNet crypto,
String[] urls,
final Activity activity,
final GrapheneApiGenerator.OnResponsesWebSocket onResponsesWebSocket,
final boolean showNormalError){
addCryptoNetURL(crypto,urls,activity,null,onResponsesWebSocket,showNormalError);
}
/*
* Utility for above methods
*
* */
public static void addCryptoNetURL(CryptoNet crypto,
String[] urls,
final Activity activity,
final GrapheneApiGenerator.OnErrorWebSocket onErrorWebSocker,
final GrapheneApiGenerator.OnResponsesWebSocket onResponsesWebSocket,
final boolean showNormalError) {
if (!CryptoNetURLs.containsKey(crypto)) {
CryptoNetURLs.put(crypto, new HashSet<String>());
}
CryptoNetVerifier verifier = CryptoNetVerifier.getNetworkVerify(crypto);
verifier.getThread().setActivity(activity); //Logical connection to ui
verifier.getThread().setOnErrorWebSocker(onErrorWebSocker); //Connect response web socket error to ui response
verifier.getThread().setOnResponsesWebSocket(onResponsesWebSocket); //Connect response and error web socket error to ui response
verifier.getThread().setShowNormalMessage(showNormalError); //Not show native message error, we handle it
for (String url : urls) {
CryptoNetURLs.get(crypto).add(url);
@ -73,8 +113,11 @@ public abstract class CryptoNetManager {
verifier.checkURL(url);
}
}
}
public static void removeCryptoNetURL(CryptoNet crypto, String url){
if(CryptoNetURLs.containsKey(crypto)){
CryptoNetURLs.get(crypto).remove(url);
@ -145,5 +188,4 @@ public abstract class CryptoNetManager {
return (int) (this.getTime() - testedURL.getTime());
}
}
}

View file

@ -1,5 +1,8 @@
package cy.agorise.crystalwallet.network;
import android.app.Activity;
import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator;
import cy.agorise.crystalwallet.enums.CryptoNet;
/**
@ -12,6 +15,14 @@ import cy.agorise.crystalwallet.enums.CryptoNet;
public abstract class CryptoNetVerifier {
/*
* Contains the worker connection thread
*/
protected WebSocketThread thread;
static CryptoNetVerifier getNetworkVerify(CryptoNet cryptoNet){
if(cryptoNet.getLabel().equals(CryptoNet.BITSHARES.getLabel())){
return new BitsharesCryptoNetVerifier();
@ -22,4 +33,9 @@ public abstract class CryptoNetVerifier {
public abstract void checkURL(final String url);
public abstract String getChainId();
public WebSocketThread getThread() {
return thread;
}
}

View file

@ -1,15 +1,19 @@
package cy.agorise.crystalwallet.network;
import android.app.Activity;
import android.util.Log;
import android.widget.Toast;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory;
import com.neovisionaries.ws.client.WebSocketListener;
import java.io.IOException;
import java.util.HashMap;
import cy.agorise.crystalwallet.activities.LoadingActivity;
import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator;
/**
* Created by henry on 8/10/2017.
*/
@ -33,6 +37,34 @@ public class WebSocketThread extends Thread {
// If the parameters of this class can be change
private boolean canChange = true;
/*
*
* Interface to catch only errors in connection with sockets
* */
private GrapheneApiGenerator.OnErrorWebSocket onErrorWebSocker;
/*
*
* Interface to catch errors and success responses in connection with sockets
* */
private GrapheneApiGenerator.OnResponsesWebSocket onResponsesWebSocket;
/*
* To catch websocket errors
* */
private Activity activity;
/*
* To show normal error message or not
* */
private boolean showNormalMessage = true;
/*
* Object needed for socket connection
* */
private WebSocketFactory factory;
/**
* Basic constructor,
@ -43,10 +75,20 @@ public class WebSocketThread extends Thread {
* @param url The url to connect
*/
public WebSocketThread(WebSocketListener webSocketListener, String url) {
try {
WebSocketFactory factory = new WebSocketFactory().setConnectionTimeout(5000);
this.mUrl = url;
/*
* The listener always can be setted
* */
this.mWebSocketListener = webSocketListener;
/*
*
* If at this point the url is not defined, this will be set after
* */
if(url!=null){
try {
factory = new WebSocketFactory().setConnectionTimeout(5000);
this.mUrl = url;
this.mWebSocket = factory.createSocket(this.mUrl);
this.mWebSocket.addListener(this.mWebSocketListener);
} catch (IOException e) {
@ -55,6 +97,7 @@ public class WebSocketThread extends Thread {
Log.e(TAG, "NullPointerException at WebsocketWorkerThreas. Msg: "+e.getMessage());
}
}
}
/**
* Gets the current url where the websocket will connect
@ -110,16 +153,62 @@ public class WebSocketThread extends Thread {
@Override
public void run() {
canChange = false;
// Moves the current Thread into the background
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
try {
/*
* If the initialization of the socket comes after
* */
if(factory==null){
factory = new WebSocketFactory().setConnectionTimeout(5000);
this.mWebSocket = factory.createSocket(this.mUrl);
this.mWebSocket.addListener(this.mWebSocketListener);
}
WebSocketThread.currentThreads.put(this.getId(),this);
mWebSocket.connect();
} catch (WebSocketException e) {
/*
*
* Websocket success response
* */
if(onResponsesWebSocket!=null){
onResponsesWebSocket.onSuccess();
}
} catch (final Exception e) {
Log.e(TAG, "WebSocketException. Msg: "+e.getMessage());
} catch(NullPointerException e){
Log.e(TAG, "NullPointerException. Msg: "+e.getMessage());
//Deliver error to user
if(activity!=null){
/*
* Show error to user if aplies
* */
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if(showNormalMessage){
Toast.makeText(activity, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
});
/*Deliver response in the listeners*/
if(onErrorWebSocker!=null){
onErrorWebSocker.onError(e);
}
else if(onResponsesWebSocket!=null){
onResponsesWebSocket.onError(e);
}
}
}
WebSocketThread.currentThreads.remove(this.getId());
}
@ -127,4 +216,25 @@ public class WebSocketThread extends Thread {
public boolean isConnected(){
return mWebSocket.isOpen();
}
public void setOnErrorWebSocker(GrapheneApiGenerator.OnErrorWebSocket onErrorWebSocker) {
this.onErrorWebSocker = onErrorWebSocker;
}
public void setActivity(Activity activity) {
this.activity = activity;
}
public void setShowNormalMessage(boolean showNormalMessage) {
this.showNormalMessage = showNormalMessage;
}
public void setmUrl(String mUrl) {
this.mUrl = mUrl;
}
public void setOnResponsesWebSocket(GrapheneApiGenerator.OnResponsesWebSocket onResponsesWebSocket) {
this.onResponsesWebSocket = onResponsesWebSocket;
}
}

View file

@ -1,5 +1,7 @@
package cy.agorise.crystalwallet.requestmanagers;
import android.app.Activity;
import cy.agorise.crystalwallet.enums.CryptoCoin;
/**
@ -19,6 +21,13 @@ public abstract class CryptoNetInfoRequest {
*/
protected CryptoNetInfoRequestListener listener;
protected CryptoNetInfoRequest(CryptoCoin coin){
this.coin = coin;
}
@ -31,4 +40,5 @@ public abstract class CryptoNetInfoRequest {
listener.onCarryOut();
CryptoNetInfoRequests.getInstance().removeRequest(this);
}
}

View file

@ -0,0 +1,94 @@
package cy.agorise.crystalwallet.tests.activities.dialogs
import android.os.Bundle
import android.widget.Toast
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.activities.CustomActivity
import cy.agorise.crystalwallet.dialogs.material.CrystalDialog
import cy.agorise.crystalwallet.dialogs.material.NegativeResponse
import cy.agorise.crystalwallet.dialogs.material.PositiveResponse
/*
* Class to test CrystalDialog
* */
class Test_CrystalDialogActivity : CustomActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.empty_activity)
//show()
//showOKDialog()
//showOKCancelDialog()
//showProgressIndeterminate()
}
/*
*
* Show the simplest dialog
*
* */
fun show(){
var crytalDialog:CrystalDialog = CrystalDialog(this)
crytalDialog.setTitle("Title")
crytalDialog.setText("Text")
crytalDialog.show()
//crytalDialog.dismiss()
}
/*
*
* Show the accept dialog
*
* */
fun showOKDialog(){
var crytalDialog:CrystalDialog = CrystalDialog(this)
crytalDialog.setTitle("Title")
crytalDialog.setText("Text")
crytalDialog.positiveResponse = object:PositiveResponse{
override fun onPositive() {
Toast.makeText(globalActivity, "CrystalDialog Positive clicked", Toast.LENGTH_LONG).show()
}
}
crytalDialog.show()
}
/*
*
* Show the accept and cancel dialog
*
* */
fun showOKCancelDialog(){
var crytalDialog:CrystalDialog = CrystalDialog(this)
crytalDialog.setTitle("Title")
crytalDialog.setText("Text")
crytalDialog.positiveResponse = object:PositiveResponse{
override fun onPositive() {
Toast.makeText(globalActivity, "CrystalDialog Positive clicked", Toast.LENGTH_LONG).show()
}
}
crytalDialog.negativeResponse = object:NegativeResponse{
override fun onNegative() {
Toast.makeText(globalActivity, "CrystalDialog Negative clicked", Toast.LENGTH_LONG).show()
}
}
crytalDialog.show()
}
/*
*
* Show the indeterminate dialog with text
*
* */
fun showProgressIndeterminate(){
var crytalDialog:CrystalDialog = CrystalDialog(this)
crytalDialog.setText("Loading...")
crytalDialog.progress()
crytalDialog.show()
}
}

View file

@ -0,0 +1,38 @@
package cy.agorise.crystalwallet.tests.activities.dialogs
import android.os.Bundle
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.activities.CustomActivity
import cy.agorise.crystalwallet.dialogs.material.DialogMaterial
/*
* Class to test DialogMaterial.kt
* */
class Test_DialogMaterialActivity : CustomActivity() {
/*
* Object to be tested
* */
lateinit var dialogMaterial: DialogMaterial;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.empty_activity)
}
/*
* This class can not be instantiate,
* this methos is commented to prevent compilation error, if uncommented it should
* throw error compilations and based on this this assertion is complete
*
* */
fun instiantiation(){
//dialogMaterial = DialogMaterial(this)
}
}

View file

@ -0,0 +1,44 @@
package cy.agorise.crystalwallet.tests.activities.dialogs
import android.os.Bundle
import android.view.View
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.activities.CustomActivity
import kotlinx.android.synthetic.main.empty_activity.*
/*
* Unit test for class GIFView
* */
class Test_GIFActivity : CustomActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.empty_activity)
/*
* For testings purpouses
* */
gifView.visibility = View.VISIBLE
load()
//loadWithContainer()
}
/*
* Load normaly the gif
* */
fun load(){
gifView.load(R.raw.burbujas)
}
/*
* Load with fit into container
* */
fun loadWithContainer(){
gifView.centerCrop()
gifView.load(R.raw.burbujas)
}
}

View file

@ -0,0 +1,78 @@
package cy.agorise.crystalwallet.tests.activities.dialogs
import android.os.Bundle
import android.widget.Toast
import cy.agorise.crystalwallet.activities.CustomActivity
import cy.agorise.crystalwallet.activities.LoadingActivity
/*
* Class to test LoadingActivity
* */
class Test_LoadingActivity : CustomActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
show()
//withTimer()
//onLoadingClose()
//onLoadingReady()
//sizeInLoadingIcon()
}
/*
* Show the simple loading graphic
* */
fun show(){
LoadingActivity.show(globalActivity)
//LoadingActivity.dismiss() //For testing porpouse
}
/*
* Loading with timer
* */
fun withTimer(){
LoadingActivity.closeOnTime(3)
LoadingActivity.show(globalActivity)
}
/*
* Listener when the loading window is closed
* */
fun onLoadingClose(){
LoadingActivity.closeOnTime(3)
LoadingActivity.onLoadingClosed(object : LoadingActivity.LoadingClosed{
override fun onLoadingClosed() {
Toast.makeText(globalActivity, "onLoadingClosed event fired", Toast.LENGTH_LONG).show()
}
})
LoadingActivity.show(globalActivity)
}
/*
* Listener when the loading window is resume
* */
fun onLoadingReady(){
LoadingActivity.onLoadingReady(object : LoadingActivity.LoadingReady{
override fun onLoadingReady() {
Toast.makeText(globalActivity, "onLoadingReady event fired", Toast.LENGTH_LONG).show()
}
})
LoadingActivity.show(globalActivity)
}
/*
* Set specified size to the loading icon
* */
fun sizeInLoadingIcon(){
LoadingActivity.loadingIconSize(30,30)
LoadingActivity.show(globalActivity)
}
}

View file

@ -0,0 +1,25 @@
package cy.agorise.crystalwallet.tests.activities.dialogs
import android.os.Bundle
import cy.agorise.crystalwallet.activities.CustomActivity
/*
* Class to test all network implementation
* */
class Test_NetworkActivity:CustomActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
fun testServerConnection(){
}
}

View file

@ -0,0 +1,34 @@
package cy.agorise.crystalwallet.tests.activities.dialogs
import android.os.Bundle
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.activities.CustomActivity
import cy.agorise.crystalwallet.dialogs.material.ToastIt
class Test_ToastActivity : CustomActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.empty_activity)
//showShort()
showLongShort()
}
/*
* Show simple short toast
* */
fun showShort(){
ToastIt.showShortToast(this,"showShortToast")
}
/*
* Show simple short toast
* */
fun showLongShort(){
ToastIt.showShortToast(this,"showLongShort")
}
}

View file

@ -0,0 +1,53 @@
package cy.agorise.crystalwallet.tests.activities.dialogs
import android.net.Uri
import android.os.Bundle
import android.view.View
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.activities.CustomActivity
import kotlinx.android.synthetic.main.empty_activity.*
/*
* Class for test VideoExView
* */
class Test_VideoActivity : CustomActivity() {
/*
* cy.agorise.crystalwallet.views.natives.VideoViewEx
* should be used as view to get the new implementations
* */
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.empty_activity)
/*
* For testing purpouses
* */
video.visibility = View.VISIBLE
//play()
playIndeterminate()
}
/*
* Just one time play
* */
fun play(){
video.setVideoRaw(R.raw.appbar_background)
video.start()
}
/*
* Just one time play
* */
fun playIndeterminate(){
video.setVideoRaw(R.raw.appbar_background)
video.playContinius()
}
}

View file

@ -0,0 +1,38 @@
package cy.agorise.crystalwallet.util
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidator
import java.util.ArrayList
class FieldsValidator {
/*
* Contains the fields to validate
* */
private var fields: MutableList<UIValidator> = ArrayList()
/*
* Setters and getters
* */
fun setFields(fields: List<UIValidator>) {
this.fields = fields as MutableList<UIValidator>
}
/*
* Endo of setters and getters
* */
/*
* Validate all the fields
* */
fun validate() {
for (uiValidator in fields) {
uiValidator.validate()
}
}
/*
* Add component to the list
* */
fun add(uiValidator: UIValidator) {
this.fields.add(uiValidator)
}
}

View file

@ -0,0 +1,72 @@
package cy.agorise.crystalwallet.util
import android.app.Activity
import android.widget.Toast
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator
import cy.agorise.crystalwallet.application.CrystalApplication
import cy.agorise.crystalwallet.enums.CryptoNet
import cy.agorise.crystalwallet.network.CryptoNetManager
/*
*
* Static methods for network utility
* */
class NetworkUtility {
/*
* Satitic methods
* */
companion object {
/*
* Test connection with server
* */
@JvmStatic fun testServerConnnection(activity:Activity){
val onErrorWebSocker = GrapheneApiGenerator.OnErrorWebSocket {
/*
* Show message to client
* */
activity.runOnUiThread(Runnable { Toast.makeText(activity, activity.getResources().getString(R.string.network_err_no_server_connection), Toast.LENGTH_LONG).show() })
}
CryptoNetManager.addCryptoNetURL(CryptoNet.BITSHARES, CrystalApplication.BITSHARES_TESTNET_URL, activity, onErrorWebSocker, false)
}
/*
* Test connection with server and custom implementation callback
* */
@JvmStatic fun testServerConnnection(activity:Activity, onResponseWebSocket: GrapheneApiGenerator.OnResponsesWebSocket){
CryptoNetManager.addCryptoNetURL(CryptoNet.BITSHARES, CrystalApplication.BITSHARES_TESTNET_URL, activity, onResponseWebSocket, false)
}
/*
* Test connection with server and custom implementation callback and with normal error
* */
@JvmStatic fun testServerConnnectionNormalError(activity:Activity, onResponseWebSocket: GrapheneApiGenerator.OnResponsesWebSocket){
/*
*
* Listener to catch the error and show the normal user error message
*
* */
val onErrorWebSocker = GrapheneApiGenerator.OnErrorWebSocket {
/*
* Show message to client
* */
activity.runOnUiThread(Runnable { Toast.makeText(activity, activity.getResources().getString(R.string.network_err_no_server_connection), Toast.LENGTH_LONG).show() })
}
/*
* Request
* */
CryptoNetManager.addCryptoNetURL( CryptoNet.BITSHARES,
CrystalApplication.BITSHARES_TESTNET_URL,
activity,
onErrorWebSocker,
onResponseWebSocket,
false)
}
}
}

View file

@ -1,39 +0,0 @@
package cy.agorise.crystalwallet.viewmodels;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.AccountSeed;
/**
* Created by Henry Varona on 27/9/2017.
*/
public class AccountSeedViewModel extends AndroidViewModel {
private LiveData<AccountSeed> accountSeed;
private CrystalDatabase db;
private Application app;
public AccountSeedViewModel(Application application) {
super(application);
this.db = CrystalDatabase.getAppDatabase(application.getApplicationContext());
this.app = application;
}
public void loadSeed(long seedId){
this.accountSeed = this.db.accountSeedDao().findByIdLiveData(seedId);
}
public void addSeed(AccountSeed seed){
long newId = this.db.accountSeedDao().insertAccountSeed(seed);
seed.setId(newId);
}
public LiveData<AccountSeed> getAccountSeed(){
return this.accountSeed;
}
}

View file

@ -0,0 +1,39 @@
package cy.agorise.crystalwallet.viewmodels
import android.app.Application
import android.arch.lifecycle.AndroidViewModel
import android.arch.lifecycle.LiveData
import cy.agorise.crystalwallet.dao.CrystalDatabase
import cy.agorise.crystalwallet.models.AccountSeed
class AccountSeedViewModel : AndroidViewModel {
private var accountSeed: LiveData<AccountSeed>? = null
private val db: CrystalDatabase
private val app: Application
constructor(application: Application,db:CrystalDatabase): super(application) {
this.app = application;
this.db = db;
}
fun loadSeed(seedId: Long) {
this.accountSeed = this.db.accountSeedDao().findByIdLiveData(seedId)
}
fun addSeed(seed: AccountSeed) {
val newId = this.db.accountSeedDao().insertAccountSeed(seed)
seed.id = newId
}
fun getAccountSeed(): LiveData<AccountSeed>? {
return this.accountSeed
}
}

View file

@ -4,6 +4,8 @@ import android.content.Context;
import android.widget.EditText;
import android.widget.Spinner;
import com.jaredrummler.materialspinner.MaterialSpinner;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.AmountValidationField;
import cy.agorise.crystalwallet.viewmodels.validators.validationfields.AssetValidationField;
@ -20,7 +22,7 @@ public class SendTransactionValidator extends UIValidator {
private CryptoNetAccount account;
public SendTransactionValidator(Context context, CryptoNetAccount account, Spinner fromEdit, EditText toEdit, Spinner assetSpinner, EditText amountEdit, EditText memoEdit){
public SendTransactionValidator(Context context, CryptoNetAccount account, MaterialSpinner fromEdit, EditText toEdit, Spinner assetSpinner, EditText amountEdit, EditText memoEdit){
super(context);
this.account = account;
this.addField(new FromValidationField(fromEdit));

View file

@ -0,0 +1,10 @@
package cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces
/*
* Interface that all the views that need validation can use
* */
interface UIValidator {
fun validate()
}

View file

@ -0,0 +1,14 @@
package cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.validationFields.CustomValidationField
/*
* Listener to deliver response to controls from inner validations
* */
interface UIValidatorListener {
fun onValidationFailed(customValidationField: CustomValidationField)
fun onValidationSucceeded(customValidationField: CustomValidationField)
}

View file

@ -0,0 +1,265 @@
package cy.agorise.crystalwallet.viewmodels.validators.customImpl.validationFields
import android.app.Activity
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator
import cy.agorise.crystalwallet.dialogs.material.CrystalDialog
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests
import cy.agorise.crystalwallet.requestmanagers.ValidateExistBitsharesAccountRequest
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidator
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidatorListener
import cy.agorise.crystalwallet.views.natives.CustomTextInputEditText
/*
*
* Validation layer for Account Name
* */
class BitsharesAccountNameValidation : CustomValidationField, UIValidator {
/*
* Contains the field to validate
* */
private val accountNameField: CustomTextInputEditText
/*
* Interface to validate when an account exist an take over control it
* */
private var onAccountExist: OnAccountExist? = null
constructor ( activity: Activity,
accountNameField: CustomTextInputEditText,
uiValidatorListener: UIValidatorListener) : super(activity) {
this.accountNameField = accountNameField
this.uiValidatorListener = uiValidatorListener
/*
* The current view for errors will be this
* */
this.currentView = this.accountNameField
}
override fun validate() {
val newValue = accountNameField.text.toString()
/*
Contains the validation result
*/
var result = true
/*
* Validate empty field
* */
if (newValue == "") {
/*
* Validation not passed
* */
result = false
accountNameField.fieldValidatorModel.setInvalid()
accountNameField.fieldValidatorModel.message = this.accountNameField.resources.getString(R.string.create_account_window_err_account_empty)
} else {
/*
* Remove error
* */
accountNameField.error = null
/*
Validate at least min length
*/
if (newValue.length < 10) {
/*
* Validation not passed
* */
result = false
accountNameField.fieldValidatorModel.setInvalid()
accountNameField.fieldValidatorModel.message = this.accountNameField.resources.getString(R.string.create_account_window_err_min_account_name_len)
} else {
/*
* Remove error
* */
accountNameField.error = null
/*
Validate at least one character
*/
if (!newValue.matches(".*[a-zA-Z]+.*".toRegex())) {
/*
* Validation not passed
* */
result = false
accountNameField.fieldValidatorModel.setInvalid()
accountNameField.fieldValidatorModel.message = this.accountNameField.resources.getString(R.string.create_account_window_err_at_least_one_character)
} else {
/*
* Remove error
* */
accountNameField.error = null
/*
Validate at least one number for the account string
*/
if (!newValue.matches(".*\\d+.*".toRegex())) {
/*
* Validation not passed
* */
result = false
accountNameField.fieldValidatorModel.setInvalid()
accountNameField.fieldValidatorModel.message = this.accountNameField.resources.getString(R.string.create_account_window_err_at_least_one_number)
} else {
/*
* Remove error
* */
accountNameField.error = null
/*
Validate at least one middle script
*/
if (!newValue.contains("-")) {
/*
* Validation not passed
* */
result = false
accountNameField.fieldValidatorModel.setInvalid()
accountNameField.fieldValidatorModel.message = this.accountNameField.resources.getString(R.string.create_account_window_err_at_least_one_script)
} else {
/*
* Remove error
* */
accountNameField.error = null
}
}
}
}
}
/*
* If passed first validations
* */
if (!result) {
/*
* Deliver result
* */
if (uiValidatorListener != null) {
uiValidatorListener.onValidationFailed(this)
}
} else {
/*
* Show the dialog for connection with the server
* */
val creatingAccountMaterialDialog = CrystalDialog(activity)
creatingAccountMaterialDialog.setText(activity.resources.getString(R.string.window_create_seed_Server_validation))
creatingAccountMaterialDialog.build()
creatingAccountMaterialDialog.show()
val request = ValidateExistBitsharesAccountRequest(newValue)
request.setListener {
/*
* Dismiss the dialog of loading
* */
creatingAccountMaterialDialog.dismiss()
if (request.accountExists) {
/*
* The account exists and is not valid
* */
accountNameField.fieldValidatorModel.setInvalid()
accountNameField.fieldValidatorModel.message = accountNameField.resources.getString(R.string.account_name_already_exist)
/*
* Deliver the response
* */
if (uiValidatorListener != null) {
uiValidatorListener.onValidationFailed(globalCustomValidationField)
}
/*
* Deliver response to local callback
* */
if (onAccountExist != null) {
onAccountExist!!.onAccountExists()
}
} else {
/*
* Passed all validations
* */
accountNameField.fieldValidatorModel.setValid()
/*
* Deliver the response
* */
if (uiValidatorListener != null) {
uiValidatorListener.onValidationSucceeded(globalCustomValidationField)
}
}
}
/*
* Listener for websocket error
* */
GrapheneApiGenerator.setActivity(activity); //Set the activity to catch errors
val onErrorWebSocker = object : GrapheneApiGenerator.OnErrorWebSocket {
override fun onError(exception: java.lang.Exception?) {
/*
*
* Hide loading dialog
*
* */
creatingAccountMaterialDialog.dismiss();
}
}
GrapheneApiGenerator.setOnErrorWebSocket(onErrorWebSocker); //Set the activity to catch errors
/*
*
* Run thread*/
CryptoNetInfoRequests.getInstance().addRequest(request)
}/*
* Passed initial validations, next final validations
* */
}
/*
* Setters and getters
* */
fun setOnAccountExist(onAccountExist: OnAccountExist) {
this.onAccountExist = onAccountExist
}
/*
* End of setters and getters
* */
/*
* Interface to validate when an account exist an take over control it
* */
open interface OnAccountExist {
fun onAccountExists()
}
}

View file

@ -0,0 +1,46 @@
package cy.agorise.crystalwallet.viewmodels.validators.customImpl.validationFields
import android.app.Activity
import android.view.View
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidatorListener
open class CustomValidationField {
/*
* Listener to deliver response to controller
* */
protected lateinit var uiValidatorListener: UIValidatorListener
/*
* Contains the field to validate
* */
@JvmField var currentView : View? = null
/*
* Contains a handler to my self
* */
@JvmField protected var globalCustomValidationField: CustomValidationField
/*
* Contains the acivity for utility
* */
@JvmField protected var activity: Activity
constructor(activity:Activity){
/*
* Save the activity
* */
this.activity = activity
/*
* Init the custom field for later references
* */
this.globalCustomValidationField = this
}
}

View file

@ -0,0 +1,135 @@
package cy.agorise.crystalwallet.viewmodels.validators.customImpl.validationFields
import android.app.Activity
import cy.agorise.crystalwallet.R
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidator
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidatorListener
import cy.agorise.crystalwallet.views.natives.CustomTextInputEditText
/*
* Validate PIN and PIN confirmation
* */
class PinDoubleConfirmationValidationField : CustomValidationField, UIValidator {
/*
* Contain the fields to validate
* */
private val pinField: CustomTextInputEditText
private val pinConfirmationField: CustomTextInputEditText
constructor(activity: Activity,
pinField: CustomTextInputEditText,
pinConfirmationField: CustomTextInputEditText,
pinDoubleConfirmationInterface: UIValidatorListener) : super(activity) {
this.pinField = pinField
this.pinConfirmationField = pinConfirmationField
this.uiValidatorListener = pinDoubleConfirmationInterface
}
override fun validate() {
val pin = pinField.text.toString().trim { it <= ' ' }
val pinConfirmation = pinConfirmationField.text.toString().trim { it <= ' ' }
/*
* Contains the result for the validations
* */
var result = true
/*
Check if the two fields are equals theme selfs
* */
if (pin.length < 5) {
/*
*
* False validation
* */
pinField.fieldValidatorModel.message = this.pinField.context.resources.getString(R.string.create_account_window_err_at_least_pin_characters)
result = false
/*
* The current view for error
* */
this.currentView = pinField
} else {
/*Remove the error*/
pinField.error = null
/*
* Same validation for PIN Confirmation
* */
if (pinConfirmation.length < 5) {
/*
*
* False validation
* */
pinConfirmationField.fieldValidatorModel.message = this.pinField.context.resources.getString(R.string.create_account_window_err_at_least_pin_characters)
result = false
/*
* The current view for error
* */
this.currentView = pinConfirmationField
} else {
/*Remove the error*/
pinField.error = null
/*
* Final validation, check if the PINs are equals
*
* */
if (!pin.isEmpty() && !pinConfirmation.isEmpty() && pinConfirmation.compareTo(pin) != 0) {
/*
*
* False validation
* */
pinField.fieldValidatorModel.message = this.pinField.context.resources.getString(R.string.mismatch_pin)
pinConfirmationField.fieldValidatorModel.message = this.pinField.context.resources.getString(R.string.mismatch_pin)
result = false
/*
* The current view for error
* */
this.currentView = pinConfirmationField
}
}
}
/*
* Passed validations
* */
if (result) {
pinField.fieldValidatorModel.setValid()
pinConfirmationField.fieldValidatorModel.setValid()
/*
* Connect response to controller
* */
if (uiValidatorListener != null) {
uiValidatorListener.onValidationSucceeded(this)
}
} else {
/*
* Connect response to controller
* */
if (uiValidatorListener != null) {
uiValidatorListener.onValidationFailed(this)
}
}/*
* Not passed validations
* */
}
}

View file

@ -21,15 +21,47 @@ public class BitsharesAccountNameDoesntExistsValidationField extends ValidationF
}
public void validate(){
final String newValue = accountNameField.getText().toString();
this.setLastValue(newValue);
this.startValidating();
/*
* Validate empty field
* */
if (newValue.equals("")){
setValidForValue("", false);
setMessageForValue("","");
validator.validationFailed(this);
} else {
}
/*
Validate at least min length
*/
else if(newValue.length()<10){
setValidForValue("", false);
setMessageForValue(validator.getContext().getResources().getString(R.string.create_account_window_err_min_account_name_len),"");
validator.validationFailed(this);
}
/*
Validate at least one number for the account string
*/
else if(!newValue.matches(".*\\\\d+.*")){
setValidForValue("", false);
setMessageForValue(validator.getContext().getResources().getString(R.string.create_account_window_err_at_least_one_number),"");
validator.validationFailed(this);
}
/*
Validate at least one middle script
*/
else if(!newValue.contains("-")){
setValidForValue("", false);
setMessageForValue(accountNameField.getContext().getResources().getString(R.string.create_account_window_err_at_least_one_number),"");
validator.validationFailed(this);
}
/*
* Passed all primary validations
* */
else {
final ValidationField field = this;
@ -37,9 +69,15 @@ public class BitsharesAccountNameDoesntExistsValidationField extends ValidationF
request.setListener(new CryptoNetInfoRequestListener() {
@Override
public void onCarryOut() {
if (request.getAccountExists()) {
/*
* The account exists and is not valid
* */
setMessageForValue(newValue,validator.getContext().getResources().getString(R.string.account_name_already_exist,"'"+newValue+"'"));
setValidForValue(newValue, false);
} else {
setValidForValue(newValue, true);
}

View file

@ -2,7 +2,10 @@ package cy.agorise.crystalwallet.viewmodels.validators.validationfields;
import android.widget.Spinner;
import com.jaredrummler.materialspinner.MaterialSpinner;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestListener;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.requestmanagers.ValidateExistBitsharesAccountRequest;
@ -14,9 +17,9 @@ import cy.agorise.crystalwallet.requestmanagers.ValidateExistBitsharesAccountReq
public class FromValidationField extends ValidationField {
//private EditText fromField;
private Spinner fromField;
private MaterialSpinner fromField;
public FromValidationField(Spinner fromField){
public FromValidationField(MaterialSpinner fromField){
super(fromField);
this.fromField = fromField;
}
@ -24,8 +27,9 @@ public class FromValidationField extends ValidationField {
public void validate(){
final String newValue;
if (fromField.getSelectedItem() != null) {
newValue = fromField.getSelectedItem().toString();
if (fromField.getSelectedIndex() != -1) {
final CryptoNetAccount cryptoNetAccount = (CryptoNetAccount) fromField.getItems().get(fromField.getSelectedIndex());
newValue = cryptoNetAccount.getName();
} else {
newValue = "";
}

View file

@ -0,0 +1,11 @@
package cy.agorise.crystalwallet.viewmodels.validators.validationfields;
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidator;
public class PinValidationField_ implements UIValidator {
@Override
public void validate() {
}
}

View file

@ -3,7 +3,10 @@ package cy.agorise.crystalwallet.viewmodels.validators.validationfields;
import android.widget.EditText;
import android.widget.Spinner;
import com.jaredrummler.materialspinner.MaterialSpinner;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestListener;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.requestmanagers.ValidateExistBitsharesAccountRequest;
@ -14,10 +17,10 @@ import cy.agorise.crystalwallet.requestmanagers.ValidateExistBitsharesAccountReq
public class ToValidationField extends ValidationField {
private Spinner fromField;
private MaterialSpinner fromField;
private EditText toField;
public ToValidationField(Spinner fromField, EditText toField){
public ToValidationField(MaterialSpinner fromField, EditText toField){
super(toField);
this.fromField = fromField;
this.toField = toField;
@ -25,8 +28,9 @@ public class ToValidationField extends ValidationField {
public void validate(){
final String fromNewValue;
if (fromField.getSelectedItem() != null) {
fromNewValue = fromField.getSelectedItem().toString();
if (fromField.getSelectedIndex() != -1) {
final CryptoNetAccount cryptoNetAccount = (CryptoNetAccount) fromField.getItems().get(fromField.getSelectedIndex());
fromNewValue = cryptoNetAccount.getName();
} else {
fromNewValue = "";
}

View file

@ -18,6 +18,10 @@ public abstract class ValidationField {
protected UIValidator validator;
protected View view;
public ValidationField(View view){
this.lastValue = "";
this.message = "";

View file

@ -192,7 +192,14 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
} else {
final CryptoNetBalanceViewHolder thisViewHolder = this;
this.cryptoNetAccountId = balance.getAccountId();
cryptoNetName.setText(balance.getCryptoNet().getLabel());
/*
* The first letter should be in mayus
* */
final String crypto = balance.getCryptoNet().getLabel().toString().toLowerCase();
final String upperString = crypto.substring(0,1).toUpperCase() + crypto.substring(1);
cryptoNetName.setText(upperString);
//Loads the crypto coin balance list of this account using a ViewModel and retrieving a LiveData List
CryptoCoinBalanceListViewModel cryptoCoinBalanceListViewModel = ViewModelProviders.of(this.fragment).get(CryptoCoinBalanceListViewModel.class);

View file

@ -0,0 +1,78 @@
package cy.agorise.crystalwallet.views.natives;
import android.content.Context;
import android.support.design.widget.TextInputEditText;
import android.util.AttributeSet;
import android.view.View;
import cy.agorise.crystalwallet.models.FieldValidatorModel;
import cy.agorise.crystalwallet.viewmodels.validators.customImpl.interfaces.UIValidator;
/*
* Custom implementation of the native control to get more over control it
* */
public class CustomTextInputEditText extends TextInputEditText implements UIValidator {
/*
* Contains the field validator, this aid to validate the field
* */
private FieldValidatorModel fieldValidatorModel = new FieldValidatorModel();
/*
* Interface to validate the field
* */
private UIValidator uiValidator;
/*
* Contains the last input value
* */
private String lastValue;
public CustomTextInputEditText(Context context, AttributeSet attrs) {
super(context, attrs);
/*
* Set listener to get the last value of the control
* */
this.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(!hasFocus){
lastValue = getText().toString();
}
}
});
}
public void setFieldValidatorModel(FieldValidatorModel fieldValidatorModel) {
this.fieldValidatorModel = fieldValidatorModel;
}
public void setUiValidator(UIValidator uiValidator) {
this.uiValidator = uiValidator;
}
public FieldValidatorModel getFieldValidatorModel() {
return fieldValidatorModel;
}
public String getLastValue() {
return lastValue;
}
/*
* End of setters and getters
* */
@Override
public void validate() {
uiValidator.validate();
}
}

View file

@ -0,0 +1,40 @@
package cy.agorise.crystalwallet.views.natives
import android.content.Context
import android.util.AttributeSet
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import cy.agorise.crystalwallet.R
/*
* GIF implementation based on existing imageview class
* */
class GIFView : ImageView {
/*
* Contains aditional options for the gif
* */
private var options: RequestOptions? = RequestOptions()
constructor(context:Context,attrs: AttributeSet?) : super(context,attrs) {
}
/*
* Load the gif
* */
fun load(rawID:Int){
Glide.with(this).asGif().load(rawID).apply(options!!).into(this)
}
/*
* Option to fit the gif in the container
* */
fun centerCrop(){
options!!.centerCrop()
}
}

View file

@ -0,0 +1,36 @@
package cy.agorise.crystalwallet.views.natives
import android.content.Context
import android.net.Uri
import android.util.AttributeSet
import android.widget.VideoView
import cy.agorise.crystalwallet.R
import kotlinx.android.synthetic.main.empty_activity.*
/*
* Extensión for videoview
* */
class VideoExView(context: Context?, attrs: AttributeSet?) : VideoView(context, attrs) {
/*
* Set the path based on raw, this should be called first to set the video path
* */
fun setVideoRaw(rawID:Int){
val uriPath = "android.resource://" + context.packageName + "/" + R.raw.appbar_background
val uri = Uri.parse(uriPath)
this.setVideoURI(uri)
}
/*
* With this method the video play continues
* */
fun playContinius(){
start()
this.setOnCompletionListener {
start()
}
}
}

View file

@ -1,13 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--DTVV: Friday July 28 2018
Change android:repeatCount="0" to android:repeatCount="1000"
-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="1000"
android:repeatCount="0"
android:repeatCount="1000"
android:toDegrees="360" />
</set>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<layer-list>
<item android:right="5dp" android:top="5dp">
<shape>
<corners android:radius="3dp" />
<solid android:color="#D6D6D6" />
</shape>
</item>
<item android:bottom="2dp" android:left="2dp">
<shape>
<gradient android:angle="270"
android:endColor="#E2E2E2" android:startColor="#BABABA" />
<stroke android:width="1dp" android:color="#BABABA" />
<corners android:radius="4dp" />
<padding android:bottom="10dp" android:left="10dp"
android:right="10dp" android:top="10dp" />
</shape>
</item>
</layer-list>
</item>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,52 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/white"
android:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="@dimen/activity_vertical_margin">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="@+id/tvMnemonicTitle"
android:layout_width="match_parent"
android:layout_width="wrap_content"
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="@string/seed_words"
android:layout_marginBottom="20dp"
android:text="@string/window_seed_backup"
android:layout_centerHorizontal="true"
android:textSize="20dp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvMnemonic"
android:layout_width="match_parent"
android:layout_height="40dp"
android:id="@+id/tvBrainKey"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tvMnemonicTitle"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:gravity="center"
android:background="@drawable/edittext_bg"
android:inputType="number"
android:maxLines="1"
android:textColor="@color/black" />
android:layout_centerHorizontal="true"
android:textColor="@color/black"
android:layout_marginBottom="20dp"/>
<ImageView
android:id="@+id/backup_seeed_imageview_warning"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentStart="true"
android:layout_marginLeft="35dp"
android:layout_alignTop="@+id/backup_seed_textview_leyend_backup"
android:background="@drawable/warning" />
<TextView
android:id="@+id/backup_seed_textview_leyend_backup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="70dp"
android:textColor="@color/send_strong_orange"
android:layout_marginRight="70dp"
android:text="@string/window_seed_leyend_backup"
android:textSize="14dp"
android:layout_below="@+id/tvBrainKey"/>
<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">
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="20dp"
android:layout_below="@+id/backup_seed_textview_leyend_backup"
android:layout_centerHorizontal="true"
android:weightSum="2">
<Button
android:id="@+id/btnOk"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:background="@drawable/ok"/>
<Button
android:id="@+id/btnCopy"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:layout_margin="10dp"
android:background="@color/pink"
android:text="@string/ok"
android:textColor="@color/white" />
</LinearLayout>
android:text="@string/window_seed_copy"
android:textColor="@color/black" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View file

@ -25,8 +25,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:maxHeight="32dp"
android:maxWidth="32dp"
android:maxHeight="28dp"
android:maxWidth="28dp"
app:srcCompat="@drawable/bts" />
<TextView
@ -34,6 +34,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/ivCryptoNetIcon"
android:ems="10"
android:text="unknown coin" />

View file

@ -21,6 +21,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="@color/red"
app:contentScrim="@color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@+id/toolbar">
@ -30,10 +31,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
<cy.agorise.crystalwallet.views.natives.GIFView
android:id="@+id/imagevieGIF"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryTransparent"/>
/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
@ -99,9 +101,13 @@
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_gravity="bottom"
android:background="@color/transparent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabSelectedTextColor="@color/white"
app:layout_collapseMode="pin"
app:tabTextAppearance="@android:style/TextAppearance.Widget.TabWidget"
app:tabTextColor="@color/lightGrayClear"
android:animateLayoutChanges="true" />
</android.support.design.widget.CollapsingToolbarLayout>

View file

@ -6,13 +6,23 @@
android:layout_height="match_parent"
tools:context=".activities.CreateSeedActivity">
<TextView
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="20dp"
android:text="@string/txt_brain_key_info"
app:layout_constraintTop_toTopOf="parent"
android:textSize="15dp" />
<android.support.design.widget.TextInputLayout
android:id="@+id/tilPin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:layout_marginTop="32dp"
android:layout_marginTop="112dp"
app:layout_constraintBottom_toTopOf="@+id/tilPinConfirmation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
@ -21,13 +31,15 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed">
<android.support.design.widget.TextInputEditText
<cy.agorise.crystalwallet.views.natives.CustomTextInputEditText
android:id="@+id/tietPin"
android:maxLength="32"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/txt_6_digits_pin"
android:inputType="number"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
@ -40,13 +52,15 @@
app:layout_constraintStart_toStartOf="@id/tilPin"
app:layout_constraintEnd_toEndOf="@id/tilPin">
<android.support.design.widget.TextInputEditText
<cy.agorise.crystalwallet.views.natives.CustomTextInputEditText
android:id="@+id/tietPinConfirmation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/txt_6_digits_pin_confirm"
android:maxLength="32"
android:inputType="number"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
@ -59,32 +73,25 @@
app:layout_constraintStart_toStartOf="@id/tilPinConfirmation"
app:layout_constraintEnd_toEndOf="@id/tilPinConfirmation">
<android.support.design.widget.TextInputEditText
<cy.agorise.crystalwallet.views.natives.CustomTextInputEditText
android:id="@+id/tietAccountName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/txt_account_name"
android:digits="abcdefghijklmnopqrstuvwxyz1234567890 -"
android:inputType="textMultiLine"
android:maxLength="255"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<!--
<TextView
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="@string/txt_brain_key_info"
android:textSize="15dp"
android:visibility="gone" /> -->
<Button
android:id="@+id/btnCancel"
android:layout_width="wrap_content"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="24dp"
android:layout_marginTop="48dp"
android:layout_marginStart="4dp"
android:layout_marginTop="28dp"
android:background="@color/redColor"
android:text="@string/cancel"
android:textColor="@color/white"
@ -95,10 +102,10 @@
<Button
android:id="@+id/btnCreate"
android:layout_width="wrap_content"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="24dp"
android:layout_marginEnd="4dp"
android:background="@color/colorPrimary"
android:padding="10dp"
android:text="@string/create_wallet"

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<cy.agorise.crystalwallet.views.natives.GIFView
android:id="@+id/gifView"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="200px"
android:layout_centerInParent="true"/>
<cy.agorise.crystalwallet.views.natives.VideoExView
android:layout_width="match_parent"
android:layout_height="200px"
android:layout_centerInParent="true"
android:visibility="gone"
android:id="@+id/video"/>
</RelativeLayout>

View file

@ -4,9 +4,19 @@
android:layout_height="match_parent"
tools:context="cy.agorise.crystalwallet.fragments.BalanceFragment">
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_gravity="start"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="#d9d9d9"
android:animateLayoutChanges="true" />
<cy.agorise.crystalwallet.views.CryptoNetBalanceListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/vCryptoNetBalanceListView" />
</FrameLayout>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageviewLoading"
android:src="@drawable/loading"
android:layout_width="50dp"
android:layout_height="50dp"
android:adjustViewBounds="true"
android:layout_centerInParent="true">
</ImageView>
</RelativeLayout>

View file

@ -44,7 +44,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
<com.jaredrummler.materialspinner.MaterialSpinner
android:id="@+id/spFrom"
android:layout_width="0dp"
android:layout_height="wrap_content"
@ -74,6 +74,7 @@
android:inputType="text"
android:textSize="20sp"
android:hint="@string/to_capital"
android:maxLength="255"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/gravatar" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

View file

@ -18,15 +18,15 @@
<attr name="civ_selectorStrokeColor" format="color"/>
<!-- The selector stroke drawn around the image upon touch events this pixels wide. (if enabled) -->
<attr name="civ_selectorStrokeWidth" format="dimension"/>
<!-- Whether or not to draw a shadow around your circular image. -->
<!-- Whether or not to draw a disable_style around your circular image. -->
<attr name="civ_shadow" format="boolean"/>
<!-- The radius for the shadow to extend to. (if enabled) -->
<!-- The radius for the disable_style to extend to. (if enabled) -->
<attr name="civ_shadowRadius" format="float"/>
<!-- Horizontal shadow offset. (if enabled) -->
<!-- Horizontal disable_style offset. (if enabled) -->
<attr name="civ_shadowDx" format="float"/>
<!-- Vertical shadow offset. (if enabled) -->
<!-- Vertical disable_style offset. (if enabled) -->
<attr name="civ_shadowDy" format="float"/>
<!-- The color of the shadow drawn around your circular image. (if enabled) -->
<!-- The color of the disable_style drawn around your circular image. (if enabled) -->
<attr name="civ_shadowColor" format="color"/>
</declare-styleable>

View file

@ -14,6 +14,9 @@
<color name="green">#147b00</color>
<color name="lightGrayClear">#cccccc</color>
<color name="black">#000000</color>
<color name="greencolor">#70882E</color>
<color name="red">#ff0000</color>

View file

@ -33,6 +33,17 @@
<string name="account_label">Choose File</string>
<string name="loading_msg">Please wait until Balances are loading</string>
<string name="window_create_seed_DialogTittle"></string>
<string name="window_create_seed_DialogMessage">Creating New Account ...</string>
<string name="window_create_seed_Server_validation">Validating With Server ...</string>
<string name="window_create_seed_Info">You will use your PIN yo make transactions between accounts</string>
<string name="window_seed_backup">Backup brainkey</string>
<string name="window_seed_toast_clipboard">Brainkey copied to clipboard!</string>
<string name="window_seed_copy">Copy</string>
<string name="window_seed_leyend_backup">IMPORTANT: Print this out, or write it down. Anyone with access to your recovery key will have access to funds within this wallet</string>
<string name="seed_words">Seed</string>
<string name="txt_6_digits_pin">PIN (6+ digits)</string>
<string name="txt_6_digits_pin_confirm">PIN confirm</string>
@ -119,7 +130,7 @@
<string name="txt_validating_account">Validating account...</string>
<string name="validating_account">Validating Account...</string>
<string name="account_name_should_be_longer">Account name should be longer</string>
<string name="account_name_already_exist">Account Name %s already exist</string>
<string name="account_name_already_exist">Account Name already exist</string>
<string name="account_name_not_exist">Account Name %s does not exist</string>
<string name="account_already_exist">Account already exist</string>
<string name="add_contact">Add</string>

View file

@ -0,0 +1,15 @@
<resources>
<string name="create_account_window_err_at_least_one_number" translatable="false">The Account Name should contains at least one number</string>
<string name="create_account_window_err_min_account_name_len" translatable="false">The Account Name should contains at least 10 characters length</string>
<string name="create_account_window_err_pin_empty" translatable="false">PIN is emtpy</string>
<string name="create_account_window_err_pin_confirmation_empty" translatable="false">PIN is emtpy</string>
<string name="create_account_window_err_account_empty" translatable="false">Account Name is emtpy</string>
<string name="create_account_window_err_at_least_one_character" translatable="false">The Account Name should contains at least one character</string>
<string name="create_account_window_err_at_least_pin_characters" translatable="false">The PIN should contains at least 6 digits</string>
<string name="create_account_window_err_at_least_one_script" translatable="false">The Account Name should contain at least one \'-\'</string>
<string name="network_err_no_server_connection" translatable="false">No server connection</string>
</resources>

View file

@ -1,15 +1,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlinVersion = '1.1.51'
repositories {
jcenter()
google()
}
ext.kotlin_version = '1.2.51'
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.android.tools.build:gradle:3.1.4'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}