network slection in menu (#71)

moved code from fragment to activity; dropdownlist is now better
This commit is contained in:
m2049r 2017-09-19 19:46:22 +02:00 committed by GitHub
parent ba408b8889
commit c4f9e8cf58
7 changed files with 259 additions and 267 deletions

View File

@ -26,6 +26,7 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.StrictMode;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@ -39,10 +40,12 @@ import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.m2049r.xmrwallet.layout.DropDownEditText;
import com.m2049r.xmrwallet.license.LicensesFragment; import com.m2049r.xmrwallet.license.LicensesFragment;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
@ -50,12 +53,16 @@ import com.m2049r.xmrwallet.service.WalletService;
import com.m2049r.xmrwallet.util.AsyncExchangeRate; import com.m2049r.xmrwallet.util.AsyncExchangeRate;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor; import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import com.m2049r.xmrwallet.util.NodeList;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.util.Date;
public class LoginActivity extends AppCompatActivity public class LoginActivity extends AppCompatActivity
implements LoginFragment.Listener, GenerateFragment.Listener, implements LoginFragment.Listener, GenerateFragment.Listener,
@ -66,6 +73,9 @@ public class LoginActivity extends AppCompatActivity
static final int DAEMON_TIMEOUT = 500; // deamon must respond in 500ms static final int DAEMON_TIMEOUT = 500; // deamon must respond in 500ms
Toolbar toolbar; Toolbar toolbar;
EditText etDummy;
DropDownEditText etDaemonAddress;
ArrayAdapter<String> nodeAdapter;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -78,6 +88,45 @@ public class LoginActivity extends AppCompatActivity
toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
etDummy = (EditText) findViewById(R.id.etDummy);
etDaemonAddress = (DropDownEditText) findViewById(R.id.etDaemonAddress);
nodeAdapter = new ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line);
etDaemonAddress.setAdapter(nodeAdapter);
Helper.hideKeyboard(this);
etDaemonAddress.setThreshold(0);
etDaemonAddress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
etDaemonAddress.showDropDown();
Helper.showKeyboard(LoginActivity.this);
}
});
etDaemonAddress.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
etDaemonAddress.showDropDown();
Helper.showKeyboard(LoginActivity.this);
}
}
});
etDaemonAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
Helper.hideKeyboard(LoginActivity.this);
etDummy.requestFocus();
return true;
}
return false;
}
});
loadPrefs();
if (Helper.getWritePermission(this)) { if (Helper.getWritePermission(this)) {
startLoginFragment(); startLoginFragment();
} else { } else {
@ -96,6 +145,22 @@ public class LoginActivity extends AppCompatActivity
@Override @Override
public void onWalletSelected(final String walletName) { public void onWalletSelected(final String walletName) {
String daemon = getDaemon();
if (daemon.length() == 0) {
Toast.makeText(this, getString(R.string.prompt_daemon_missing), Toast.LENGTH_SHORT).show();
etDaemonAddress.requestFocus();
Helper.showKeyboard(this);
return;
}
if (!checkAndSetWalletDaemon(getDaemon(), isTestnet())) {
Toast.makeText(this, getString(R.string.warn_daemon_unavailable), Toast.LENGTH_SHORT).show();
return;
}
// looking good
savePrefs();
if (checkServiceRunning()) return; if (checkServiceRunning()) return;
Log.d(TAG, "selected wallet is ." + walletName + "."); Log.d(TAG, "selected wallet is ." + walletName + ".");
// now it's getting real, check if wallet exists // now it's getting real, check if wallet exists
@ -114,6 +179,7 @@ public class LoginActivity extends AppCompatActivity
@Override @Override
public void onWalletDetails(final String walletName) { public void onWalletDetails(final String walletName) {
checkAndSetWalletDaemon("", isTestnet()); // just set selected net
Log.d(TAG, "details for wallet ." + walletName + "."); Log.d(TAG, "details for wallet ." + walletName + ".");
if (checkServiceRunning()) return; if (checkServiceRunning()) return;
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@ -151,6 +217,7 @@ public class LoginActivity extends AppCompatActivity
@Override @Override
public void onWalletReceive(String walletName) { public void onWalletReceive(String walletName) {
checkAndSetWalletDaemon("", isTestnet()); // just set selected net
Log.d(TAG, "receive for wallet ." + walletName + "."); Log.d(TAG, "receive for wallet ." + walletName + ".");
if (checkServiceRunning()) return; if (checkServiceRunning()) return;
final File walletFile = Helper.getWalletFile(this, walletName); final File walletFile = Helper.getWalletFile(this, walletName);
@ -376,13 +443,16 @@ public class LoginActivity extends AppCompatActivity
try { try {
LoginFragment loginFragment = (LoginFragment) LoginFragment loginFragment = (LoginFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container); getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (loginFragment != null) {
loginFragment.loadList(); loginFragment.loadList();
}
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
} }
} }
@Override @Override
public void onAddWallet() { public void onAddWallet() {
checkAndSetWalletDaemon("", isTestnet());
if (checkServiceRunning()) return; if (checkServiceRunning()) return;
startGenerateFragment(); startGenerateFragment();
} }
@ -477,30 +547,30 @@ public class LoginActivity extends AppCompatActivity
return Helper.getStorageRoot(getApplicationContext()); return Helper.getStorageRoot(getApplicationContext());
} }
@Override ////////////////////////////////////////
////////////////////////////////////////
public void setTitle(String title) { public void setTitle(String title) {
toolbar.setTitle(title); toolbar.setTitle(title);
} }
@Override
public void setSubtitle(String subtitle) { public void setSubtitle(String subtitle) {
toolbar.setSubtitle(subtitle); toolbar.setSubtitle(subtitle);
} }
@Override public void showNet(boolean testnet) {
public void setTestNet(boolean testnet) {
if (testnet) { if (testnet) {
toolbar.setBackgroundResource(R.color.colorPrimaryDark); toolbar.setBackgroundResource(R.color.colorPrimaryDark);
} else { } else {
toolbar.setBackgroundResource(R.color.moneroOrange); toolbar.setBackgroundResource(R.color.moneroOrange);
} }
setSubtitle(getString(testnet ? R.string.connect_testnet : R.string.connect_mainnet));
} }
////////////////////////////////////////
////////////////////////////////////////
@Override @Override
protected void onPause() { protected void onPause() {
Log.d(TAG, "onPause()"); Log.d(TAG, "onPause()");
savePrefs();
super.onPause(); super.onPause();
} }
@ -510,6 +580,7 @@ public class LoginActivity extends AppCompatActivity
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
Log.d(TAG, "onResume()"); Log.d(TAG, "onResume()");
setTitle(getString(R.string.login_activity_name));
// wait for WalletService to finish // wait for WalletService to finish
if (WalletService.Running && (asyncWaitTask == null)) { if (WalletService.Running && (asyncWaitTask == null)) {
// and show a progress dialog, but only if there isn't one already // and show a progress dialog, but only if there isn't one already
@ -920,15 +991,159 @@ public class LoginActivity extends AppCompatActivity
} }
} }
boolean testnet = false;
@Override
public boolean isTestnet() {
return testnet;
}
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_lincense_info: case R.id.action_lincense_info:
LicensesFragment.displayLicensesFragment(getSupportFragmentManager()); LicensesFragment.displayLicensesFragment(getSupportFragmentManager());
return true; return true;
case R.id.action_testnet:
boolean lastState = testnet;//item.isChecked();
item.setChecked(!lastState);
setNet(!lastState, true); // set and save
return true;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
} }
public void setNet(boolean testnet, boolean save) {
this.testnet = testnet;
showNet(testnet);
if (save) {
savePrefs(true); // use previous state as we just clicked it
}
if (testnet) {
setDaemon(daemonTestNet);
} else {
setDaemon(daemonMainNet);
}
etDummy.requestFocus();
Helper.hideKeyboard(this);
reloadWalletList();
}
String getDaemon() {
return etDaemonAddress.getText().toString();
}
void setDaemon(NodeList nodeList) {
Log.d(TAG, "setDaemon() " + nodeList.toString());
String[] nodes = nodeList.getNodes().toArray(new String[0]);
nodeAdapter.clear();
nodeAdapter.addAll(nodes);
etDaemonAddress.getText().clear();
if (nodes.length > 0) {
etDaemonAddress.setText(nodes[0]);
}
etDaemonAddress.dismissDropDown();
}
private static final String PREF_DAEMON_TESTNET = "daemon_testnet";
private static final String PREF_DAEMON_MAINNET = "daemon_mainnet";
private static final String PREF_TESTNET = "testnet";
private static final String PREF_DAEMONLIST_MAINNET =
"node.moneroworld.com:18089;node.xmrbackb.one:18081;node.xmr.be:18081";
private NodeList daemonTestNet;
private NodeList daemonMainNet;
void loadPrefs() {
SharedPreferences sharedPref = getPrefs();
boolean testnet = sharedPref.getBoolean(PREF_TESTNET, false);
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, ""));
//############### ignore last net state - always start in mainnet (like other clients)
// MenuItem net = (MenuItem) getView().findViewById(R.id.action_testnet);
// net.setChecked(!mainnet);
setNet(testnet, false);
}
void savePrefs() {
savePrefs(false);
}
void savePrefs(boolean usePreviousState) {
Log.d(TAG, "SAVE / " + usePreviousState);
// save the daemon address for the net
boolean testnet = isTestnet() ^ usePreviousState;
String daemon = getDaemon();
if (testnet) {
daemonTestNet.setRecent(daemon);
} else {
daemonMainNet.setRecent(daemon);
}
SharedPreferences sharedPref = getPrefs();
SharedPreferences.Editor editor = sharedPref.edit();
//editor.putBoolean(PREF_TESTNET, testnet);
editor.putString(PREF_DAEMON_MAINNET, daemonMainNet.toString());
editor.putString(PREF_DAEMON_TESTNET, daemonTestNet.toString());
editor.apply();
}
private boolean checkAndSetWalletDaemon(String daemon, boolean testnet) {
String daemonAddress = "";
String username = "";
String password = "";
if (!daemon.isEmpty()) { // no actual daemon is also fine
String a[] = daemon.split("@");
if (a.length == 1) { // no credentials
daemonAddress = a[0];
} else if (a.length == 2) { // credentials
String up[] = a[0].split(":");
if (up.length != 2) return false;
username = up[0];
if (!username.isEmpty()) password = up[1];
daemonAddress = a[1];
} else {
return false;
}
String da[] = daemonAddress.split(":");
if ((da.length > 2) || (da.length < 1)) return false;
String host = da[0];
int port;
if (da.length == 2) {
try {
port = Integer.parseInt(da[1]);
} catch (NumberFormatException ex) {
return false;
}
} else {
port = (testnet ? 28081 : 18081);
daemonAddress = daemonAddress + ":" + port;
}
//Log.d(TAG, "DAEMON " + username + "/" + password + "/" + host + "/" + port);
// if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy prevPolicy = StrictMode.getThreadPolicy();
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder(prevPolicy).permitNetwork().build();
StrictMode.setThreadPolicy(policy);
Socket socket = new Socket();
long timeA = new Date().getTime();
try {
socket.connect(new InetSocketAddress(host, port), LoginActivity.DAEMON_TIMEOUT);
socket.close();
} catch (IOException ex) {
Log.d(TAG, "Cannot reach daemon " + host + "/" + port + " because " + ex.getLocalizedMessage());
return false;
} finally {
StrictMode.setThreadPolicy(prevPolicy);
}
long timeB = new Date().getTime();
Log.d(TAG, "Daemon is " + (timeB - timeA) + "ms away.");
}
WalletManager mgr = WalletManager.getInstance();
mgr.setDaemon(daemonAddress, testnet, username, password);
return true;
}
} }

