#16 - added Dapp list remembering and implemented dapps dialogs.
Partially implemented json wallet import.
This commit is contained in:
parent
f3bb5165d6
commit
c74594f68d
|
@ -28,6 +28,7 @@ import android.widget.ArrayAdapter;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.RadioButton;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
@ -37,8 +38,15 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
|
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.nio.MappedByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -61,16 +69,14 @@ import static org.ethereum.config.SystemProperties.CONFIG;
|
||||||
public abstract class BaseActivity extends AppCompatActivity implements
|
public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
OnClickListener, OnDAppClickListener, OnProfileClickListener {
|
OnClickListener, OnDAppClickListener, OnProfileClickListener {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger("SyngApplication");
|
||||||
|
|
||||||
private static final int DRAWER_CLOSE_DELAY_SHORT = 200;
|
private static final int DRAWER_CLOSE_DELAY_SHORT = 200;
|
||||||
private static final int DRAWER_CLOSE_DELAY_LONG = 400;
|
private static final int DRAWER_CLOSE_DELAY_LONG = 400;
|
||||||
|
|
||||||
private static final String CONTRIBUTE_LINK = "https://github.com/syng-io";
|
private static final String CONTRIBUTE_LINK = "https://github.com/syng-io";
|
||||||
private static final String CONTINUE_SEARCH_LINK = "dapp://syng.io/store?q=search%20query";
|
private static final String CONTINUE_SEARCH_LINK = "dapp://syng.io/store?q=search%20query";
|
||||||
|
|
||||||
private ArrayList<String> mDAppNamesList = new ArrayList<>(Arrays.asList("Console"));
|
|
||||||
|
|
||||||
private ArrayList<String> mAccountNamesList = new ArrayList<>(Arrays.asList("Cow"));
|
|
||||||
|
|
||||||
private ActionBarDrawerToggle mDrawerToggle;
|
private ActionBarDrawerToggle mDrawerToggle;
|
||||||
|
|
||||||
private Spinner mAccountSpinner;
|
private Spinner mAccountSpinner;
|
||||||
|
@ -108,12 +114,6 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
mDrawerLayout = (DrawerLayout) inflater.inflate(R.layout.drawer, null, false);
|
mDrawerLayout = (DrawerLayout) inflater.inflate(R.layout.drawer, null, false);
|
||||||
FrameLayout content = (FrameLayout) mDrawerLayout.findViewById(R.id.content);
|
FrameLayout content = (FrameLayout) mDrawerLayout.findViewById(R.id.content);
|
||||||
|
|
||||||
mDAppsRecyclerView = (RecyclerView) mDrawerLayout.findViewById(R.id.dapd_drawer_recycler_view);
|
|
||||||
mDAppsRecyclerView.setHasFixedSize(true);
|
|
||||||
RecyclerView.LayoutManager layoutManager1 = new LinearLayoutManager(this);
|
|
||||||
mDAppsRecyclerView.setLayoutManager(layoutManager1);
|
|
||||||
initDApps();
|
|
||||||
|
|
||||||
Toolbar toolbar = (Toolbar) inflater.inflate(layoutResID, content, true).findViewById(R.id.myToolbar);
|
Toolbar toolbar = (Toolbar) inflater.inflate(layoutResID, content, true).findViewById(R.id.myToolbar);
|
||||||
if (toolbar != null) {
|
if (toolbar != null) {
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
@ -137,6 +137,7 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
mSearchTextView = (EditText) mDrawerLayout.findViewById(R.id.search);
|
mSearchTextView = (EditText) mDrawerLayout.findViewById(R.id.search);
|
||||||
initSearch();
|
initSearch();
|
||||||
|
|
||||||
|
mDrawerLayout.findViewById(R.id.ll_import_wallet).setOnClickListener(this);
|
||||||
mDrawerLayout.findViewById(R.id.ll_settings).setOnClickListener(this);
|
mDrawerLayout.findViewById(R.id.ll_settings).setOnClickListener(this);
|
||||||
mDrawerLayout.findViewById(R.id.ll_contribute).setOnClickListener(this);
|
mDrawerLayout.findViewById(R.id.ll_contribute).setOnClickListener(this);
|
||||||
mDrawerLayout.findViewById(R.id.drawer_header).setOnClickListener(this);
|
mDrawerLayout.findViewById(R.id.drawer_header).setOnClickListener(this);
|
||||||
|
@ -150,6 +151,12 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
mAccountsRecyclerView.setLayoutManager(layoutManager2);
|
mAccountsRecyclerView.setLayoutManager(layoutManager2);
|
||||||
initProfiles();
|
initProfiles();
|
||||||
|
|
||||||
|
mDAppsRecyclerView = (RecyclerView) mDrawerLayout.findViewById(R.id.dapd_drawer_recycler_view);
|
||||||
|
mDAppsRecyclerView.setHasFixedSize(true);
|
||||||
|
RecyclerView.LayoutManager layoutManager1 = new LinearLayoutManager(this);
|
||||||
|
mDAppsRecyclerView.setLayoutManager(layoutManager1);
|
||||||
|
initDApps();
|
||||||
|
|
||||||
ImageView header = (ImageView) mDrawerLayout.findViewById(R.id.iv_header);
|
ImageView header = (ImageView) mDrawerLayout.findViewById(R.id.iv_header);
|
||||||
Glide.with(this).load(R.drawable.two).into(header);
|
Glide.with(this).load(R.drawable.two).into(header);
|
||||||
|
|
||||||
|
@ -180,39 +187,40 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
|
|
||||||
|
|
||||||
private void initProfiles() {
|
private void initProfiles() {
|
||||||
mProfiles = new ArrayList<>(mAccountNamesList.size());
|
mProfiles = PrefsUtil.getProfiles();
|
||||||
for (String name : mAccountNamesList) {
|
// Add default cow account if not present
|
||||||
|
if (mProfiles.size() == 0) {
|
||||||
Profile profile = new Profile();
|
Profile profile = new Profile();
|
||||||
profile.setName(name);
|
profile.setName("Cow");
|
||||||
// default cow account
|
// Add default cow and monkey addresses
|
||||||
if (name.equals("Cow")) {
|
List<String> addresses = new ArrayList<String>();
|
||||||
// Add default cow and monkey addresses
|
byte[] cowAddr = HashUtil.sha3("cow".getBytes());
|
||||||
List<String> addresses = new ArrayList<String>();
|
addresses.add(Hex.toHexString(cowAddr));
|
||||||
byte[] cowAddr = HashUtil.sha3("cow".getBytes());
|
String secret = CONFIG.coinbaseSecret();
|
||||||
addresses.add(Hex.toHexString(cowAddr));
|
byte[] cbAddr = HashUtil.sha3(secret.getBytes());
|
||||||
String secret = CONFIG.coinbaseSecret();
|
addresses.add(Hex.toHexString(cbAddr));
|
||||||
byte[] cbAddr = HashUtil.sha3(secret.getBytes());
|
profile.setPrivateKeys(addresses);
|
||||||
addresses.add(Hex.toHexString(cbAddr));
|
PrefsUtil.saveProfile(profile);
|
||||||
profile.setPrivateKeys(addresses);
|
|
||||||
SyngApplication app = (SyngApplication) getApplication();
|
|
||||||
if (app.currentProfile == null) {
|
|
||||||
changeProfile(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mProfiles.add(profile);
|
mProfiles.add(profile);
|
||||||
}
|
}
|
||||||
mAccountDrawerAdapter = new AccountDrawerAdapter(this, mProfiles, this);
|
mAccountDrawerAdapter = new AccountDrawerAdapter(this, mProfiles, this);
|
||||||
mAccountsRecyclerView.setAdapter(mAccountDrawerAdapter);
|
mAccountsRecyclerView.setAdapter(mAccountDrawerAdapter);
|
||||||
|
if (SyngApplication.currentProfile == null) {
|
||||||
|
SyngApplication.changeProfile(mProfiles.get(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initDApps() {
|
private void initDApps() {
|
||||||
mDApps = new ArrayList<>(mDAppNamesList.size());
|
mDApps = new ArrayList<>();
|
||||||
for (String name : mDAppNamesList) {
|
if (SyngApplication.currentProfile != null) {
|
||||||
mDApps.add(new Dapp(name));
|
mDApps = SyngApplication.currentProfile.getDapps();
|
||||||
}
|
}
|
||||||
mDAppsDrawerAdapter = new DAppDrawerAdapter(new ArrayList<>(mDApps), this);
|
// Add default Console dapp if not present
|
||||||
mDAppsRecyclerView.setAdapter(mDAppsDrawerAdapter);
|
if (mDApps.size() == 0) {
|
||||||
|
mDApps.add(new Dapp("Console"));
|
||||||
|
}
|
||||||
|
updateAppList(mSearchTextView.getText().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -226,11 +234,8 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
if (textView != null) {
|
if (textView != null) {
|
||||||
textView.setText(profile.getName());
|
textView.setText(profile.getName());
|
||||||
}
|
}
|
||||||
SyngApplication application = (SyngApplication) getApplication();
|
SyngApplication.changeProfile(profile);
|
||||||
List<String> privateKeys = profile.getPrivateKeys();
|
initDApps();
|
||||||
SyngApplication.sEthereumConnector.init(privateKeys);
|
|
||||||
application.currentProfile = profile;
|
|
||||||
//currentPosition = spinnerAdapter.getPosition(profile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void requestChangeProfile(Profile profile) {
|
protected void requestChangeProfile(Profile profile) {
|
||||||
|
@ -374,6 +379,9 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
switch (v.getId()) {
|
switch (v.getId()) {
|
||||||
|
case R.id.ll_import_wallet:
|
||||||
|
onProfileImport();
|
||||||
|
break;
|
||||||
case R.id.ll_contribute:
|
case R.id.ll_contribute:
|
||||||
String url = CONTRIBUTE_LINK;
|
String url = CONTRIBUTE_LINK;
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
@ -405,6 +413,7 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
Profile profile = new Profile();
|
Profile profile = new Profile();
|
||||||
profile.setName(input.toString());
|
profile.setName(input.toString());
|
||||||
mProfiles.add(profile);
|
mProfiles.add(profile);
|
||||||
|
PrefsUtil.saveProfile(profile);
|
||||||
mAccountDrawerAdapter.notifyDataSetChanged();
|
mAccountDrawerAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
}).show();
|
}).show();
|
||||||
|
@ -501,17 +510,57 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDAppPress(final Dapp dapp) {
|
public void onProfileImport() {
|
||||||
new MaterialDialog.Builder(this)
|
new MaterialDialog.Builder(this)
|
||||||
.title("Edit")
|
.title(R.string.wallet_title)
|
||||||
.customView(R.layout.dapp_form, true)
|
.customView(R.layout.wallet_import, true)
|
||||||
.positiveText(R.string.save)
|
.positiveText(R.string.sImport)
|
||||||
.negativeText(R.string.cancel)
|
.negativeText(R.string.cancel)
|
||||||
.callback(new MaterialDialog.ButtonCallback() {
|
.callback(new MaterialDialog.ButtonCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositive(MaterialDialog dialog) {
|
public void onPositive(MaterialDialog dialog) {
|
||||||
Toast.makeText(BaseActivity.this, "Just do nothing", Toast.LENGTH_SHORT).show();
|
RadioButton importJsonRadio = (RadioButton)dialog.findViewById(R.id.radio_import_json);
|
||||||
|
EditText importPathEdit = (EditText)dialog.findViewById(R.id.wallet_import_path);
|
||||||
|
EditText walletPasswordEdit = (EditText)dialog.findViewById(R.id.wallet_password);
|
||||||
|
String importPath = importPathEdit.getText().toString();
|
||||||
|
String password = walletPasswordEdit.getText().toString();
|
||||||
|
String fileContents = null;
|
||||||
|
try {
|
||||||
|
File walletFile = new File(importPath);
|
||||||
|
if (walletFile.exists()) {
|
||||||
|
FileInputStream stream = new FileInputStream(walletFile);
|
||||||
|
try {
|
||||||
|
FileChannel fileChannel = stream.getChannel();
|
||||||
|
MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
|
||||||
|
fileContents = Charset.defaultCharset().decode(buffer).toString();
|
||||||
|
} finally {
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(BaseActivity.this, R.string.file_not_found, Toast.LENGTH_SHORT).show();
|
||||||
|
logger.warn("Wallet file not found: " + importPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast.makeText(BaseActivity.this, R.string.error_reading_file, Toast.LENGTH_SHORT).show();
|
||||||
|
logger.error("Error reading wallet file", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (importJsonRadio.isChecked()) {
|
||||||
|
if (SyngApplication.currentProfile != null) {
|
||||||
|
if (SyngApplication.currentProfile.importWallet(fileContents, password)) {
|
||||||
|
PrefsUtil.updateProfile(SyngApplication.currentProfile);
|
||||||
|
SyngApplication.changeProfile(SyngApplication.currentProfile);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(BaseActivity.this, R.string.invalid_wallet_password, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn("SyngApplication.currentProfile is null ...?!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SyngApplication.currentProfile.importPrivateKey(fileContents, password);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -522,9 +571,41 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
.build().show();
|
.build().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDAppPress(final Dapp dapp) {
|
||||||
|
MaterialDialog dialog = new MaterialDialog.Builder(this)
|
||||||
|
.title("Edit")
|
||||||
|
.customView(R.layout.dapp_form, true)
|
||||||
|
.positiveText(R.string.save)
|
||||||
|
.negativeText(R.string.cancel)
|
||||||
|
.callback(new MaterialDialog.ButtonCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPositive(MaterialDialog dialog) {
|
||||||
|
EditText dappNameEdit = (EditText) dialog.findViewById(R.id.dapp_name);
|
||||||
|
EditText dappUrlEdit = (EditText) dialog.findViewById(R.id.dapp_url);
|
||||||
|
dapp.setName(dappNameEdit.getText().toString());
|
||||||
|
dapp.setUrl(dappUrlEdit.getText().toString());
|
||||||
|
SyngApplication.updateDapp(dapp);
|
||||||
|
initDApps();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNegative(MaterialDialog dialog) {
|
||||||
|
dialog.hide();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
EditText dappNameEdit = (EditText) dialog.findViewById(R.id.dapp_name);
|
||||||
|
dappNameEdit.setText(dapp.getName());
|
||||||
|
EditText dappUrlEdit = (EditText) dialog.findViewById(R.id.dapp_url);
|
||||||
|
dappUrlEdit.setText(dapp.getUrl());
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProfilePress(Profile profile) {
|
public void onProfilePress(Profile profile) {
|
||||||
new MaterialDialog.Builder(this)
|
MaterialDialog dialog = new MaterialDialog.Builder(this)
|
||||||
.title("Edit account")
|
.title("Edit account")
|
||||||
.content("Put your name to create new account")
|
.content("Put your name to create new account")
|
||||||
.inputType(InputType.TYPE_CLASS_TEXT)
|
.inputType(InputType.TYPE_CLASS_TEXT)
|
||||||
|
@ -534,7 +615,7 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
Toast.makeText(BaseActivity.this, "Just do nothing", Toast.LENGTH_SHORT).show();
|
Toast.makeText(BaseActivity.this, "Just do nothing", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}).show();
|
}).show();
|
||||||
|
dialog.getInputEditText().setText(profile.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -548,7 +629,12 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositive(MaterialDialog dialog) {
|
public void onPositive(MaterialDialog dialog) {
|
||||||
Toast.makeText(BaseActivity.this, "Just do nothing", Toast.LENGTH_SHORT).show();
|
EditText dappNameEdit = (EditText)dialog.findViewById(R.id.dapp_name);
|
||||||
|
EditText dappUrlEdit = (EditText)dialog.findViewById(R.id.dapp_url);
|
||||||
|
Dapp dapp = new Dapp(dappNameEdit.getText().toString());
|
||||||
|
dapp.setUrl(dappUrlEdit.getText().toString());
|
||||||
|
SyngApplication.addDapp(dapp);
|
||||||
|
initDApps();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,6 +27,7 @@ public class AccountDrawerAdapter extends RecyclerView.Adapter<RecyclerView.View
|
||||||
|
|
||||||
void onProfileClick(Profile profile);
|
void onProfileClick(Profile profile);
|
||||||
void onProfilePress(Profile profile);
|
void onProfilePress(Profile profile);
|
||||||
|
void onProfileImport();
|
||||||
void onNewProfile();
|
void onNewProfile();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@ import com.squareup.leakcanary.RefWatcher;
|
||||||
import org.ethereum.android.service.ConnectorHandler;
|
import org.ethereum.android.service.ConnectorHandler;
|
||||||
import org.ethereum.android.service.EthereumConnector;
|
import org.ethereum.android.service.EthereumConnector;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.syng.entity.Dapp;
|
||||||
import io.syng.entity.Profile;
|
import io.syng.entity.Profile;
|
||||||
import io.syng.service.EthereumService;
|
import io.syng.service.EthereumService;
|
||||||
import io.syng.util.PrefsUtil;
|
import io.syng.util.PrefsUtil;
|
||||||
|
@ -20,7 +23,23 @@ public class SyngApplication extends MultiDexApplication implements ConnectorHan
|
||||||
|
|
||||||
private RefWatcher refWatcher;
|
private RefWatcher refWatcher;
|
||||||
|
|
||||||
public Profile currentProfile;
|
public static Profile currentProfile;
|
||||||
|
|
||||||
|
public static void changeProfile(Profile profile) {
|
||||||
|
List<String> privateKeys = profile.getPrivateKeys();
|
||||||
|
sEthereumConnector.init(privateKeys);
|
||||||
|
currentProfile = profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addDapp(Dapp dapp) {
|
||||||
|
currentProfile.addDapp(dapp);
|
||||||
|
PrefsUtil.updateProfile(currentProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateDapp(Dapp dapp) {
|
||||||
|
currentProfile.updateDapp(dapp);
|
||||||
|
PrefsUtil.updateProfile(currentProfile);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
|
|
|
@ -1,22 +1,40 @@
|
||||||
package io.syng.entity;
|
package io.syng.entity;
|
||||||
|
|
||||||
public class Dapp {
|
import org.ethereum.crypto.HashUtil;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class Dapp implements Serializable {
|
||||||
|
|
||||||
protected String name = "";
|
protected String name = "";
|
||||||
protected String version = "";
|
protected String version = "";
|
||||||
protected String url = "";
|
protected String url = "";
|
||||||
protected String id;
|
protected String id = "";
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public Dapp(String id, String name) {
|
public Dapp(String id, String name) {
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dapp(String name) {
|
public Dapp(String name) {
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.id = generateID();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dapp() {
|
public Dapp() {
|
||||||
|
|
||||||
|
this.id = generateID();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateID() {
|
||||||
|
|
||||||
|
byte[] privateKey = HashUtil.sha3(HashUtil.randomPeerId());
|
||||||
|
return Hex.toHexString(privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
package io.syng.entity;
|
package io.syng.entity;
|
||||||
|
|
||||||
|
import org.ethereum.crypto.ECKey;
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
|
import org.ethereum.wallet.EtherSaleWallet;
|
||||||
|
import org.ethereum.wallet.EtherSaleWalletDecoder;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -9,6 +15,8 @@ import java.util.List;
|
||||||
|
|
||||||
public class Profile implements Serializable {
|
public class Profile implements Serializable {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger("Profile");
|
||||||
|
|
||||||
protected String name;
|
protected String name;
|
||||||
|
|
||||||
protected List<String> privateKeys = new ArrayList<>();
|
protected List<String> privateKeys = new ArrayList<>();
|
||||||
|
@ -16,7 +24,7 @@ public class Profile implements Serializable {
|
||||||
/* "password protect profile" (encrypt the private keys) */
|
/* "password protect profile" (encrypt the private keys) */
|
||||||
protected boolean passwordProtectedProfile = false;
|
protected boolean passwordProtectedProfile = false;
|
||||||
|
|
||||||
protected List<Dapp> dapps;
|
protected List<Dapp> dapps = new ArrayList<>();
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ -80,6 +88,16 @@ public class Profile implements Serializable {
|
||||||
this.dapps.add(dapp);
|
this.dapps.add(dapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateDapp(Dapp dapp) {
|
||||||
|
|
||||||
|
for (Dapp item: dapps) {
|
||||||
|
if (item.getId().equals(dapp.getId())) {
|
||||||
|
int index = dapps.indexOf(item);
|
||||||
|
dapps.set(index, dapp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void removeDapp(Dapp dapp) {
|
public void removeDapp(Dapp dapp) {
|
||||||
|
|
||||||
this.dapps.remove(dapp);
|
this.dapps.remove(dapp);
|
||||||
|
@ -150,4 +168,50 @@ public class Profile implements Serializable {
|
||||||
// TODO: Decrypt private key
|
// TODO: Decrypt private key
|
||||||
return privateKey;
|
return privateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean importWallet(String jsonWallet, String password) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONObject json = new JSONObject(jsonWallet);
|
||||||
|
byte[] privateKey = null;
|
||||||
|
EtherSaleWallet wallet = new EtherSaleWallet();
|
||||||
|
if (json.has("encseed")) {
|
||||||
|
wallet.setEncseed(json.getString("encseed"));
|
||||||
|
wallet.setEthaddr(json.getString("ethaddr"));
|
||||||
|
wallet.setEmail(json.getString("email"));
|
||||||
|
wallet.setBtcaddr(json.getString("btcaddr"));
|
||||||
|
EtherSaleWalletDecoder decoder = new EtherSaleWalletDecoder(wallet);
|
||||||
|
privateKey = decoder.getPrivateKey(password);
|
||||||
|
} else if (json.has("Crypto")) {
|
||||||
|
wallet.setEncseed(json.getJSONObject("Crypto").getJSONObject("cipherparams").getString("iv") + json.getJSONObject("Crypto").getString("ciphertext"));
|
||||||
|
wallet.setEthaddr(json.getString("address"));
|
||||||
|
EtherSaleWalletDecoder decoder = new EtherSaleWalletDecoder(wallet);
|
||||||
|
privateKey = decoder.getPrivateKey(password);
|
||||||
|
}
|
||||||
|
if (privateKey == null) {
|
||||||
|
logger.warn("Invalid json wallet file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ECKey key = ECKey.fromPrivate(privateKey);
|
||||||
|
String address = Hex.toHexString(key.getAddress());
|
||||||
|
if (address.equals(wallet.getEthaddr())) {
|
||||||
|
privateKeys.add(Hex.toHexString(privateKey));
|
||||||
|
} else {
|
||||||
|
logger.warn("Invalid wallet password.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error importing wallet.", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void importPrivateKey(String privateKey, String password) {
|
||||||
|
|
||||||
|
privateKeys.add(decryptPrivateKey(privateKey, password));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public final class PrefsUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Editor getEditor() {
|
private static Editor getEditor() {
|
||||||
return getInstance().mPreferences.edit();
|
return getPrefs().edit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SharedPreferences getPrefs() {
|
private static SharedPreferences getPrefs() {
|
||||||
|
@ -48,11 +48,12 @@ public final class PrefsUtil {
|
||||||
|
|
||||||
public static void saveProfiles(ArrayList<Profile> profiles) {
|
public static void saveProfiles(ArrayList<Profile> profiles) {
|
||||||
try {
|
try {
|
||||||
getEditor().putString(PROFILES_KEY, ObjectSerializer.serialize(profiles));
|
SharedPreferences.Editor editor = getEditor();
|
||||||
|
editor.putString(PROFILES_KEY, ObjectSerializer.serialize(profiles));
|
||||||
|
editor.apply();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
getEditor().apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ArrayList<Profile> getProfiles() {
|
public static ArrayList<Profile> getProfiles() {
|
||||||
|
@ -65,6 +66,32 @@ public final class PrefsUtil {
|
||||||
return profiles;
|
return profiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void updateProfile(Profile profile) {
|
||||||
|
|
||||||
|
ArrayList<Profile> profiles = getProfiles();
|
||||||
|
for (Profile item: profiles) {
|
||||||
|
if (item.getName().equals(profile.getName())) {
|
||||||
|
int index = profiles.indexOf(item);
|
||||||
|
profiles.set(index, profile);
|
||||||
|
saveProfiles(profiles);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean saveProfile(Profile profile) {
|
||||||
|
|
||||||
|
ArrayList<Profile> profiles = PrefsUtil.getProfiles();
|
||||||
|
for (Profile item: profiles) {
|
||||||
|
if (item.getName().equals(profile.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
profiles.add(profile);
|
||||||
|
saveProfiles(profiles);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void setFirstLaunch(boolean isFirstLaunch) {
|
public static void setFirstLaunch(boolean isFirstLaunch) {
|
||||||
getEditor().putBoolean(FIRST_LAUNCH_KEY, isFirstLaunch).apply();
|
getEditor().putBoolean(FIRST_LAUNCH_KEY, isFirstLaunch).apply();
|
||||||
|
|
|
@ -17,6 +17,35 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_import_wallet"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/listPreferredItemHeightSmall"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:src="@drawable/ic_add_black_24dp"
|
||||||
|
android:tint="@color/drawer_icons_color"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_import_wallet"
|
||||||
|
style="@style/Base.TextAppearance.AppCompat.Body2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/listPreferredItemHeightSmall"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingLeft="32dp"
|
||||||
|
android:paddingStart="32dp"
|
||||||
|
android:text="Import Wallet"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/ll_settings"
|
android:id="@+id/ll_settings"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -2,33 +2,36 @@
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:orientation="vertical" android:layout_width="match_parent"
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
|
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
<RadioButton android:id="@+id/radio_new_account"
|
<RadioButton android:id="@+id/radio_import_json"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textColor="@color/accent"
|
android:textColor="@color/accent"
|
||||||
android:text="@string/create_new_wallet"/>
|
android:checked="true"
|
||||||
<RadioButton android:id="@+id/radio_import_file"
|
android:text="@string/json_wallet"/>
|
||||||
|
<RadioButton android:id="@+id/radio_import_hex"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textColor="@color/accent"
|
android:textColor="@color/accent"
|
||||||
android:text="@string/import_wallet_from_file"/>
|
android:text="@string/hex_private_key"/>
|
||||||
<RadioButton android:id="@+id/radio_import_string"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textColor="@color/accent"
|
|
||||||
android:text="@string/import_account_from_string"/>
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/accout_import_source"
|
android:id="@+id/wallet_import_path"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textColor="@color/accent"
|
android:textColor="@color/accent"
|
||||||
android:inputType="none"/>
|
android:singleLine="true"
|
||||||
|
android:hint="File Path"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/wallet_password"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/accent"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:hint="Password"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -15,15 +15,18 @@
|
||||||
<string name="url">Url</string>
|
<string name="url">Url</string>
|
||||||
<string name="save">Save</string>
|
<string name="save">Save</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
|
<string name="sImport">Import</string>
|
||||||
<string name="manage_profiles">Manage Profiles</string>
|
<string name="manage_profiles">Manage Profiles</string>
|
||||||
|
|
||||||
<string name="title_activity_spash_screen">Syng</string>
|
<string name="title_activity_spash_screen">Syng</string>
|
||||||
|
|
||||||
<string name="wallet_title">Wallet</string>
|
<string name="wallet_title">Import Wallet</string>
|
||||||
<string name="ok">OK</string>
|
<string name="ok">OK</string>
|
||||||
<string name="create_new_wallet">Create new Wallet</string>
|
<string name="json_wallet">Import json wallet</string>
|
||||||
<string name="import_wallet_from_file">Import wallet from file</string>
|
<string name="hex_private_key">Import hex encoded private key</string>
|
||||||
<string name="import_account_from_string">Import account from string</string>
|
<string name="file_not_found">The specified file was not found.</string>
|
||||||
|
<string name="error_reading_file">Error reading specified file.</string>
|
||||||
|
<string name="invalid_wallet_password">Invalid wallet or password.</string>
|
||||||
|
|
||||||
<string name="request_profile_password">Profile Password</string>
|
<string name="request_profile_password">Profile Password</string>
|
||||||
<string name="warning.message">This is PRE-ALPHA software and most likely contains numerous bugs. The layout, design, and functionality may change frequently. This also lacks numerous features that will be included in later versions. Using this software you agree that you hold yourself personally accountable for interacting with this software.</string>
|
<string name="warning.message">This is PRE-ALPHA software and most likely contains numerous bugs. The layout, design, and functionality may change frequently. This also lacks numerous features that will be included in later versions. Using this software you agree that you hold yourself personally accountable for interacting with this software.</string>
|
||||||
|
|
Loading…
Reference in New Issue