Fixed conflict

master
Nelson R. Perez 2017-10-02 14:23:02 -05:00
commit eb2029049a
34 changed files with 935 additions and 44 deletions

View File

@ -53,4 +53,7 @@ dependencies {
compile 'org.bitcoinj:bitcoinj-core:0.14.3'
compile 'com.neovisionaries:nv-websocket-client:1.30'
compile 'org.tukaani:xz:1.6'
compile 'com.jakewharton:butterknife:8.8.1'
apt 'com.jakewharton:butterknife-compiler:8.8.1'
}

View File

@ -10,13 +10,10 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import carbon.crypto.com.carbon.Assertions.RecyclerViewItemsCountAssertion;
import cy.agorise.crystalwallet.IntroActivity;
import cy.agorise.crystalwallet.activities.IntroActivity;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
@ -25,9 +22,6 @@ import cy.agorise.crystalwallet.randomdatagenerators.RandomTransactionsGenerator
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
/**
* Created by Henry Varona on 19/9/2017.

View File

@ -10,13 +10,17 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".IntroActivity">
<activity android:name=".activities.IntroActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".activities.AccountSeedsManagementActivity" >
</activity>
<activity android:name=".activities.ImportSeedActivity" >
</activity>
</application>
</manifest>

View File

@ -0,0 +1,57 @@
package cy.agorise.crystalwallet.activities;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel;
import cy.agorise.crystalwallet.views.AccountSeedListView;
public class AccountSeedsManagementActivity extends AppCompatActivity {
AccountSeedsManagementActivity accountSeedsManagementActivity;
AccountSeedListViewModel accountSeedListViewModel;
@BindView(R.id.vAccountSeedList)
AccountSeedListView vAccountSeedList;
@BindView(R.id.btnImportAccountSeed)
Button btnImportAccountSeed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.account_seeds_management);
ButterKnife.bind(this);
accountSeedListViewModel = ViewModelProviders.of(this).get(AccountSeedListViewModel.class);
LiveData<List<AccountSeed>> accountSeedData = accountSeedListViewModel.getAccountSeedList();
vAccountSeedList.setData(null);
accountSeedData.observe(this, new Observer<List<AccountSeed>>() {
@Override
public void onChanged(List<AccountSeed> accountSeeds) {
vAccountSeedList.setData(accountSeeds);
}
});
}
@OnClick (R.id.btnImportAccountSeed)
public void importAccountSeed(){
Intent intent = new Intent(this, ImportSeedActivity.class);
startActivity(intent);
}
}

View File

@ -0,0 +1,66 @@
package cy.agorise.crystalwallet.activities;
import android.arch.lifecycle.LifecycleActivity;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
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 cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel;
import cy.agorise.crystalwallet.viewmodels.AccountSeedViewModel;
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
import cy.agorise.crystalwallet.views.TransactionListView;
public class ImportSeedActivity extends AppCompatActivity {
AccountSeedViewModel accountSeedViewModel;
@BindView(R.id.tvPin)
TextView tvPin;
@BindView(R.id.tvPinConfirmation)
TextView tvPinConfirmation;
@BindView(R.id.etSeedWords)
EditText etSeedWords;
@BindView (R.id.etAccountName)
EditText etAccountName;
@BindView(R.id.btnImport)
Button btnImport;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.import_seed);
ButterKnife.bind(this);
accountSeedViewModel = ViewModelProviders.of(this).get(AccountSeedViewModel.class);
//this.seed = new AccountSeed();
}
@OnClick(R.id.btnImport)
public void importSeed(){
AccountSeed seed = new AccountSeed();
//TODO verify if PIN and PIN confirmation are not null and are the same
//TODO verify if words are already in the db
//TODO check if name has been asigned to other seed
seed.setMasterSeed(etSeedWords.getText().toString());
seed.setName(etAccountName.getText().toString());
accountSeedViewModel.addSeed(seed);
}
}

View File

@ -1,4 +1,4 @@
package cy.agorise.crystalwallet;
package cy.agorise.crystalwallet.activities;
import android.arch.lifecycle.LifecycleActivity;
import android.arch.lifecycle.LiveData;
@ -6,6 +6,7 @@ import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProvider;
import android.arch.lifecycle.ViewModelProviders;
import android.arch.paging.PagedList;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
@ -14,6 +15,7 @@ import android.widget.Button;
import java.util.List;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
@ -21,12 +23,13 @@ import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.randomdatagenerators.RandomCryptoNetAccountGenerator;
import cy.agorise.crystalwallet.randomdatagenerators.RandomSeedGenerator;
import cy.agorise.crystalwallet.randomdatagenerators.RandomTransactionsGenerator;
import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel;
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
import cy.agorise.crystalwallet.views.TransactionListView;
import static cy.agorise.crystalwallet.R.string.transactions;
public class IntroActivity extends LifecycleActivity {
public class IntroActivity extends AppCompatActivity {
TransactionListViewModel transactionListViewModel;
TransactionListView transactionListView;
@ -36,6 +39,16 @@ public class IntroActivity extends LifecycleActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intro);
//Checks if the user has any seed created
AccountSeedListViewModel accountSeedListViewModel = ViewModelProviders.of(this).get(AccountSeedListViewModel.class);
//if (accountSeedListViewModel.accountSeedsCount() == 0){
//If the user doesn't have any seeds created, then
//send the user to create/import an account
Intent intent = new Intent(this, AccountSeedsManagementActivity.class);
startActivity(intent);
//}
/*CrystalDatabase db = CrystalDatabase.getAppDatabase(getApplicationContext());
List<AccountSeed> seeds = RandomSeedGenerator.generateSeeds(2);
for(int i=0;i<seeds.size();i++) {
@ -53,7 +66,7 @@ public class IntroActivity extends LifecycleActivity {
transactions.get(i).setId(newId);
}*/
transactionListView = this.findViewById(R.id.transaction_list);
/*transactionListView = this.findViewById(R.id.transaction_list);
transactionListViewModel = ViewModelProviders.of(this).get(TransactionListViewModel.class);
LiveData<PagedList<CryptoCoinTransaction>> transactionData = transactionListViewModel.getTransactionList();
@ -64,6 +77,6 @@ public class IntroActivity extends LifecycleActivity {
public void onChanged(PagedList<CryptoCoinTransaction> cryptoCoinTransactions) {
transactionListView.setData(cryptoCoinTransactions);
}
});
});*/
}
}