View File

@ -19,42 +19,31 @@ package com.m2049r.xmrwallet;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.StrictMode;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import android.widget.ToggleButton;
import com.m2049r.xmrwallet.layout.InstantAutoComplete;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.NodeList;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@ -75,10 +64,6 @@ public class LoginFragment extends Fragment {
}); });
List<String> displayedList = new ArrayList<>(); List<String> displayedList = new ArrayList<>();
ToggleButton tbMainNet;
InstantAutoComplete etDaemonAddress;
ArrayAdapter<String> nodeAdapter;
FloatingActionButton fabAdd; FloatingActionButton fabAdd;
Listener activityCallback; Listener activityCallback;
@ -103,11 +88,7 @@ public class LoginFragment extends Fragment {
void onAddWallet(); void onAddWallet();
void setTitle(String title); boolean isTestnet();
void setSubtitle(String subtitle);
void setTestNet(boolean testnet);
} }
@ -125,7 +106,6 @@ public class LoginFragment extends Fragment {
@Override @Override
public void onPause() { public void onPause() {
Log.d(TAG, "onPause()"); Log.d(TAG, "onPause()");
savePrefs();
super.onPause(); super.onPause();
} }
@ -133,7 +113,6 @@ public class LoginFragment extends Fragment {
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
Log.d(TAG, "onResume()"); Log.d(TAG, "onResume()");
activityCallback.setTitle(getString(R.string.login_activity_name));
} }
@Override @Override
@ -142,76 +121,23 @@ public class LoginFragment extends Fragment {
Log.d(TAG, "onCreateView"); Log.d(TAG, "onCreateView");
View view = inflater.inflate(R.layout.login_fragment, container, false); View view = inflater.inflate(R.layout.login_fragment, container, false);
tbMainNet = (ToggleButton) view.findViewById(R.id.tbMainNet);
etDaemonAddress = (InstantAutoComplete) view.findViewById(R.id.etDaemonAddress);
nodeAdapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_dropdown_item_1line);
etDaemonAddress.setAdapter(nodeAdapter);
fabAdd = (FloatingActionButton) view.findViewById(R.id.fabAdd); fabAdd = (FloatingActionButton) view.findViewById(R.id.fabAdd);
fabAdd.setOnClickListener(new View.OnClickListener() { fabAdd.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
checkAndSetWalletDaemon("", !isMainNet());
activityCallback.onAddWallet(); activityCallback.onAddWallet();
} }
}); });
Helper.hideKeyboard(getActivity());
etDaemonAddress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.showKeyboard(getActivity());
}
});
etDaemonAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
Helper.hideKeyboard(getActivity());
return false;
}
return false;
}
});
tbMainNet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean mainnet = ((ToggleButton) v).isChecked(); // current state
activityCallback.setTestNet(!mainnet);
savePrefs(true); // use previous state as we just clicked it
if (mainnet) {
setDaemon(daemonMainNet);
} else {
setDaemon(daemonTestNet);
}
activityCallback.setSubtitle(getString(mainnet ? R.string.connect_mainnet : R.string.connect_testnet));
filterList();
((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
}
});
loadPrefs();
activityCallback.setSubtitle(getString(isMainNet() ? R.string.connect_mainnet : R.string.connect_testnet));
listView = (ListView) view.findViewById(R.id.list); listView = (ListView) view.findViewById(R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
android.R.layout.simple_list_item_1, android.R.id.text1, this.displayedList); android.R.layout.simple_list_item_1, android.R.id.text1, this.displayedList);
listView.setAdapter(adapter); listView.setAdapter(adapter);
registerForContextMenu(listView); registerForContextMenu(listView);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
EditText tvDaemonAddress = (EditText) getView().findViewById(R.id.etDaemonAddress);
if (tvDaemonAddress.getText().toString().length() == 0) {
Toast.makeText(getActivity(), getString(R.string.prompt_daemon_missing), Toast.LENGTH_SHORT).show();
tvDaemonAddress.requestFocus();
Helper.showKeyboard(getActivity());
return;
}
String itemValue = (String) listView.getItemAtPosition(position); String itemValue = (String) listView.getItemAtPosition(position);
if (itemValue.length() <= (WALLETNAME_PREAMBLE_LENGTH)) { if (itemValue.length() <= (WALLETNAME_PREAMBLE_LENGTH)) {
@ -219,21 +145,14 @@ public class LoginFragment extends Fragment {
return; return;
} }
String x = isMainNet() ? "4-" : "9A-"; String x = activityCallback.isTestnet() ? "9A-" : "4-";
if (x.indexOf(itemValue.charAt(1)) < 0) { if (x.indexOf(itemValue.charAt(1)) < 0) {
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show(); Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
return; return;
} }
if (!checkAndSetWalletDaemon(getDaemon(), !isMainNet())) {
Toast.makeText(getActivity(), getString(R.string.warn_daemon_unavailable), Toast.LENGTH_SHORT).show();
return;
}
// looking good
savePrefs();
String wallet = itemValue.substring(WALLETNAME_PREAMBLE_LENGTH); String wallet = itemValue.substring(WALLETNAME_PREAMBLE_LENGTH);
activityCallback.onWalletSelected(wallet); activityCallback.onWalletSelected(wallet);
} }
}); });
@ -244,7 +163,7 @@ public class LoginFragment extends Fragment {
private void filterList() { private void filterList() {
displayedList.clear(); displayedList.clear();
String x = isMainNet() ? "4" : "9A"; String x = activityCallback.isTestnet() ? "9A" : "4";
for (String s : walletList) { for (String s : walletList) {
if (x.indexOf(s.charAt(1)) >= 0) displayedList.add(s); if (x.indexOf(s.charAt(1)) >= 0) displayedList.add(s);
} }
@ -252,6 +171,7 @@ public class LoginFragment extends Fragment {
public void loadList() { public void loadList() {
Log.d(TAG, "loadList()"); Log.d(TAG, "loadList()");
// TODO this should probably be in LoginActivity
WalletManager mgr = WalletManager.getInstance(); WalletManager mgr = WalletManager.getInstance();
List<WalletManager.WalletInfo> walletInfos = List<WalletManager.WalletInfo> walletInfos =
mgr.findWallets(activityCallback.getStorageRoot()); mgr.findWallets(activityCallback.getStorageRoot());
@ -272,135 +192,6 @@ public class LoginFragment extends Fragment {
} }
boolean isMainNet() {
return tbMainNet.isChecked();
}
void setMainNet(boolean mainnet) {
tbMainNet.setChecked(mainnet);
activityCallback.setTestNet(!mainnet);
}
String getDaemon() {
return etDaemonAddress.getText().toString();
}
void setDaemon(NodeList nodeList) {
Log.d(TAG, "setDaemon() " + nodeList.toString());
String[] nodes = nodeList.getNodes().toArray(new String[0]);
nodeAdapter.clear();
nodeAdapter.addAll(nodes);
etDaemonAddress.getText().clear();
if (nodes.length > 0) {
etDaemonAddress.setText(nodes[0]);
}
etDaemonAddress.dismissDropDown();
}
private static final String PREF_DAEMON_TESTNET = "daemon_testnet";
private static final String PREF_DAEMON_MAINNET = "daemon_mainnet";
private static final String PREF_MAINNET = "mainnet";
private static final String PREF_DAEMONLIST_MAINNET =
"node.moneroworld.com:18089;node.xmrbackb.one:18081;node.xmr.be:18081";
private NodeList daemonTestNet;
private NodeList daemonMainNet;
void loadPrefs() {
SharedPreferences sharedPref = activityCallback.getPrefs();
boolean mainnet = sharedPref.getBoolean(PREF_MAINNET, false);
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, ""));
setMainNet(mainnet);
if (mainnet) {
setDaemon(daemonMainNet);
} else {
setDaemon(daemonTestNet);
}
}
void savePrefs() {
savePrefs(false);
}
void savePrefs(boolean usePreviousState) {
// save the daemon address for the net
boolean mainnet = isMainNet() ^ usePreviousState;
String daemon = getDaemon();
if (mainnet) {
daemonMainNet.setRecent(daemon);
} else {
daemonTestNet.setRecent(daemon);
}
SharedPreferences sharedPref = activityCallback.getPrefs();
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(PREF_MAINNET, mainnet);
editor.putString(PREF_DAEMON_MAINNET, daemonMainNet.toString());
editor.putString(PREF_DAEMON_TESTNET, daemonTestNet.toString());
editor.apply();
}
private boolean checkAndSetWalletDaemon(String daemon, boolean testnet) {
String daemonAddress = "";
String username = "";
String password = "";
if (!daemon.isEmpty()) { // no actual daemon is also fine
String a[] = daemon.split("@");
if (a.length == 1) { // no credentials
daemonAddress = a[0];
} else if (a.length == 2) { // credentials
String up[] = a[0].split(":");
if (up.length != 2) return false;
username = up[0];
if (!username.isEmpty()) password = up[1];
daemonAddress = a[1];
} else {
return false;
}
String da[] = daemonAddress.split(":");
if ((da.length > 2) || (da.length < 1)) return false;
String host = da[0];
int port;
if (da.length == 2) {
try {
port = Integer.parseInt(da[1]);
} catch (NumberFormatException ex) {
return false;
}
} else {
port = (testnet ? 28081 : 18081);
daemonAddress = daemonAddress + ":" + port;
}
//Log.d(TAG, "DAEMON " + username + "/" + password + "/" + host + "/" + port);
// if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy prevPolicy = StrictMode.getThreadPolicy();
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder(prevPolicy).permitNetwork().build();
StrictMode.setThreadPolicy(policy);
Socket socket = new Socket();
long timeA = new Date().getTime();
try {
socket.connect(new InetSocketAddress(host, port), LoginActivity.DAEMON_TIMEOUT);
socket.close();
} catch (IOException ex) {
Log.d(TAG, "Cannot reach daemon " + host + "/" + port + " because " + ex.getLocalizedMessage());
return false;
} finally {
StrictMode.setThreadPolicy(prevPolicy);
}
long timeB = new Date().getTime();
Log.d(TAG, "Daemon is " + (timeB - timeA) + "ms away.");
}
WalletManager mgr = WalletManager.getInstance();
mgr.setDaemon(daemonAddress, testnet, username, password);
return true;
}
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View v, public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) { ContextMenu.ContextMenuInfo menuInfo) {
@ -413,7 +204,7 @@ public class LoginFragment extends Fragment {
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
String listItem = (String) listView.getItemAtPosition(info.position); String listItem = (String) listView.getItemAtPosition(info.position);
String name = nameFromListItem(listItem, !isMainNet()); String name = nameFromListItem(listItem, activityCallback.isTestnet());
if (name == null) { if (name == null) {
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show(); Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
} }
@ -440,14 +231,10 @@ public class LoginFragment extends Fragment {
} }
private void showInfo(@NonNull String name) { private void showInfo(@NonNull String name) {
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
activityCallback.onWalletDetails(name); activityCallback.onWalletDetails(name);
} }
private boolean showReceive(@NonNull String name) { private boolean showReceive(@NonNull String name) {
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
activityCallback.onWalletReceive(name); activityCallback.onWalletReceive(name);
return true; return true;
} }

View File

@ -23,17 +23,17 @@ import android.graphics.Rect;
import android.support.v7.widget.AppCompatAutoCompleteTextView; import android.support.v7.widget.AppCompatAutoCompleteTextView;
import android.util.AttributeSet; import android.util.AttributeSet;
public class InstantAutoComplete extends AppCompatAutoCompleteTextView { public class DropDownEditText extends AppCompatAutoCompleteTextView {
public InstantAutoComplete(Context context) { public DropDownEditText(Context context) {
super(context); super(context);
} }
public InstantAutoComplete(Context arg0, AttributeSet arg1) { public DropDownEditText(Context arg0, AttributeSet arg1) {
super(arg0, arg1); super(arg0, arg1);
} }
public InstantAutoComplete(Context arg0, AttributeSet arg1, int arg2) { public DropDownEditText(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2); super(arg0, arg1, arg2);
} }
@ -47,7 +47,7 @@ public class InstantAutoComplete extends AppCompatAutoCompleteTextView {
Rect previouslyFocusedRect) { Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect); super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (focused && getAdapter() != null) { if (focused && getAdapter() != null) {
performFiltering(getText(), 0); performFiltering("", 0);
} }
} }

View File

@ -9,6 +9,23 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
layout="@layout/toolbar" /> layout="@layout/toolbar" />
<EditText
android:id="@+id/etDummy"
android:layout_width="0sp"
android:layout_height="0sp" />
<com.m2049r.xmrwallet.layout.DropDownEditText
android:id="@+id/etDaemonAddress"
style="@style/MoneroEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:hint="@string/prompt_daemon"
android:imeOptions="actionDone"
android:inputType="textWebEmailAddress|textNoSuggestions"
android:maxLines="1"
android:textIsSelectable="true" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container" android:id="@+id/fragment_container"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -4,41 +4,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ToggleButton
android:id="@+id/tbMainNet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:textOff="@string/connect_testnet"
android:textOn="@string/connect_mainnet"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.m2049r.xmrwallet.layout.InstantAutoComplete
android:id="@+id/etDaemonAddress"
style="@style/MoneroEdit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:hint="@string/prompt_daemon"
android:imeOptions="actionDone"
android:inputType="textWebEmailAddress|textNoSuggestions"
android:maxLines="1"
android:textIsSelectable="true"
app:layout_constraintBaseline_toBaselineOf="@+id/tbMainNet"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tbMainNet" />
</android.support.constraint.ConstraintLayout>
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

View File

@ -2,10 +2,17 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_testnet"
android:checkable="true"
android:orderInCategory="100"
android:title="@string/menu_testnet"
app:showAsAction="never" />
<item <item
android:id="@+id/action_lincense_info" android:id="@+id/action_lincense_info"
android:icon="@drawable/ic_info_black_24dp" android:icon="@drawable/ic_info_black_24dp"
android:orderInCategory="100" android:orderInCategory="200"
android:title="@string/menu_about" android:title="@string/menu_about"
app:showAsAction="never" /> app:showAsAction="never" />

View File

@ -3,6 +3,7 @@
<string name="login_activity_name">Monerujo</string> <string name="login_activity_name">Monerujo</string>
<string name="wallet_activity_name">Wallet</string> <string name="wallet_activity_name">Wallet</string>
<string name="menu_testnet">Testnet</string>
<string name="menu_about">About &#8230;</string> <string name="menu_about">About &#8230;</string>
<string name="menu_info">Details</string> <string name="menu_info">Details</string>