diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java index e2e8d921..4adaac8d 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java @@ -43,8 +43,10 @@ import android.widget.TextView; import android.widget.Toast; import android.widget.ToggleButton; +import com.m2049r.xmrwallet.layout.InstantAutoComplete; import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.util.Helper; +import com.m2049r.xmrwallet.util.NodeList; import java.io.File; import java.io.IOException; @@ -74,7 +76,9 @@ public class LoginFragment extends Fragment { List displayedList = new ArrayList<>(); ToggleButton tbMainNet; - EditText etDaemonAddress; + InstantAutoComplete etDaemonAddress; + ArrayAdapter nodeAdapter; + FloatingActionButton fabAdd; Listener activityCallback; @@ -139,8 +143,9 @@ public class LoginFragment extends Fragment { View view = inflater.inflate(R.layout.login_fragment, container, false); tbMainNet = (ToggleButton) view.findViewById(R.id.tbMainNet); - etDaemonAddress = (EditText) view.findViewById(R.id.etDaemonAddress); - + etDaemonAddress = (InstantAutoComplete) view.findViewById(R.id.etDaemonAddress); + nodeAdapter = new ArrayAdapter(getContext(), android.R.layout.simple_dropdown_item_1line); + etDaemonAddress.setAdapter(nodeAdapter); fabAdd = (FloatingActionButton) view.findViewById(R.id.fabAdd); fabAdd.setOnClickListener(new View.OnClickListener() { @@ -281,23 +286,34 @@ public class LoginFragment extends Fragment { return etDaemonAddress.getText().toString(); } - void setDaemon(String address) { - etDaemonAddress.setText(address); + 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 String daemonTestNet; - private String daemonMainNet; + 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 = sharedPref.getString(PREF_DAEMON_MAINNET, ""); - daemonTestNet = sharedPref.getString(PREF_DAEMON_TESTNET, ""); + daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET)); + daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, "")); setMainNet(mainnet); if (mainnet) { @@ -316,16 +332,16 @@ public class LoginFragment extends Fragment { boolean mainnet = isMainNet() ^ usePreviousState; String daemon = getDaemon(); if (mainnet) { - daemonMainNet = daemon; + daemonMainNet.setRecent(daemon); } else { - daemonTestNet = daemon; + daemonTestNet.setRecent(daemon); } SharedPreferences sharedPref = activityCallback.getPrefs(); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(PREF_MAINNET, mainnet); - editor.putString(PREF_DAEMON_MAINNET, daemonMainNet); - editor.putString(PREF_DAEMON_TESTNET, daemonTestNet); + editor.putString(PREF_DAEMON_MAINNET, daemonMainNet.toString()); + editor.putString(PREF_DAEMON_TESTNET, daemonTestNet.toString()); editor.apply(); } diff --git a/app/src/main/java/com/m2049r/xmrwallet/layout/InstantAutoComplete.java b/app/src/main/java/com/m2049r/xmrwallet/layout/InstantAutoComplete.java new file mode 100644 index 00000000..a48f6d6f --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/layout/InstantAutoComplete.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 m2049r + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// https://stackoverflow.com/questions/2126717/android-autocompletetextview-show-suggestions-when-no-text-entered + +package com.m2049r.xmrwallet.layout; + +import android.content.Context; +import android.graphics.Rect; +import android.support.v7.widget.AppCompatAutoCompleteTextView; +import android.util.AttributeSet; + +public class InstantAutoComplete extends AppCompatAutoCompleteTextView { + + public InstantAutoComplete(Context context) { + super(context); + } + + public InstantAutoComplete(Context arg0, AttributeSet arg1) { + super(arg0, arg1); + } + + public InstantAutoComplete(Context arg0, AttributeSet arg1, int arg2) { + super(arg0, arg1, arg2); + } + + @Override + public boolean enoughToFilter() { + return true; + } + + @Override + protected void onFocusChanged(boolean focused, int direction, + Rect previouslyFocusedRect) { + super.onFocusChanged(focused, direction, previouslyFocusedRect); + if (focused && getAdapter() != null) { + performFiltering(getText(), 0); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/NodeList.java b/app/src/main/java/com/m2049r/xmrwallet/util/NodeList.java new file mode 100644 index 00000000..f036a6aa --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/util/NodeList.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017 m2049r + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.m2049r.xmrwallet.util; + +import android.util.Log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class NodeList { + static private final String TAG = "NodeList"; + static public final int MAX_SIZE = 5; + + List nodes = new ArrayList<>(); + + public List getNodes() { + return nodes; + } + + public void setRecent(String aNode) { + if (aNode.trim().isEmpty()) return; + boolean found = false; + for (int i = 0; i < nodes.size(); i++) { + if (nodes.get(i).equals(aNode)) { // node is already in the list => move it to top + nodes.remove(i); + found = true; + break; + } + } + if (!found) { + if (nodes.size() > MAX_SIZE) { + nodes.remove(nodes.size() - 1); // drop last one + } + } + nodes.add(0, aNode); + } + + public NodeList(String aString) { + String[] newNodes = aString.split(";"); + nodes.addAll(Arrays.asList(newNodes)); + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for (String node : this.nodes) { + sb.append(node).append(";"); + } + return sb.toString(); + } +} diff --git a/app/src/main/res/layout/login_fragment.xml b/app/src/main/res/layout/login_fragment.xml index 3a88477a..f1901bdf 100644 --- a/app/src/main/res/layout/login_fragment.xml +++ b/app/src/main/res/layout/login_fragment.xml @@ -19,7 +19,7 @@ app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> -