View File

@ -10,6 +10,7 @@ import java.util.List;
import cy.agorise.graphenej.Address;
import cy.agorise.graphenej.UserAccount;
import cy.agorise.graphenej.api.GetAccountByName;
import cy.agorise.graphenej.api.GetAccounts;
import cy.agorise.graphenej.api.GetKeyReferences;
import cy.agorise.graphenej.api.GetRelativeAccountHistory;
@ -165,12 +166,45 @@ public class GrapheneApiGenerator {
}
/**
* Gets if an Account Name is avaible to be used for a new account
* Retrieves the account id by the name of the account
*
* @param accountName The account Name to find
* @param request The Api request object, to answer this petition
*/
public static void isAccountNameAvaible(String accountName, ApiRequest request){
//TODO implement
public static void getAccountIdByName(String accountName, final ApiRequest request){
WebSocketFactory factory = new WebSocketFactory().setConnectionTimeout(connectionTimeout);
try {
final WebSocket webSocket = factory.createSocket(url);
webSocket.addListener(new GetAccountByName(accountName, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
AccountProperties accountProperties = ((WitnessResponse<AccountProperties>) response).result;
if(accountProperties != null){
request.getListener().success(null,request.getId());
}else{
request.getListener().success(accountProperties.id,request.getId());
}
}
@Override
public void onError(BaseResponse.Error error) {
request.getListener().fail(request.getId());
}
}));
Thread thread = new Thread(){
public void run(){
try {
webSocket.connect();
} catch (WebSocketException e) {
e.printStackTrace();
request.getListener().fail(request.getId());
}
}
};
thread.start();
} catch (IOException e) {
e.printStackTrace();
request.getListener().fail(request.getId());
}
}
}

View File

@ -0,0 +1,24 @@
package cy.agorise.crystalwallet.cryptonetinforequests;
import cy.agorise.crystalwallet.enums.CryptoCoin;
/**
* Created by Henry Varona on 1/10/2017.
*/
public abstract class CryptoNetInfoRequest {
protected CryptoCoin coin;
protected CryptoNetInfoRequestListener listener;
public CryptoNetInfoRequest(CryptoCoin coin){
this.coin = coin;
}
public void setListener(CryptoNetInfoRequestListener listener){
this.listener = listener;
}
public void _fireOnCarryOutEvent(){
listener.onCarryOut();
}
}

