mirror of
https://codeberg.org/anoncontributorxmr/mysu.git
synced 2024-11-25 17:02:28 +00:00
0.5.3: Better synchronization/status
This commit is contained in:
parent
cab3a0d79f
commit
0a9d774f18
21 changed files with 349 additions and 197 deletions
|
@ -10,8 +10,8 @@ android {
|
||||||
applicationId "net.mynero.wallet"
|
applicationId "net.mynero.wallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 50200
|
versionCode 50300
|
||||||
versionName "0.5.2 'Fluorine Fermi'"
|
versionName "0.5.3 'Fluorine Fermi'"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
|
|
@ -920,11 +920,25 @@ Java_net_mynero_wallet_model_Wallet_getConnectionStatusJ(JNIEnv *env, jobject in
|
||||||
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
||||||
return wallet->connected();
|
return wallet->connected();
|
||||||
}
|
}
|
||||||
//TODO virtual void setTrustedDaemon(bool arg) = 0;
|
JNIEXPORT void JNICALL
|
||||||
|
Java_net_mynero_wallet_model_Wallet_setTrustedDaemonJ(JNIEnv *env, jobject instance, jboolean trusted) {
|
||||||
|
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
||||||
|
if (trusted) {
|
||||||
|
wallet->setTrustedDaemon(true);
|
||||||
|
} else {
|
||||||
|
wallet->setTrustedDaemon(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_net_mynero_wallet_model_Wallet_isTrustedDaemonJ(JNIEnv *env, jobject instance) {
|
||||||
|
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
||||||
|
bool td = wallet->trustedDaemon();
|
||||||
|
return td;
|
||||||
|
}
|
||||||
//TODO virtual bool trustedDaemon() const = 0;
|
//TODO virtual bool trustedDaemon() const = 0;
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_net_mynero_wallet_model_Wallet_setProxy(JNIEnv *env, jobject instance,
|
Java_net_mynero_wallet_model_Wallet_setProxyJ(JNIEnv *env, jobject instance,
|
||||||
jstring address) {
|
jstring address) {
|
||||||
const char *_address = env->GetStringUTFChars(address, nullptr);
|
const char *_address = env->GetStringUTFChars(address, nullptr);
|
||||||
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
||||||
|
|
|
@ -4,7 +4,11 @@ import android.os.Bundle
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import net.mynero.wallet.fragment.dialog.PasswordBottomSheetDialog
|
import net.mynero.wallet.fragment.dialog.PasswordBottomSheetDialog
|
||||||
import net.mynero.wallet.fragment.dialog.PasswordBottomSheetDialog.PasswordListener
|
import net.mynero.wallet.fragment.dialog.PasswordBottomSheetDialog.PasswordListener
|
||||||
import net.mynero.wallet.fragment.dialog.SendBottomSheetDialog
|
import net.mynero.wallet.fragment.dialog.SendBottomSheetDialog
|
||||||
|
@ -13,13 +17,16 @@ import net.mynero.wallet.model.WalletManager
|
||||||
import net.mynero.wallet.service.AddressService
|
import net.mynero.wallet.service.AddressService
|
||||||
import net.mynero.wallet.service.BalanceService
|
import net.mynero.wallet.service.BalanceService
|
||||||
import net.mynero.wallet.service.BlockchainService
|
import net.mynero.wallet.service.BlockchainService
|
||||||
|
import net.mynero.wallet.service.DaemonService
|
||||||
import net.mynero.wallet.service.HistoryService
|
import net.mynero.wallet.service.HistoryService
|
||||||
import net.mynero.wallet.service.MoneroHandlerThread
|
import net.mynero.wallet.service.MoneroHandlerThread
|
||||||
import net.mynero.wallet.service.PrefService
|
import net.mynero.wallet.service.PrefService
|
||||||
|
import net.mynero.wallet.service.ProxyService
|
||||||
import net.mynero.wallet.service.TxService
|
import net.mynero.wallet.service.TxService
|
||||||
import net.mynero.wallet.service.UTXOService
|
import net.mynero.wallet.service.UTXOService
|
||||||
import net.mynero.wallet.util.Constants
|
import net.mynero.wallet.util.Constants
|
||||||
import net.mynero.wallet.util.UriData
|
import net.mynero.wallet.util.UriData
|
||||||
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(), MoneroHandlerThread.Listener, PasswordListener {
|
class MainActivity : AppCompatActivity(), MoneroHandlerThread.Listener, PasswordListener {
|
||||||
|
@ -29,6 +36,8 @@ class MainActivity : AppCompatActivity(), MoneroHandlerThread.Listener, Password
|
||||||
private var balanceService: BalanceService? = null
|
private var balanceService: BalanceService? = null
|
||||||
private var addressService: AddressService? = null
|
private var addressService: AddressService? = null
|
||||||
private var historyService: HistoryService? = null
|
private var historyService: HistoryService? = null
|
||||||
|
private var proxyService: ProxyService? = null
|
||||||
|
private var daemonService: DaemonService? = null
|
||||||
private var blockchainService: BlockchainService? = null
|
private var blockchainService: BlockchainService? = null
|
||||||
private var utxoService: UTXOService? = null
|
private var utxoService: UTXOService? = null
|
||||||
private var proceedToSend = false
|
private var proceedToSend = false
|
||||||
|
@ -77,6 +86,8 @@ class MainActivity : AppCompatActivity(), MoneroHandlerThread.Listener, Password
|
||||||
addressService = AddressService(thread)
|
addressService = AddressService(thread)
|
||||||
historyService = HistoryService(thread)
|
historyService = HistoryService(thread)
|
||||||
blockchainService = BlockchainService(thread)
|
blockchainService = BlockchainService(thread)
|
||||||
|
daemonService = DaemonService(thread)
|
||||||
|
proxyService = ProxyService(thread)
|
||||||
utxoService = UTXOService(thread)
|
utxoService = UTXOService(thread)
|
||||||
thread.start()
|
thread.start()
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,8 @@ class Node {
|
||||||
private set
|
private set
|
||||||
var password = ""
|
var password = ""
|
||||||
private set
|
private set
|
||||||
private var favourite = false
|
var trusted = false
|
||||||
|
private set
|
||||||
|
|
||||||
internal constructor(nodeString: String?) {
|
internal constructor(nodeString: String?) {
|
||||||
require(!nodeString.isNullOrEmpty()) { "daemon is empty" }
|
require(!nodeString.isNullOrEmpty()) { "daemon is empty" }
|
||||||
|
@ -142,6 +143,9 @@ class Node {
|
||||||
}
|
}
|
||||||
require(networkType == WalletManager.instance?.networkType) { "wrong net: $networkType" }
|
require(networkType == WalletManager.instance?.networkType) { "wrong net: $networkType" }
|
||||||
}
|
}
|
||||||
|
if (jsonObject.has("trusted")) {
|
||||||
|
this.trusted = jsonObject.getBoolean("trusted")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -197,6 +201,7 @@ class Node {
|
||||||
null -> TODO()
|
null -> TODO()
|
||||||
}
|
}
|
||||||
if (name?.isNotEmpty() == true) jsonObject.put("name", name)
|
if (name?.isNotEmpty() == true) jsonObject.put("name", name)
|
||||||
|
jsonObject.put("trusted", trusted)
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
throw RuntimeException(e)
|
throw RuntimeException(e)
|
||||||
}
|
}
|
||||||
|
@ -235,7 +240,7 @@ class Node {
|
||||||
levinPort = anotherNode.levinPort
|
levinPort = anotherNode.levinPort
|
||||||
username = anotherNode.username
|
username = anotherNode.username
|
||||||
password = anotherNode.password
|
password = anotherNode.password
|
||||||
favourite = anotherNode.favourite
|
trusted = anotherNode.trusted
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
import android.widget.CheckBox
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
@ -38,6 +39,8 @@ class AddNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
val nodeNameEditText = view.findViewById<EditText>(R.id.node_name_edittext)
|
val nodeNameEditText = view.findViewById<EditText>(R.id.node_name_edittext)
|
||||||
val usernameEditText = view.findViewById<EditText>(R.id.username_edittext)
|
val usernameEditText = view.findViewById<EditText>(R.id.username_edittext)
|
||||||
val passwordEditText = view.findViewById<EditText>(R.id.password_edittext)
|
val passwordEditText = view.findViewById<EditText>(R.id.password_edittext)
|
||||||
|
val trustedDaemonCheckbox = view.findViewById<CheckBox>(R.id.trusted_node_checkbox)
|
||||||
|
|
||||||
val pastePasswordImageButton =
|
val pastePasswordImageButton =
|
||||||
view.findViewById<ImageButton>(R.id.paste_password_imagebutton)
|
view.findViewById<ImageButton>(R.id.paste_password_imagebutton)
|
||||||
usernameEditText.addTextChangedListener(object : TextWatcher {
|
usernameEditText.addTextChangedListener(object : TextWatcher {
|
||||||
|
@ -63,6 +66,8 @@ class AddNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
val name = nodeNameEditText.text.toString()
|
val name = nodeNameEditText.text.toString()
|
||||||
val user = usernameEditText.text.toString()
|
val user = usernameEditText.text.toString()
|
||||||
val pass = passwordEditText.text.toString()
|
val pass = passwordEditText.text.toString()
|
||||||
|
val trusted = trustedDaemonCheckbox.isChecked
|
||||||
|
|
||||||
if (name.isEmpty()) {
|
if (name.isEmpty()) {
|
||||||
Toast.makeText(context, "Enter node name", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Enter node name", Toast.LENGTH_SHORT).show()
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
|
@ -85,6 +90,7 @@ class AddNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
jsonObject.put("rpcPort", portString.toInt())
|
jsonObject.put("rpcPort", portString.toInt())
|
||||||
jsonObject.put("network", "mainnet")
|
jsonObject.put("network", "mainnet")
|
||||||
jsonObject.put("name", name)
|
jsonObject.put("name", name)
|
||||||
|
jsonObject.put("trusted", trusted)
|
||||||
addNodeToSaved(jsonObject)
|
addNodeToSaved(jsonObject)
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener?.onNodeAdded()
|
listener?.onNodeAdded()
|
||||||
|
|
|
@ -7,6 +7,7 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
import android.widget.CheckBox
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
@ -39,6 +40,7 @@ class EditNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
val nodeNameEditText = view.findViewById<EditText>(R.id.node_name_edittext)
|
val nodeNameEditText = view.findViewById<EditText>(R.id.node_name_edittext)
|
||||||
val usernameEditText = view.findViewById<EditText>(R.id.username_edittext)
|
val usernameEditText = view.findViewById<EditText>(R.id.username_edittext)
|
||||||
val passwordEditText = view.findViewById<EditText>(R.id.password_edittext)
|
val passwordEditText = view.findViewById<EditText>(R.id.password_edittext)
|
||||||
|
val trustedDaemonCheckBox = view.findViewById<CheckBox>(R.id.trusted_node_checkbox)
|
||||||
val pastePasswordImageButton =
|
val pastePasswordImageButton =
|
||||||
view.findViewById<ImageButton>(R.id.paste_password_imagebutton)
|
view.findViewById<ImageButton>(R.id.paste_password_imagebutton)
|
||||||
if (node == null) return
|
if (node == null) return
|
||||||
|
@ -46,6 +48,7 @@ class EditNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
portEditText.setText("${node?.rpcPort}")
|
portEditText.setText("${node?.rpcPort}")
|
||||||
nodeNameEditText.setText(node?.name)
|
nodeNameEditText.setText(node?.name)
|
||||||
usernameEditText.setText(node?.username)
|
usernameEditText.setText(node?.username)
|
||||||
|
trustedDaemonCheckBox.isChecked = node?.trusted ?: false
|
||||||
if (node?.password?.isNotEmpty() == true) {
|
if (node?.password?.isNotEmpty() == true) {
|
||||||
passwordEditText.setText(node?.password)
|
passwordEditText.setText(node?.password)
|
||||||
passwordEditText.visibility = View.VISIBLE
|
passwordEditText.visibility = View.VISIBLE
|
||||||
|
@ -78,6 +81,7 @@ class EditNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
val nodeName = nodeNameEditText.text.toString()
|
val nodeName = nodeNameEditText.text.toString()
|
||||||
val user = usernameEditText.text.toString()
|
val user = usernameEditText.text.toString()
|
||||||
val pass = passwordEditText.text.toString()
|
val pass = passwordEditText.text.toString()
|
||||||
|
val trusted = trustedDaemonCheckBox.isChecked
|
||||||
if (nodeName.isEmpty()) {
|
if (nodeName.isEmpty()) {
|
||||||
Toast.makeText(context, "Enter node name", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Enter node name", Toast.LENGTH_SHORT).show()
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
|
@ -101,6 +105,7 @@ class EditNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
jsonObject.put("rpcPort", portString.toInt())
|
jsonObject.put("rpcPort", portString.toInt())
|
||||||
jsonObject.put("network", "mainnet")
|
jsonObject.put("network", "mainnet")
|
||||||
jsonObject.put("name", nodeName)
|
jsonObject.put("name", nodeName)
|
||||||
|
jsonObject.put("trusted", trusted)
|
||||||
listener?.onNodeEdited(node, fromJson(jsonObject))
|
listener?.onNodeEdited(node, fromJson(jsonObject))
|
||||||
dismiss()
|
dismiss()
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
|
|
|
@ -7,9 +7,12 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import net.mynero.wallet.R
|
import net.mynero.wallet.R
|
||||||
import net.mynero.wallet.adapter.NodeSelectionAdapter
|
import net.mynero.wallet.adapter.NodeSelectionAdapter
|
||||||
import net.mynero.wallet.adapter.NodeSelectionAdapter.NodeSelectionAdapterListener
|
import net.mynero.wallet.adapter.NodeSelectionAdapter.NodeSelectionAdapterListener
|
||||||
|
@ -18,6 +21,7 @@ import net.mynero.wallet.data.Node
|
||||||
import net.mynero.wallet.data.Node.Companion.fromJson
|
import net.mynero.wallet.data.Node.Companion.fromJson
|
||||||
import net.mynero.wallet.data.Node.Companion.fromString
|
import net.mynero.wallet.data.Node.Companion.fromString
|
||||||
import net.mynero.wallet.model.WalletManager
|
import net.mynero.wallet.model.WalletManager
|
||||||
|
import net.mynero.wallet.service.DaemonService
|
||||||
import net.mynero.wallet.service.PrefService
|
import net.mynero.wallet.service.PrefService
|
||||||
import net.mynero.wallet.util.Constants
|
import net.mynero.wallet.util.Constants
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
|
@ -90,18 +94,12 @@ class NodeSelectionBottomSheetDialog : BottomSheetDialogFragment(), NodeSelectio
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSelectNode(node: Node?) {
|
override fun onSelectNode(node: Node?) {
|
||||||
val activity: Activity? = activity
|
|
||||||
activity?.runOnUiThread {
|
|
||||||
Toast.makeText(
|
|
||||||
activity,
|
|
||||||
getString(R.string.node_selected),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
PrefService.instance?.edit()?.putString(Constants.PREF_NODE_2, node?.toJson().toString())
|
PrefService.instance?.edit()?.putString(Constants.PREF_NODE_2, node?.toJson().toString())
|
||||||
?.apply()
|
?.apply()
|
||||||
WalletManager.instance?.setDaemon(node)
|
node?.let { DaemonService.instance?.setDaemon(it) }
|
||||||
|
activity?.runOnUiThread {
|
||||||
adapter?.updateSelectedNode()
|
adapter?.updateSelectedNode()
|
||||||
|
}
|
||||||
listener?.onNodeSelected()
|
listener?.onNodeSelected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,16 @@ import android.widget.Button
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import net.mynero.wallet.MainActivity
|
import net.mynero.wallet.MainActivity
|
||||||
import net.mynero.wallet.R
|
import net.mynero.wallet.R
|
||||||
import net.mynero.wallet.adapter.TransactionInfoAdapter
|
import net.mynero.wallet.adapter.TransactionInfoAdapter
|
||||||
|
@ -22,9 +26,12 @@ import net.mynero.wallet.model.TransactionInfo
|
||||||
import net.mynero.wallet.model.WalletManager
|
import net.mynero.wallet.model.WalletManager
|
||||||
import net.mynero.wallet.service.BalanceService
|
import net.mynero.wallet.service.BalanceService
|
||||||
import net.mynero.wallet.service.BlockchainService
|
import net.mynero.wallet.service.BlockchainService
|
||||||
|
import net.mynero.wallet.service.DaemonService
|
||||||
import net.mynero.wallet.service.HistoryService
|
import net.mynero.wallet.service.HistoryService
|
||||||
import net.mynero.wallet.service.PrefService
|
import net.mynero.wallet.service.PrefService
|
||||||
|
import net.mynero.wallet.service.ProxyService
|
||||||
import net.mynero.wallet.util.Constants
|
import net.mynero.wallet.util.Constants
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
class HomeFragment : Fragment(), TxInfoAdapterListener {
|
class HomeFragment : Fragment(), TxInfoAdapterListener {
|
||||||
private var startHeight: Long = 0
|
private var startHeight: Long = 0
|
||||||
|
@ -66,6 +73,26 @@ class HomeFragment : Fragment(), TxInfoAdapterListener {
|
||||||
val historyService = HistoryService.instance
|
val historyService = HistoryService.instance
|
||||||
val blockchainService = BlockchainService.instance
|
val blockchainService = BlockchainService.instance
|
||||||
|
|
||||||
|
ProxyService.instance?.proxyChangeEvents?.observe(viewLifecycleOwner) { proxy ->
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
Timber.d("Updating proxy:: $proxy")
|
||||||
|
WalletManager.instance?.setProxy(proxy)
|
||||||
|
WalletManager.instance?.wallet?.setProxy(proxy)
|
||||||
|
WalletManager.instance?.wallet?.init(0)
|
||||||
|
WalletManager.instance?.wallet?.startRefresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DaemonService.instance?.daemonChangeEvents?.observe(viewLifecycleOwner) { daemon ->
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
Timber.d("Updating daemon:: $daemon")
|
||||||
|
WalletManager.instance?.setDaemon(daemon)
|
||||||
|
WalletManager.instance?.wallet?.setTrustedDaemon(daemon.trusted)
|
||||||
|
WalletManager.instance?.wallet?.init(0)
|
||||||
|
WalletManager.instance?.wallet?.startRefresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
balanceService?.balanceInfo?.observe(viewLifecycleOwner) { balanceInfo ->
|
balanceService?.balanceInfo?.observe(viewLifecycleOwner) { balanceInfo ->
|
||||||
if (balanceInfo != null) {
|
if (balanceInfo != null) {
|
||||||
unlockedBalanceTextView.text = balanceInfo.unlockedDisplay
|
unlockedBalanceTextView.text = balanceInfo.unlockedDisplay
|
||||||
|
@ -101,7 +128,8 @@ class HomeFragment : Fragment(), TxInfoAdapterListener {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
progressBar.visibility = View.INVISIBLE
|
progressBar.visibility = View.INVISIBLE
|
||||||
progressBarText.visibility = View.GONE
|
progressBarText.visibility = View.VISIBLE
|
||||||
|
progressBarText.text = "Synchronized"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val adapter = TransactionInfoAdapter(this)
|
val adapter = TransactionInfoAdapter(this)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.widget.CompoundButton
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.appcompat.widget.SwitchCompat
|
import androidx.appcompat.widget.SwitchCompat
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
@ -28,6 +29,7 @@ import net.mynero.wallet.fragment.dialog.NodeSelectionBottomSheetDialog
|
||||||
import net.mynero.wallet.fragment.dialog.NodeSelectionBottomSheetDialog.NodeSelectionDialogListener
|
import net.mynero.wallet.fragment.dialog.NodeSelectionBottomSheetDialog.NodeSelectionDialogListener
|
||||||
import net.mynero.wallet.fragment.onboarding.OnboardingViewModel.SeedType
|
import net.mynero.wallet.fragment.onboarding.OnboardingViewModel.SeedType
|
||||||
import net.mynero.wallet.service.PrefService
|
import net.mynero.wallet.service.PrefService
|
||||||
|
import net.mynero.wallet.service.ProxyService
|
||||||
import net.mynero.wallet.util.Constants
|
import net.mynero.wallet.util.Constants
|
||||||
|
|
||||||
class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListener {
|
class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListener {
|
||||||
|
@ -186,11 +188,11 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
||||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USES_TOR, b)?.apply()
|
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USES_TOR, b)?.apply()
|
||||||
removeProxyTextListeners()
|
removeProxyTextListeners()
|
||||||
if (b) {
|
if (b) {
|
||||||
if (PrefService.instance?.hasProxySet() == true) {
|
if (ProxyService.instance?.hasProxySet() == true) {
|
||||||
val proxyAddress =
|
val proxyAddress =
|
||||||
PrefService.instance?.proxyAddress ?: return@setOnCheckedChangeListener
|
ProxyService.instance?.proxyAddress ?: return@setOnCheckedChangeListener
|
||||||
val proxyPort =
|
val proxyPort =
|
||||||
PrefService.instance?.proxyPort ?: return@setOnCheckedChangeListener
|
ProxyService.instance?.proxyPort ?: return@setOnCheckedChangeListener
|
||||||
initProxyStuff(proxyAddress, proxyPort)
|
initProxyStuff(proxyAddress, proxyPort)
|
||||||
} else {
|
} else {
|
||||||
initProxyStuff("127.0.0.1", "9050")
|
initProxyStuff("127.0.0.1", "9050")
|
||||||
|
@ -277,6 +279,11 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
||||||
override fun onNodeSelected() {
|
override fun onNodeSelected() {
|
||||||
val node = PrefService.instance?.node
|
val node = PrefService.instance?.node
|
||||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||||
|
Toast.makeText(
|
||||||
|
activity,
|
||||||
|
getString(R.string.node_selected),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
mViewModel?.updateProxy(activity?.application as MoneroApplication)
|
mViewModel?.updateProxy(activity?.application as MoneroApplication)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package net.mynero.wallet.fragment.settings
|
package net.mynero.wallet.fragment.settings
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -12,12 +10,17 @@ import android.widget.CompoundButton
|
||||||
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 androidx.activity.OnBackPressedCallback
|
||||||
import androidx.appcompat.widget.SwitchCompat
|
import androidx.appcompat.widget.SwitchCompat
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import net.mynero.wallet.MoneroApplication
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import net.mynero.wallet.R
|
import net.mynero.wallet.R
|
||||||
import net.mynero.wallet.data.Node
|
import net.mynero.wallet.data.Node
|
||||||
import net.mynero.wallet.data.Node.Companion.fromJson
|
import net.mynero.wallet.data.Node.Companion.fromJson
|
||||||
|
@ -34,37 +37,23 @@ import net.mynero.wallet.model.Wallet.ConnectionStatus
|
||||||
import net.mynero.wallet.model.WalletManager
|
import net.mynero.wallet.model.WalletManager
|
||||||
import net.mynero.wallet.service.BalanceService
|
import net.mynero.wallet.service.BalanceService
|
||||||
import net.mynero.wallet.service.BlockchainService
|
import net.mynero.wallet.service.BlockchainService
|
||||||
|
import net.mynero.wallet.service.DaemonService
|
||||||
import net.mynero.wallet.service.HistoryService
|
import net.mynero.wallet.service.HistoryService
|
||||||
import net.mynero.wallet.service.PrefService
|
import net.mynero.wallet.service.PrefService
|
||||||
|
import net.mynero.wallet.service.ProxyService
|
||||||
import net.mynero.wallet.util.Constants
|
import net.mynero.wallet.util.Constants
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListener, AddNodeListener,
|
class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListener, AddNodeListener,
|
||||||
EditNodeListener {
|
EditNodeListener {
|
||||||
private var mViewModel: SettingsViewModel? = null
|
private var mViewModel: SettingsViewModel? = null
|
||||||
private var proxyAddressListener: TextWatcher = object : TextWatcher {
|
|
||||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
|
||||||
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
|
||||||
override fun afterTextChanged(editable: Editable) {
|
|
||||||
if (mViewModel != null) {
|
|
||||||
mViewModel?.setProxyAddress(editable.toString())
|
|
||||||
mViewModel?.updateProxy(activity?.application as MoneroApplication)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private var proxyPortListener: TextWatcher = object : TextWatcher {
|
|
||||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
|
||||||
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
|
||||||
override fun afterTextChanged(editable: Editable) {
|
|
||||||
if (mViewModel != null) {
|
|
||||||
mViewModel?.setProxyPort(editable.toString())
|
|
||||||
mViewModel?.updateProxy(activity?.application as MoneroApplication)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private var walletProxyAddressEditText: EditText? = null
|
private var walletProxyAddressEditText: EditText? = null
|
||||||
private var walletProxyPortEditText: EditText? = null
|
private var walletProxyPortEditText: EditText? = null
|
||||||
private var selectNodeButton: Button? = null
|
private var selectNodeButton: Button? = null
|
||||||
|
private var cachedProxyAddress: String = ""
|
||||||
|
private var cachedProxyPort: String = ""
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
|
@ -103,12 +92,12 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
||||||
donationSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
donationSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_DONATE_PER_TX, b)?.apply()
|
PrefService.instance?.edit()?.putBoolean(Constants.PREF_DONATE_PER_TX, b)?.apply()
|
||||||
}
|
}
|
||||||
val prefService = PrefService.instance
|
val prefService = PrefService.instance ?: return
|
||||||
val usesProxy = prefService?.getBoolean(Constants.PREF_USES_TOR, false) == true
|
val usesProxy = prefService.getBoolean(Constants.PREF_USES_TOR, false)
|
||||||
if (prefService?.hasProxySet() == true) {
|
cachedProxyAddress = ProxyService.instance?.proxyAddress ?: return
|
||||||
val proxyAddress = prefService.proxyAddress
|
cachedProxyPort = ProxyService.instance?.proxyPort ?: return
|
||||||
val proxyPort = prefService.proxyPort
|
if (ProxyService.instance?.hasProxySet() == true) {
|
||||||
initProxyStuff(proxyAddress, proxyPort)
|
initProxyStuff(cachedProxyAddress, cachedProxyPort)
|
||||||
}
|
}
|
||||||
torSwitch.isChecked = usesProxy
|
torSwitch.isChecked = usesProxy
|
||||||
if (usesProxy) {
|
if (usesProxy) {
|
||||||
|
@ -116,22 +105,19 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
||||||
} else {
|
} else {
|
||||||
proxySettingsLayout.visibility = View.GONE
|
proxySettingsLayout.visibility = View.GONE
|
||||||
}
|
}
|
||||||
addProxyTextListeners()
|
|
||||||
torSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
torSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||||
prefService?.edit()?.putBoolean(Constants.PREF_USES_TOR, b)?.apply()
|
prefService.edit()?.putBoolean(Constants.PREF_USES_TOR, b)?.apply()
|
||||||
if (b) {
|
if (b) {
|
||||||
if (prefService?.hasProxySet() == true) {
|
if (ProxyService.instance?.hasProxySet() == true) {
|
||||||
removeProxyTextListeners()
|
val proxyAddress = ProxyService.instance?.proxyAddress ?: return@setOnCheckedChangeListener
|
||||||
val proxyAddress = prefService.proxyAddress
|
val proxyPort = ProxyService.instance?.proxyPort ?: return@setOnCheckedChangeListener
|
||||||
val proxyPort = prefService.proxyPort
|
|
||||||
initProxyStuff(proxyAddress, proxyPort)
|
initProxyStuff(proxyAddress, proxyPort)
|
||||||
addProxyTextListeners()
|
|
||||||
}
|
}
|
||||||
proxySettingsLayout.visibility = View.VISIBLE
|
proxySettingsLayout.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
proxySettingsLayout.visibility = View.GONE
|
proxySettingsLayout.visibility = View.GONE
|
||||||
}
|
}
|
||||||
mViewModel?.updateProxy(activity?.application as MoneroApplication)
|
refreshProxy()
|
||||||
}
|
}
|
||||||
displaySeedButton.setOnClickListener {
|
displaySeedButton.setOnClickListener {
|
||||||
val usesPassword =
|
val usesPassword =
|
||||||
|
@ -148,16 +134,6 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
displayUtxosButton.setOnClickListener { navigate(R.id.nav_to_utxos) }
|
displayUtxosButton.setOnClickListener { navigate(R.id.nav_to_utxos) }
|
||||||
val statusTextView = view.findViewById<TextView>(R.id.status_textview)
|
|
||||||
BlockchainService.instance?.connectionStatus?.observe(viewLifecycleOwner) { connectionStatus: ConnectionStatus ->
|
|
||||||
if (connectionStatus === ConnectionStatus.ConnectionStatus_Connected) {
|
|
||||||
statusTextView.text = resources.getText(R.string.connected)
|
|
||||||
} else if (connectionStatus === ConnectionStatus.ConnectionStatus_Disconnected) {
|
|
||||||
statusTextView.text = resources.getText(R.string.disconnected)
|
|
||||||
} else if (connectionStatus === ConnectionStatus.ConnectionStatus_WrongVersion) {
|
|
||||||
statusTextView.text = resources.getText(R.string.version_mismatch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val node = PrefService.instance?.node // shouldn't use default value here
|
val node = PrefService.instance?.node // shouldn't use default value here
|
||||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||||
selectNodeButton?.setOnClickListener {
|
selectNodeButton?.setOnClickListener {
|
||||||
|
@ -167,6 +143,25 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
||||||
dialog.show(fragmentManager, "node_selection_dialog")
|
dialog.show(fragmentManager, "node_selection_dialog")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val onBackPressedCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
refreshProxy()
|
||||||
|
findNavController().popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, onBackPressedCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshProxy() {
|
||||||
|
val proxyAddress = walletProxyAddressEditText?.text.toString()
|
||||||
|
val proxyPort = walletProxyPortEditText?.text.toString()
|
||||||
|
if((proxyAddress != cachedProxyAddress) || (proxyPort != cachedProxyPort)) {
|
||||||
|
ProxyService.instance?.updateProxy(proxyAddress, proxyPort)
|
||||||
|
cachedProxyAddress = proxyAddress
|
||||||
|
cachedProxyPort = proxyPort
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun displaySeedDialog(password: String) {
|
private fun displaySeedDialog(password: String) {
|
||||||
|
@ -188,30 +183,22 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
||||||
private fun initProxyStuff(proxyAddress: String, proxyPort: String) {
|
private fun initProxyStuff(proxyAddress: String, proxyPort: String) {
|
||||||
val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
|
val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
|
||||||
if (validIpAddress) {
|
if (validIpAddress) {
|
||||||
mViewModel?.setProxyAddress(proxyAddress)
|
|
||||||
mViewModel?.setProxyPort(proxyPort)
|
|
||||||
walletProxyAddressEditText?.setText(proxyAddress)
|
walletProxyAddressEditText?.setText(proxyAddress)
|
||||||
walletProxyPortEditText?.setText(proxyPort)
|
walletProxyPortEditText?.setText(proxyPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeProxyTextListeners() {
|
|
||||||
walletProxyAddressEditText?.removeTextChangedListener(proxyAddressListener)
|
|
||||||
walletProxyPortEditText?.removeTextChangedListener(proxyPortListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addProxyTextListeners() {
|
|
||||||
walletProxyAddressEditText?.addTextChangedListener(proxyAddressListener)
|
|
||||||
walletProxyPortEditText?.addTextChangedListener(proxyPortListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNodeSelected() {
|
override fun onNodeSelected() {
|
||||||
val node = PrefService.instance?.node
|
val node = PrefService.instance?.node
|
||||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||||
mViewModel?.updateProxy(activity?.application as MoneroApplication)
|
refreshProxy()
|
||||||
(activity?.application as MoneroApplication).executor?.execute {
|
|
||||||
WalletManager.instance?.wallet?.init(0)
|
activity?.runOnUiThread {
|
||||||
WalletManager.instance?.wallet?.startRefresh()
|
Toast.makeText(
|
||||||
|
activity,
|
||||||
|
activity?.getString(R.string.node_selected, node?.name ?: node?.host),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,36 +8,5 @@ import net.mynero.wallet.service.PrefService
|
||||||
import net.mynero.wallet.util.Constants
|
import net.mynero.wallet.util.Constants
|
||||||
|
|
||||||
class SettingsViewModel : ViewModel() {
|
class SettingsViewModel : ViewModel() {
|
||||||
private var proxyAddress = ""
|
|
||||||
private var proxyPort = ""
|
|
||||||
fun updateProxy(application: MoneroApplication) {
|
|
||||||
application.executor?.execute {
|
|
||||||
val usesProxy = PrefService.instance?.getBoolean(Constants.PREF_USES_TOR, false) == true
|
|
||||||
val curretNode = PrefService.instance?.node
|
|
||||||
val isNodeLocalIp =
|
|
||||||
curretNode?.address?.startsWith("10.") == true || curretNode?.address?.startsWith("192.168.") == true || curretNode?.address == "localhost" || curretNode?.address == "127.0.0.1"
|
|
||||||
if (!usesProxy || isNodeLocalIp) {
|
|
||||||
WalletManager.instance?.setProxy("")
|
|
||||||
WalletManager.instance?.wallet?.setProxy("")
|
|
||||||
return@execute
|
|
||||||
}
|
|
||||||
if (proxyAddress.isEmpty()) proxyAddress = "127.0.0.1"
|
|
||||||
if (proxyPort.isEmpty()) proxyPort = "9050"
|
|
||||||
val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
|
|
||||||
if (validIpAddress) {
|
|
||||||
val proxy = "$proxyAddress:$proxyPort"
|
|
||||||
PrefService.instance?.edit()?.putString(Constants.PREF_PROXY, proxy)?.apply()
|
|
||||||
WalletManager.instance?.setProxy(proxy)
|
|
||||||
WalletManager.instance?.wallet?.setProxy(proxy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setProxyAddress(address: String) {
|
|
||||||
proxyAddress = address
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setProxyPort(port: String) {
|
|
||||||
proxyPort = port
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -57,6 +57,12 @@ class SingleLiveEvent<T> : MutableLiveData<T>() {
|
||||||
super.setValue(t)
|
super.setValue(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
override fun postValue(value: T) {
|
||||||
|
mPending.set(true)
|
||||||
|
super.postValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for cases where T is Void, to make calls cleaner.
|
* Used for cases where T is Void, to make calls cleaner.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -208,8 +208,20 @@ class Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
private external fun getConnectionStatusJ(): Int
|
private external fun getConnectionStatusJ(): Int
|
||||||
|
fun setTrustedDaemon(trusted: Boolean) {
|
||||||
|
setTrustedDaemonJ(trusted)
|
||||||
|
}
|
||||||
|
private external fun setTrustedDaemonJ(trusted: Boolean)
|
||||||
|
|
||||||
external fun setProxy(address: String?): Boolean
|
fun isTrustedDaemon(): Boolean {
|
||||||
|
return isTrustedDaemonJ();
|
||||||
|
}
|
||||||
|
private external fun isTrustedDaemonJ(): Boolean
|
||||||
|
|
||||||
|
fun setProxy(address: String?): Boolean {
|
||||||
|
return setProxyJ(address)
|
||||||
|
}
|
||||||
|
private external fun setProxyJ(address: String?): Boolean
|
||||||
val balance: Long
|
val balance: Long
|
||||||
get() = getBalance(accountIndex)
|
get() = getBalance(accountIndex)
|
||||||
|
|
||||||
|
|
27
app/src/main/java/net/mynero/wallet/service/DaemonService.kt
Normal file
27
app/src/main/java/net/mynero/wallet/service/DaemonService.kt
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package net.mynero.wallet.service
|
||||||
|
|
||||||
|
import android.util.Patterns
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import net.mynero.wallet.data.Node
|
||||||
|
import net.mynero.wallet.livedata.SingleLiveEvent
|
||||||
|
import net.mynero.wallet.model.WalletManager
|
||||||
|
import net.mynero.wallet.util.Constants
|
||||||
|
|
||||||
|
class DaemonService(thread: MoneroHandlerThread) : ServiceBase(thread) {
|
||||||
|
val daemonChangeEvents: SingleLiveEvent<Node> = SingleLiveEvent()
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
instance = this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setDaemon(daemon: Node) {
|
||||||
|
daemonChangeEvents.postValue(daemon)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var instance: DaemonService? = null
|
||||||
|
private set
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package net.mynero.wallet.service
|
package net.mynero.wallet.service
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import net.mynero.wallet.model.PendingTransaction
|
import net.mynero.wallet.model.PendingTransaction
|
||||||
import net.mynero.wallet.model.TransactionOutput
|
import net.mynero.wallet.model.TransactionOutput
|
||||||
import net.mynero.wallet.model.Wallet
|
import net.mynero.wallet.model.Wallet
|
||||||
|
@ -25,6 +26,7 @@ import net.mynero.wallet.model.Wallet.ConnectionStatus
|
||||||
import net.mynero.wallet.model.WalletListener
|
import net.mynero.wallet.model.WalletListener
|
||||||
import net.mynero.wallet.model.WalletManager
|
import net.mynero.wallet.model.WalletManager
|
||||||
import net.mynero.wallet.util.Constants
|
import net.mynero.wallet.util.Constants
|
||||||
|
import timber.log.Timber
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,11 +59,12 @@ class MoneroHandlerThread(name: String, val listener: Listener?, wallet: Wallet)
|
||||||
currentNode?.address == "localhost" ||
|
currentNode?.address == "localhost" ||
|
||||||
currentNode?.address == "127.0.0.1"
|
currentNode?.address == "127.0.0.1"
|
||||||
if (usesTor && !isLocalIp) {
|
if (usesTor && !isLocalIp) {
|
||||||
val proxy = prefService.proxy
|
val proxy = ProxyService.instance?.proxy
|
||||||
proxy?.let { WalletManager.instance?.setProxy(it) }
|
proxy?.let { WalletManager.instance?.setProxy(it) }
|
||||||
wallet.setProxy(proxy)
|
wallet.setProxy(proxy)
|
||||||
}
|
}
|
||||||
WalletManager.instance?.setDaemon(currentNode)
|
WalletManager.instance?.setDaemon(currentNode)
|
||||||
|
currentNode?.trusted?.let { wallet.setTrustedDaemon(it) }
|
||||||
wallet.init(0)
|
wallet.init(0)
|
||||||
wallet.setListener(this)
|
wallet.setListener(this)
|
||||||
wallet.startRefresh()
|
wallet.startRefresh()
|
||||||
|
@ -81,20 +84,36 @@ class MoneroHandlerThread(name: String, val listener: Listener?, wallet: Wallet)
|
||||||
|
|
||||||
override fun refreshed() {
|
override fun refreshed() {
|
||||||
val status = wallet.fullStatus.connectionStatus
|
val status = wallet.fullStatus.connectionStatus
|
||||||
|
val daemonHeight = wallet.getDaemonBlockChainHeight()
|
||||||
|
val chainHeight = wallet.getBlockChainHeight()
|
||||||
|
BlockchainService.instance?.daemonHeight = daemonHeight
|
||||||
|
status?.let { BlockchainService.instance?.setConnectionStatus(it) }
|
||||||
if (status === ConnectionStatus.ConnectionStatus_Disconnected || status == null) {
|
if (status === ConnectionStatus.ConnectionStatus_Disconnected || status == null) {
|
||||||
if (triesLeft > 0) {
|
tryRestartOrFail()
|
||||||
wallet.startRefresh()
|
|
||||||
triesLeft--
|
|
||||||
} else {
|
} else {
|
||||||
listener?.onConnectionFail()
|
val heightDiff = daemonHeight - chainHeight
|
||||||
}
|
if(heightDiff >= 2) {
|
||||||
|
tryRestartOrFail()
|
||||||
} else {
|
} else {
|
||||||
BlockchainService.instance?.daemonHeight = wallet.getDaemonBlockChainHeight()
|
Timber.d("refreshed() Synchronized")
|
||||||
wallet.setSynchronized()
|
wallet.setSynchronized()
|
||||||
wallet.store()
|
wallet.store()
|
||||||
refresh(true)
|
refresh(true)
|
||||||
}
|
}
|
||||||
status?.let { BlockchainService.instance?.setConnectionStatus(it) }
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryRestartOrFail() {
|
||||||
|
Timber.d("refreshed() Disconnected")
|
||||||
|
if (triesLeft > 0) {
|
||||||
|
Timber.d("refreshed() Starting refresh")
|
||||||
|
wallet.startRefresh()
|
||||||
|
triesLeft--
|
||||||
|
} else {
|
||||||
|
Timber.d("refreshed() On connection fail")
|
||||||
|
listener?.onConnectionFail()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refresh(walletSynced: Boolean) {
|
private fun refresh(walletSynced: Boolean) {
|
||||||
|
|
|
@ -29,8 +29,8 @@ class PrefService(application: MoneroApplication) : ServiceBase(null) {
|
||||||
val usesProxy = getBoolean(Constants.PREF_USES_TOR, false)
|
val usesProxy = getBoolean(Constants.PREF_USES_TOR, false)
|
||||||
var defaultNode = DefaultNodes.SAMOURAI
|
var defaultNode = DefaultNodes.SAMOURAI
|
||||||
if (usesProxy) {
|
if (usesProxy) {
|
||||||
val proxyPort = proxyPort
|
val proxyPort = ProxyService.instance?.proxyPort
|
||||||
if (proxyPort.isNotEmpty()) {
|
if (proxyPort?.isNotEmpty() == true) {
|
||||||
val port = proxyPort.toInt()
|
val port = proxyPort.toInt()
|
||||||
defaultNode = if (port == 4447) {
|
defaultNode = if (port == 4447) {
|
||||||
DefaultNodes.MYNERO_I2P
|
DefaultNodes.MYNERO_I2P
|
||||||
|
@ -60,35 +60,6 @@ class PrefService(application: MoneroApplication) : ServiceBase(null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val proxy: String?
|
|
||||||
get() = instance?.getString(Constants.PREF_PROXY, "")
|
|
||||||
|
|
||||||
fun hasProxySet(): Boolean {
|
|
||||||
val proxyString = proxy
|
|
||||||
return proxyString?.contains(":") == true
|
|
||||||
}
|
|
||||||
|
|
||||||
val proxyAddress: String
|
|
||||||
get() {
|
|
||||||
if (hasProxySet()) {
|
|
||||||
val proxyString = proxy
|
|
||||||
return proxyString?.split(":".toRegex())?.dropLastWhile { it.isEmpty() }
|
|
||||||
?.toTypedArray()
|
|
||||||
?.get(0) ?: ""
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
val proxyPort: String
|
|
||||||
get() {
|
|
||||||
if (hasProxySet()) {
|
|
||||||
val proxyString = proxy
|
|
||||||
return proxyString?.split(":".toRegex())?.dropLastWhile { it.isEmpty() }
|
|
||||||
?.toTypedArray()
|
|
||||||
?.get(1) ?: ""
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getString(key: String?, defaultValue: String): String? {
|
fun getString(key: String?, defaultValue: String): String? {
|
||||||
val value = preferences?.getString(key, "")
|
val value = preferences?.getString(key, "")
|
||||||
if (value?.isEmpty() == true && defaultValue.isNotEmpty()) {
|
if (value?.isEmpty() == true && defaultValue.isNotEmpty()) {
|
||||||
|
|
75
app/src/main/java/net/mynero/wallet/service/ProxyService.kt
Normal file
75
app/src/main/java/net/mynero/wallet/service/ProxyService.kt
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package net.mynero.wallet.service
|
||||||
|
|
||||||
|
import android.util.Patterns
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import net.mynero.wallet.data.Node
|
||||||
|
import net.mynero.wallet.livedata.SingleLiveEvent
|
||||||
|
import net.mynero.wallet.model.WalletManager
|
||||||
|
import net.mynero.wallet.util.Constants
|
||||||
|
|
||||||
|
class ProxyService(thread: MoneroHandlerThread) : ServiceBase(thread) {
|
||||||
|
val proxyChangeEvents: SingleLiveEvent<String> = SingleLiveEvent()
|
||||||
|
|
||||||
|
init {
|
||||||
|
instance = this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateProxy(proxyAddress: String, proxyPort: String) {
|
||||||
|
var finalProxyAddress = proxyAddress
|
||||||
|
var finalProxyPort = proxyPort
|
||||||
|
val usesProxy = PrefService.instance?.getBoolean(Constants.PREF_USES_TOR, false) == true
|
||||||
|
val curretNode = PrefService.instance?.node
|
||||||
|
val isNodeLocalIp =
|
||||||
|
curretNode?.address?.startsWith("10.") == true || curretNode?.address?.startsWith("192.168.") == true || curretNode?.address == "localhost" || curretNode?.address == "127.0.0.1"
|
||||||
|
curretNode?.trusted?.let { WalletManager.instance?.wallet?.setTrustedDaemon(it) }
|
||||||
|
if (!usesProxy || isNodeLocalIp) {
|
||||||
|
// User is not using proxy, or is using local node currently, so we will disable proxy here.
|
||||||
|
proxyChangeEvents.postValue("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// We are using proxy at this point, but user set them to empty. We will fallback to Tor defaults here.
|
||||||
|
if (proxyAddress.isEmpty()) finalProxyAddress = "127.0.0.1"
|
||||||
|
if (proxyPort.isEmpty()) finalProxyPort = "9050"
|
||||||
|
val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
|
||||||
|
if (validIpAddress) {
|
||||||
|
val proxy = "$finalProxyAddress:$finalProxyPort"
|
||||||
|
PrefService.instance?.edit()?.putString(Constants.PREF_PROXY, proxy)?.apply()
|
||||||
|
proxyChangeEvents.postValue(proxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasProxySet(): Boolean {
|
||||||
|
val proxyString = proxy
|
||||||
|
return proxyString?.contains(":") == true
|
||||||
|
}
|
||||||
|
|
||||||
|
val proxy: String?
|
||||||
|
get() = PrefService.instance?.getString(Constants.PREF_PROXY, "")
|
||||||
|
|
||||||
|
val proxyAddress: String
|
||||||
|
get() {
|
||||||
|
if (hasProxySet()) {
|
||||||
|
val proxyString = proxy
|
||||||
|
return proxyString?.split(":".toRegex())?.dropLastWhile { it.isEmpty() }
|
||||||
|
?.toTypedArray()
|
||||||
|
?.get(0) ?: ""
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
val proxyPort: String
|
||||||
|
get() {
|
||||||
|
if (hasProxySet()) {
|
||||||
|
val proxyString = proxy
|
||||||
|
return proxyString?.split(":".toRegex())?.dropLastWhile { it.isEmpty() }
|
||||||
|
?.toTypedArray()
|
||||||
|
?.get(1) ?: ""
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var instance: ProxyService? = null
|
||||||
|
private set
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,20 +59,20 @@
|
||||||
android:id="@+id/address_edittext"
|
android:id="@+id/address_edittext"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:background="@drawable/edittext_bg"
|
android:background="@drawable/edittext_bg"
|
||||||
android:hint="@string/node_address_hint"
|
android:hint="@string/node_address_hint"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:digits="QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890.:-[]"
|
android:digits="QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890.:-[]"
|
||||||
app:layout_constraintBottom_toTopOf="@id/username_edittext"
|
app:layout_constraintBottom_toTopOf="@id/trusted_node_checkbox"
|
||||||
app:layout_constraintEnd_toStartOf="@id/node_port_edittext"
|
app:layout_constraintEnd_toStartOf="@id/node_port_edittext"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/node_name_edittext"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/node_port_edittext"
|
android:id="@+id/node_port_edittext"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:background="@drawable/edittext_bg"
|
android:background="@drawable/edittext_bg"
|
||||||
android:hint="@string/node_port_hint"
|
android:hint="@string/node_port_hint"
|
||||||
|
@ -83,6 +83,19 @@
|
||||||
app:layout_constraintEnd_toStartOf="@id/paste_address_imagebutton"
|
app:layout_constraintEnd_toStartOf="@id/paste_address_imagebutton"
|
||||||
app:layout_constraintStart_toEndOf="@id/address_edittext" />
|
app:layout_constraintStart_toEndOf="@id/address_edittext" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/trusted_node_checkbox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="@string/trusted_daemon"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/username_edittext"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/address_edittext"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/add_node_button"
|
android:id="@+id/add_node_button"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -101,6 +114,7 @@
|
||||||
android:background="@drawable/edittext_bg"
|
android:background="@drawable/edittext_bg"
|
||||||
android:hint="@string/node_username_hint"
|
android:hint="@string/node_username_hint"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/trusted_node_checkbox"
|
||||||
app:layout_constraintBottom_toTopOf="@id/password_edittext"
|
app:layout_constraintBottom_toTopOf="@id/password_edittext"
|
||||||
app:layout_constraintEnd_toStartOf="@id/paste_username_imagebutton"
|
app:layout_constraintEnd_toStartOf="@id/paste_username_imagebutton"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
@ -123,11 +137,10 @@
|
||||||
android:id="@+id/password_edittext"
|
android:id="@+id/password_edittext"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:background="@drawable/edittext_bg"
|
android:background="@drawable/edittext_bg"
|
||||||
android:hint="@string/node_password_hint"
|
android:hint="@string/node_password_hint"
|
||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
android:visibility="gone"
|
android:visibility="visible"
|
||||||
app:layout_constraintBottom_toTopOf="@id/add_node_button"
|
app:layout_constraintBottom_toTopOf="@id/add_node_button"
|
||||||
app:layout_constraintEnd_toStartOf="@id/paste_password_imagebutton"
|
app:layout_constraintEnd_toStartOf="@id/paste_password_imagebutton"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
@ -136,12 +149,10 @@
|
||||||
android:id="@+id/paste_password_imagebutton"
|
android:id="@+id/paste_password_imagebutton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:minWidth="48dp"
|
android:minWidth="48dp"
|
||||||
android:minHeight="48dp"
|
android:minHeight="48dp"
|
||||||
android:visibility="gone"
|
android:visibility="visible"
|
||||||
android:src="@drawable/ic_content_paste_24dp"
|
android:src="@drawable/ic_content_paste_24dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/password_edittext"
|
app:layout_constraintBottom_toBottomOf="@id/password_edittext"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|
|
@ -59,20 +59,20 @@
|
||||||
android:id="@+id/address_edittext"
|
android:id="@+id/address_edittext"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:background="@drawable/edittext_bg"
|
android:background="@drawable/edittext_bg"
|
||||||
android:hint="@string/node_address_hint"
|
android:hint="@string/node_address_hint"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:digits="QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890.:-[]"
|
android:digits="QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890.:-[]"
|
||||||
app:layout_constraintBottom_toTopOf="@id/username_edittext"
|
app:layout_constraintBottom_toTopOf="@id/trusted_node_checkbox"
|
||||||
app:layout_constraintEnd_toStartOf="@id/node_port_edittext"
|
app:layout_constraintEnd_toStartOf="@id/node_port_edittext"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/node_name_edittext"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/node_port_edittext"
|
android:id="@+id/node_port_edittext"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:background="@drawable/edittext_bg"
|
android:background="@drawable/edittext_bg"
|
||||||
android:hint="@string/node_port_hint"
|
android:hint="@string/node_port_hint"
|
||||||
|
@ -83,15 +83,29 @@
|
||||||
app:layout_constraintEnd_toStartOf="@id/paste_address_imagebutton"
|
app:layout_constraintEnd_toStartOf="@id/paste_address_imagebutton"
|
||||||
app:layout_constraintStart_toEndOf="@id/address_edittext" />
|
app:layout_constraintStart_toEndOf="@id/address_edittext" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/trusted_node_checkbox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="@string/trusted_daemon"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/username_edittext"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/address_edittext"/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/username_edittext"
|
android:id="@+id/username_edittext"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:background="@drawable/edittext_bg"
|
android:background="@drawable/edittext_bg"
|
||||||
android:hint="@string/node_username_hint"
|
android:hint="@string/node_username_hint"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
app:layout_constraintTop_toBottomOf="@id/address_edittext"
|
app:layout_constraintTop_toBottomOf="@id/trusted_node_checkbox"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/password_edittext"
|
||||||
app:layout_constraintEnd_toStartOf="@id/paste_username_imagebutton"
|
app:layout_constraintEnd_toStartOf="@id/paste_username_imagebutton"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
@ -113,12 +127,10 @@
|
||||||
android:id="@+id/password_edittext"
|
android:id="@+id/password_edittext"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:background="@drawable/edittext_bg"
|
android:background="@drawable/edittext_bg"
|
||||||
android:hint="@string/node_password_hint"
|
android:hint="@string/node_password_hint"
|
||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
android:visibility="gone"
|
android:visibility="visible"
|
||||||
app:layout_constraintTop_toBottomOf="@id/username_edittext"
|
app:layout_constraintTop_toBottomOf="@id/username_edittext"
|
||||||
app:layout_constraintBottom_toTopOf="@id/delete_node_button"
|
app:layout_constraintBottom_toTopOf="@id/delete_node_button"
|
||||||
app:layout_constraintEnd_toStartOf="@id/paste_password_imagebutton"
|
app:layout_constraintEnd_toStartOf="@id/paste_password_imagebutton"
|
||||||
|
@ -128,13 +140,11 @@
|
||||||
android:id="@+id/paste_password_imagebutton"
|
android:id="@+id/paste_password_imagebutton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:minWidth="24dp"
|
android:minWidth="48dp"
|
||||||
android:minHeight="24dp"
|
android:minHeight="48dp"
|
||||||
android:padding="8dp"
|
android:padding="8dp"
|
||||||
android:visibility="gone"
|
android:visibility="visible"
|
||||||
android:src="@drawable/ic_content_paste_24dp"
|
android:src="@drawable/ic_content_paste_24dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/password_edittext"
|
app:layout_constraintBottom_toBottomOf="@id/password_edittext"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -146,7 +156,7 @@
|
||||||
android:id="@+id/delete_node_button"
|
android:id="@+id/delete_node_button"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="32dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginEnd="1dp"
|
android:layout_marginEnd="1dp"
|
||||||
android:background="@drawable/button_bg_left"
|
android:background="@drawable/button_bg_left"
|
||||||
android:text="@string/delete"
|
android:text="@string/delete"
|
||||||
|
@ -157,7 +167,7 @@
|
||||||
android:id="@+id/done_editing_button"
|
android:id="@+id/done_editing_button"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="32dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginStart="1dp"
|
android:layout_marginStart="1dp"
|
||||||
android:background="@drawable/button_bg_right"
|
android:background="@drawable/button_bg_right"
|
||||||
android:text="@string/done"
|
android:text="@string/done"
|
||||||
|
|
|
@ -16,24 +16,13 @@
|
||||||
android:text="@string/settings"
|
android:text="@string/settings"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
android:textSize="32sp"
|
android:textSize="32sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintEnd_toStartOf="@id/status_textview"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/status_textview"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/disconnected"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:layout_marginEnd="24dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/settings_textview"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/settings_textview"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/settings_textview" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/wallet_settings_textview"
|
android:id="@+id/wallet_settings_textview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -105,7 +105,8 @@
|
||||||
<string name="transaction_conf_1_desc2_confirmed">time, and was mined in block</string>
|
<string name="transaction_conf_1_desc2_confirmed">time, and was mined in block</string>
|
||||||
<string name="date">Date</string>
|
<string name="date">Date</string>
|
||||||
<string name="transaction_on_date_label">on</string>
|
<string name="transaction_on_date_label">on</string>
|
||||||
<string name="node_selected">Node has been selected</string>
|
<string name="node_selecting">Selecting node…</string>
|
||||||
|
<string name="node_selected">Using node: %1$s</string>
|
||||||
<string name="fee_priority">Fee priority:</string>
|
<string name="fee_priority">Fee priority:</string>
|
||||||
<string name="low">Low</string>
|
<string name="low">Low</string>
|
||||||
<string name="medium">Medium</string>
|
<string name="medium">Medium</string>
|
||||||
|
@ -134,6 +135,7 @@
|
||||||
<string name="wallet_restore_height_label">Restore height</string>
|
<string name="wallet_restore_height_label">Restore height</string>
|
||||||
<string name="block_height">Block Height</string>
|
<string name="block_height">Block Height</string>
|
||||||
<string name="use_password_as_seed_offset">Use passphrase as seed offset</string>
|
<string name="use_password_as_seed_offset">Use passphrase as seed offset</string>
|
||||||
|
<string name="trusted_daemon">Trusted daemon</string>
|
||||||
<string name="subbaddress_info_subtitle" translatable="false">#%1$d: %2$s</string>
|
<string name="subbaddress_info_subtitle" translatable="false">#%1$d: %2$s</string>
|
||||||
<string name="previous_addresses">Previous addresses</string>
|
<string name="previous_addresses">Previous addresses</string>
|
||||||
<string name="donate_label">Donate to Mysu</string>
|
<string name="donate_label">Donate to Mysu</string>
|
||||||
|
|
Loading…
Reference in a new issue