View File

@ -0,0 +1,10 @@
package cy.agorise.crystalwallet.cryptonetinforequests;
/**
* Created by Henry Varona on 1/10/2017.
*/
interface CryptoNetInfoRequestListener {
public void onCarryOut();
}

View File

@ -0,0 +1,48 @@
package cy.agorise.crystalwallet.cryptonetinforequests;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Henry Varona on 1/10/2017.
*/
public class CryptoNetInfoRequests {
private List<CryptoNetInfoRequest> requests;
private List<CryptoNetInfoRequestsListener> listeners;
private CryptoNetInfoRequests instance;
private void CryptoNetInfoRequests(){
//Private constructor for singleton pattern
}
public CryptoNetInfoRequests getInstance(){
if (this.instance == null){
this.instance = new CryptoNetInfoRequests();
this.requests = new ArrayList<CryptoNetInfoRequest>();
this.listeners = new ArrayList<CryptoNetInfoRequestsListener>();
}
return this.instance;
}
public void addRequest(CryptoNetInfoRequest request){
this.requests.add(request);
this._fireNewRequestEvent(request);
}
public void removeRequest(CryptoNetInfoRequest request){
this.requests.remove(request);
}
public void addListener(CryptoNetInfoRequestsListener listener){
this.listeners.add(listener);
}
private void _fireNewRequestEvent(CryptoNetInfoRequest request){
for (int i=0;i<this.listeners.size();i++){
this.listeners.get(i).onNewRequest(request);
}
}
}

View File

@ -0,0 +1,9 @@
package cy.agorise.crystalwallet.cryptonetinforequests;
/**
* Created by Henry Varona on 1/10/2017.
*/
public interface CryptoNetInfoRequestsListener {
public void onNewRequest(CryptoNetInfoRequest request);
}

View File

@ -0,0 +1,44 @@
package cy.agorise.crystalwallet.cryptonetinforequests;
import cy.agorise.crystalwallet.enums.CryptoCoin;
/**
* Created by Henry Varona on 1/10/2017.
*/
public class ValidateImportBitsharesAccountRequest extends CryptoNetInfoRequest {
private String accountName;
private String mnemonic;
private Boolean accountExists;
private Boolean mnemonicIsCorrect;
public ValidateImportBitsharesAccountRequest(String accountName, String mnemonic){
super(CryptoCoin.BITSHARES);
this.accountName = accountName;
this.mnemonic = mnemonic;
}
public void setAccountExists(boolean value){
this.accountExists = value;
}
public void setMnemonicIsCorrect(boolean value){
this.mnemonicIsCorrect = value;
}
public boolean getAccountExists(){
return this.accountExists;
}
public boolean getMnemonicIsCorrect(){
return this.mnemonicIsCorrect;
}
public void validate(){
if ((this.accountExists != null) && (this.mnemonicIsCorrect != null)){
this._fireOnCarryOutEvent();
}
}
}

View File

@ -1,5 +1,7 @@
package cy.agorise.crystalwallet.dao;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy;
@ -17,9 +19,17 @@ import cy.agorise.crystalwallet.models.AccountSeed;
public interface AccountSeedDao {
@Query("SELECT * FROM account_seed")
List<AccountSeed> getAll();
LiveData<List<AccountSeed>> getAll();
@Query("SELECT * FROM account_seed WHERE id = :id")
LiveData<AccountSeed> findById(long id);
@Query("SELECT COUNT(*) from account_seed")
int countAccountSeeds();
@Insert(onConflict = OnConflictStrategy.REPLACE)
public long[] insertAccountSeed(AccountSeed... seeds);
public long[] insertAccountSeeds(AccountSeed... seeds);
@Insert(onConflict = OnConflictStrategy.REPLACE)
public long insertAccountSeed(AccountSeed seed);
}

View File

@ -6,6 +6,7 @@ import java.util.Date;
import cy.agorise.crystalwallet.enums.CryptoCoin;
import cy.agorise.crystalwallet.enums.CryptoNet;
import cy.agorise.crystalwallet.enums.SeedType;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
import static cy.agorise.crystalwallet.R.string.account;
@ -84,4 +85,22 @@ public class Converters {
return CryptoNet.valueOf(value);
}
}
@TypeConverter
public String seedTypeToName(SeedType value) {
if (value == null) {
return "";
} else {
return value.name();
}
}
@TypeConverter
public SeedType nameToSeedType(String value) {
if (value.equals("")){
return null;
} else {
return SeedType.valueOf(value);
}
}
}

View File

@ -0,0 +1,10 @@
package cy.agorise.crystalwallet.enums;
/**
* Created by Henry Varona on 30/9/2017.
*/
public enum SeedType {
BIP39,
BRAINKEY
}

View File

@ -1,12 +1,15 @@
package cy.agorise.crystalwallet.manager;
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequest;
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestsListener;
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateImportBitsharesAccountRequest;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
/**
* Created by henry on 26/9/2017.
*/
public class BitsharesAccountManager implements CryptoAccountManager {
public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener {
@Override
public CryptoNetAccount createAccountFromSeed(CryptoNetAccount account) {
return null;
@ -21,4 +24,10 @@ public class BitsharesAccountManager implements CryptoAccountManager {
public void loadAccountFromDB(CryptoNetAccount account) {
}
@Override
public void onNewRequest(CryptoNetInfoRequest request) {
if (request instanceof ValidateImportBitsharesAccountRequest){
}
}
}

View File

@ -4,6 +4,10 @@ package cy.agorise.crystalwallet.models;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;
import android.support.annotation.NonNull;
import android.support.v7.recyclerview.extensions.DiffCallback;
import cy.agorise.crystalwallet.enums.SeedType;
/**
* Represents a type of crypto seed for HD wallets
@ -32,6 +36,11 @@ public class AccountSeed {
@ColumnInfo(name = "master_seed")
private String mMasterSeed;
/**
* The type of this seed: BIP39, BRAINKEY
*/
private SeedType type;
public long getId() {
return mId;
}
@ -56,5 +65,36 @@ public class AccountSeed {
this.mMasterSeed = mMasterSeed;
}
public SeedType getType() {
return type;
}
public void setType(SeedType type) {
this.type = type;
}
public static final DiffCallback<AccountSeed> DIFF_CALLBACK = new DiffCallback<AccountSeed>() {
@Override
public boolean areItemsTheSame(
@NonNull AccountSeed oldAccountSeed, @NonNull AccountSeed newAccountSeed) {
return oldAccountSeed.getId() == newAccountSeed.getId();
}
@Override
public boolean areContentsTheSame(
@NonNull AccountSeed oldAccountSeed, @NonNull AccountSeed newAccountSeed) {
return oldAccountSeed.equals(newAccountSeed);
}
};
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AccountSeed that = (AccountSeed) o;
if (mId != that.mId) return false;
return mMasterSeed.equals(that.mMasterSeed);
}
}

View File

@ -0,0 +1,36 @@
package cy.agorise.crystalwallet.viewmodels;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.arch.paging.PagedList;
import java.util.List;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
/**
* Created by Henry Varona on 27/9/2017.
*/
public class AccountSeedListViewModel extends AndroidViewModel {
private LiveData<List<AccountSeed>> accountSeedList;
private CrystalDatabase db;
public AccountSeedListViewModel(Application application) {
super(application);
this.db = CrystalDatabase.getAppDatabase(application.getApplicationContext());
this.accountSeedList = this.db.accountSeedDao().getAll();
}
public LiveData<List<AccountSeed>> getAccountSeedList(){
return this.accountSeedList;
}
public int accountSeedsCount(){
return this.db.accountSeedDao().countAccountSeeds();
}
}

View File

@ -0,0 +1,38 @@
package cy.agorise.crystalwallet.viewmodels;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import java.util.List;
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;
public AccountSeedViewModel(Application application) {
super(application);
this.db = CrystalDatabase.getAppDatabase(application.getApplicationContext());
}
public void loadSeed(int seedId){
this.accountSeed = this.db.accountSeedDao().findById(seedId);
}
public void addSeed(AccountSeed seed){
this.db.accountSeedDao().insertAccountSeed(seed);
}
public LiveData<AccountSeed> getAccountSeed(){
return this.accountSeed;
}
}

View File

@ -0,0 +1,40 @@
package cy.agorise.crystalwallet.views;
import android.arch.paging.PagedListAdapter;
import android.support.v7.recyclerview.extensions.ListAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
/**
* Created by Henry Varona on 11/9/2017.
*/
public class AccountSeedListAdapter extends ListAdapter<AccountSeed, AccountSeedViewHolder> {
public AccountSeedListAdapter() {
super(AccountSeed.DIFF_CALLBACK);
}
@Override
public AccountSeedViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.account_seed_list_item,parent,false);
return new AccountSeedViewHolder(v);
}
@Override
public void onBindViewHolder(AccountSeedViewHolder holder, int position) {
AccountSeed accountSeed = getItem(position);
if (accountSeed != null) {
holder.bindTo(accountSeed);
} else {
holder.clear();
}
}
}

View File

@ -0,0 +1,73 @@
package cy.agorise.crystalwallet.views;
import android.arch.paging.PagedList;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import java.util.List;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel;
import cy.agorise.crystalwallet.viewmodels.TransactionListViewModel;
/**
* Created by Henry Varona on 10/9/2017.
*/
public class AccountSeedListView extends RelativeLayout {
LayoutInflater mInflater;
View rootView;
RecyclerView listView;
AccountSeedListAdapter listAdapter;
AccountSeedListViewModel accountSeedListViewModel;
public AccountSeedListView(Context context){
super(context);
this.mInflater = LayoutInflater.from(context);
init();
}
public AccountSeedListView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mInflater = LayoutInflater.from(context);
init();
}
public AccountSeedListView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
this.mInflater = LayoutInflater.from(context);
init();
}
public void init(){
rootView = mInflater.inflate(R.layout.account_seed_list, this, true);
this.listView = rootView.findViewById(R.id.accountSeedListView);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this.getContext());
this.listView.setLayoutManager(linearLayoutManager);
this.listView.setNestedScrollingEnabled(false);
}
public void setData(List<AccountSeed> data){
if (this.listAdapter == null) {
this.listAdapter = new AccountSeedListAdapter();
this.listView.setAdapter(this.listAdapter);
}
if (data != null) {
this.listAdapter.setList(data);
}
}
}

View File

@ -0,0 +1,34 @@
package cy.agorise.crystalwallet.views;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
/**
* Created by Henry Varona on 17/9/2017.
*/
public class AccountSeedViewHolder extends RecyclerView.ViewHolder {
private TextView tvAccountSeedName;
public AccountSeedViewHolder(View itemView) {
super(itemView);
tvAccountSeedName = (TextView) itemView.findViewById(R.id.tvAccountSeedName);
}
public void clear(){
tvAccountSeedName.setText("loading...");
}
public void bindTo(final AccountSeed accountSeed) {
if (accountSeed == null){
tvAccountSeedName.setText("loading...");
} else {
tvAccountSeedName.setText(accountSeed.getName());
}
}
}

View File

@ -0,0 +1,13 @@
package cy.agorise.graphenej;
/**
* Enum-type used to specify the different roles of an authority.
*
* @see <a href="https://bitshares.org/doxygen/authority_8hpp_source.html">Authority</a>
*/
public enum AuthorityType {
OWNER,
ACTIVE,
MEMO
}

View File

@ -20,6 +20,7 @@ import cy.agorise.graphenej.models.ApiCall;
import cy.agorise.graphenej.models.BaseResponse;
import cy.agorise.graphenej.models.HistoricalTransfer;
import cy.agorise.graphenej.models.WitnessResponse;
import cy.agorise.graphenej.objects.Memo;
import cy.agorise.graphenej.operations.TransferOperation;
/**
@ -161,6 +162,7 @@ public class GetRelativeAccountHistory extends BaseGrapheneHandler {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer());
gsonBuilder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
gsonBuilder.registerTypeAdapter(Memo.class, new Memo.MemoDeserializer());
WitnessResponse<List<HistoricalTransfer>> transfersResponse = gsonBuilder.create().fromJson(response, RelativeAccountHistoryResponse);
mListener.onSuccess(transfersResponse);
}

View File

@ -26,6 +26,7 @@ import cy.agorise.graphenej.models.ApiCall;
import cy.agorise.graphenej.models.DynamicGlobalProperties;
import cy.agorise.graphenej.models.SubscriptionResponse;
import cy.agorise.graphenej.models.WitnessResponse;
import cy.agorise.graphenej.objects.Memo;
import cy.agorise.graphenej.operations.LimitOrderCreateOperation;
import cy.agorise.graphenej.operations.TransferOperation;
@ -91,6 +92,7 @@ public class SubscriptionMessagesHub extends BaseGrapheneHandler implements Subs
builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountSimpleDeserializer());
builder.registerTypeAdapter(DynamicGlobalProperties.class, new DynamicGlobalProperties.DynamicGlobalPropertiesDeserializer());
builder.registerTypeAdapter(Memo.class, new Memo.MemoDeserializer());
this.gson = builder.create();
}

View File

@ -1,17 +1,25 @@
package cy.agorise.graphenej.objects;
import com.google.common.primitives.Bytes;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import cy.agorise.graphenej.Address;
import cy.agorise.graphenej.PublicKey;
import cy.agorise.graphenej.Util;
import cy.agorise.graphenej.errors.ChecksumException;
import cy.agorise.graphenej.errors.MalformedAddressException;
import cy.agorise.graphenej.interfaces.ByteSerializable;
import cy.agorise.graphenej.interfaces.JsonSerializable;
import cy.agorise.graphenej.operations.TransferOperation;
import org.bitcoinj.core.ECKey;
import org.spongycastle.math.ec.ECPoint;
import java.lang.reflect.Type;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@ -269,4 +277,30 @@ public class Memo implements ByteSerializable, JsonSerializable {
}
return memoObject;
}
/**
* Class used to deserialize a memo
*/
public static class MemoDeserializer implements JsonDeserializer<Memo> {
@Override
public Memo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String fromAddress = jsonObject.get(KEY_FROM).getAsString();
String toAddress = jsonObject.get(KEY_TO).getAsString();
long nonce = jsonObject.get(KEY_NONCE).getAsLong();
String msg = jsonObject.get(KEY_MESSAGE).getAsString();
Memo memo = null;
try{
Address from = new Address(fromAddress);
Address to = new Address(toAddress);
byte[] message = Util.hexToBytes(msg);
memo = new Memo(from, to, nonce, message);
}catch(MalformedAddressException e){
System.out.println("MalformedAddressException. Msg: "+e.getMessage());
}
return memo;
}
}
}

View File

@ -1,7 +1,6 @@
package cy.agorise.graphenej.operations;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedLong;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
@ -14,13 +13,10 @@ import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import cy.agorise.graphenej.Address;
import cy.agorise.graphenej.AssetAmount;
import cy.agorise.graphenej.BaseOperation;
import cy.agorise.graphenej.OperationType;
import cy.agorise.graphenej.UserAccount;
import cy.agorise.graphenej.Util;
import cy.agorise.graphenej.errors.MalformedAddressException;
import cy.agorise.graphenej.objects.Memo;
/**
@ -171,7 +167,6 @@ public class TransferOperation extends BaseOperation {
@Override
public TransferOperation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
System.out.println("Deserialized bitch start. Msg: "+ json.getAsString());
if(json.isJsonArray()){
// This block is used just to check if we are in the first step of the deserialization
// when we are dealing with an array.
@ -197,20 +192,10 @@ public class TransferOperation extends BaseOperation {
UserAccount to = new UserAccount(jsonObject.get(KEY_TO).getAsString());
TransferOperation transfer = new TransferOperation(from, to, amount, fee);
// Deserializing Memo if it exists
System.out.println("Deserialized bitch. Msg: "+ jsonObject.getAsString());
if(jsonObject.get(KEY_MEMO) != null){
JsonObject memoObj = jsonObject.get(KEY_MEMO).getAsJsonObject();
try{
Address memoFrom = new Address(memoObj.get(Memo.KEY_FROM).getAsString());
Address memoTo = new Address(memoObj.get(KEY_TO).getAsString());
long nonce = UnsignedLong.valueOf(memoObj.get(Memo.KEY_NONCE).getAsString()).longValue();
byte[] message = Util.hexToBytes(memoObj.get(Memo.KEY_MESSAGE).getAsString());
Memo memo = new Memo(memoFrom, memoTo, nonce, message);
transfer.setMemo(memo);
}catch(MalformedAddressException e){
System.out.println("MalformedAddressException. Msg: "+e.getMessage());
}
// If the transfer had a memo, deserialize it
if(jsonObject.has(KEY_MEMO)){
Memo memo = context.deserialize(jsonObject.get(KEY_MEMO), Memo.class);
transfer.setMemo(memo);
}
return transfer;

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/accountSeedListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<TextView
android:id="@+id/tvAccountSeedName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:text="name of the account" />
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btnImportAccountSeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="import seed" />
<cy.agorise.crystalwallet.views.AccountSeedListView
android:id="@+id/vAccountSeedList"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</cy.agorise.crystalwallet.views.AccountSeedListView>
</RelativeLayout>

View File

@ -95,16 +95,17 @@
android:layout_gravity="center"
android:id="@+id/btnCancel"
android:text="@string/cancel"/>
<Button
android:id="@+id/btnWallet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/green"
android:textColor="@color/white"
android:layout_margin="10dp"
android:padding="10dp"
android:layout_gravity="center"
android:id="@+id/btnWallet"
android:text="@string/create_wallet"/>
android:layout_margin="10dp"
android:background="@color/green"
android:padding="10dp"
android:text="@string/import_new_account"
android:textColor="@color/white" />
</LinearLayout>

View File

@ -8,7 +8,7 @@
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="cy.agorise.crystalwallet.IntroActivity">
tools:context="cy.agorise.crystalwallet.activities.IntroActivity">
<cy.agorise.crystalwallet.views.TransactionListView
android:id="@+id/transaction_list"

View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="@color/white"
android:layout_height="match_parent"
android:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/txt_6_digits_pin"
android:id="@+id/tvPin"
android:textStyle="bold"
android:layout_marginTop="10dp"/>
<EditText
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:id="@+id/etPin"
android:layout_width="match_parent"
android:inputType="number"
android:background="@drawable/edittext_bg"
android:maxLines="1"
android:layout_height="40dp"/>
<TextView
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tvPinConfirmation"
android:text="@string/txt_6_digits_pin_confirm"
android:textStyle="bold"
android:layout_marginTop="10dp"/>
<EditText
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:id="@+id/etPinConfirmation"
android:layout_width="match_parent"
android:inputType="number"
android:background="@drawable/edittext_bg"
android:singleLine="true"
android:maxLines="1"
android:layout_height="40dp" />
<TextView
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/seed_words"
android:textStyle="bold"
android:layout_marginTop="10dp"/>
<EditText
android:id="@+id/etSeedWords"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:background="@drawable/edittext_bg"
android:gravity="top"
android:inputType="textMultiLine" />
<TextView
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/txt_account_name"
android:textStyle="bold"
android:layout_marginTop="10dp"/>
<EditText
android:id="@+id/etAccountName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:background="@drawable/edittext_bg"
android:gravity="top"
android:inputType="textMultiLine" />
<TextView
android:visibility="gone"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/txt_brain_key_info"
android:textSize="15dp"
android:layout_marginTop="10dp"/>
<LinearLayout
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp"
android:gravity="center">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/pink"
android:textColor="@color/white"
android:layout_margin="10dp"
android:layout_gravity="center"
android:id="@+id/btnCancel"
android:text="@string/cancel"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/green"
android:textColor="@color/white"
android:layout_margin="10dp"
android:padding="10dp"
android:layout_gravity="center"
android:id="@+id/btnImport"
android:text="@string/create_wallet"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:background="@color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/black">
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="35dp"
android:gravity="bottom"
android:orientation="horizontal"
android:background="@color/bottomBarColor">
<TextView
android:text="@string/v_1_0_beta"
android:id="@+id/tvAppVersion_brain_key_activity"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:id="@+id/tvBlockNumberHead_brain_key_activity"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="@string/block_number"/>
<ImageView
android:id="@+id/ivSocketConnected_brain_key_activity"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:layout_gravity="center"/>
<ImageView android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:layout_gravity="center"
android:src="@drawable/icon_setting"
android:visibility="invisible"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -33,6 +33,7 @@
<string name="account_label">Choose File</string>
<string name="loading_msg">Please wait until Balances are loading</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>
<string name="create">CREATE</string>