mirror of
https://codeberg.org/anoncontributorxmr/mysu.git
synced 2024-11-25 08:52: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"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
versionCode 50200
|
||||
versionName "0.5.2 'Fluorine Fermi'"
|
||||
versionCode 50300
|
||||
versionName "0.5.3 'Fluorine Fermi'"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
|
|
|
@ -920,11 +920,25 @@ Java_net_mynero_wallet_model_Wallet_getConnectionStatusJ(JNIEnv *env, jobject in
|
|||
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
||||
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;
|
||||
|
||||
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) {
|
||||
const char *_address = env->GetStringUTFChars(address, nullptr);
|
||||
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
||||
|
|
|
@ -4,7 +4,11 @@ import android.os.Bundle
|
|||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
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.PasswordListener
|
||||
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.BalanceService
|
||||
import net.mynero.wallet.service.BlockchainService
|
||||
import net.mynero.wallet.service.DaemonService
|
||||
import net.mynero.wallet.service.HistoryService
|
||||
import net.mynero.wallet.service.MoneroHandlerThread
|
||||
import net.mynero.wallet.service.PrefService
|
||||
import net.mynero.wallet.service.ProxyService
|
||||
import net.mynero.wallet.service.TxService
|
||||
import net.mynero.wallet.service.UTXOService
|
||||
import net.mynero.wallet.util.Constants
|
||||
import net.mynero.wallet.util.UriData
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
class MainActivity : AppCompatActivity(), MoneroHandlerThread.Listener, PasswordListener {
|
||||
|
@ -29,6 +36,8 @@ class MainActivity : AppCompatActivity(), MoneroHandlerThread.Listener, Password
|
|||
private var balanceService: BalanceService? = null
|
||||
private var addressService: AddressService? = null
|
||||
private var historyService: HistoryService? = null
|
||||
private var proxyService: ProxyService? = null
|
||||
private var daemonService: DaemonService? = null
|
||||
private var blockchainService: BlockchainService? = null
|
||||
private var utxoService: UTXOService? = null
|
||||
private var proceedToSend = false
|
||||
|
@ -77,6 +86,8 @@ class MainActivity : AppCompatActivity(), MoneroHandlerThread.Listener, Password
|
|||
addressService = AddressService(thread)
|
||||
historyService = HistoryService(thread)
|
||||
blockchainService = BlockchainService(thread)
|
||||
daemonService = DaemonService(thread)
|
||||
proxyService = ProxyService(thread)
|
||||
utxoService = UTXOService(thread)
|
||||
thread.start()
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ class Node {
|
|||
private set
|
||||
var password = ""
|
||||
private set
|
||||
private var favourite = false
|
||||
var trusted = false
|
||||
private set
|
||||
|
||||
internal constructor(nodeString: String?) {
|
||||
require(!nodeString.isNullOrEmpty()) { "daemon is empty" }
|
||||
|
@ -142,6 +143,9 @@ class Node {
|
|||
}
|
||||
require(networkType == WalletManager.instance?.networkType) { "wrong net: $networkType" }
|
||||
}
|
||||
if (jsonObject.has("trusted")) {
|
||||
this.trusted = jsonObject.getBoolean("trusted")
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
|
@ -197,6 +201,7 @@ class Node {
|
|||
null -> TODO()
|
||||
}
|
||||
if (name?.isNotEmpty() == true) jsonObject.put("name", name)
|
||||
jsonObject.put("trusted", trusted)
|
||||
} catch (e: JSONException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
|
@ -235,7 +240,7 @@ class Node {
|
|||
levinPort = anotherNode.levinPort
|
||||
username = anotherNode.username
|
||||
password = anotherNode.password
|
||||
favourite = anotherNode.favourite
|
||||
trusted = anotherNode.trusted
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.CheckBox
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.Toast
|
||||
|
@ -38,6 +39,8 @@ class AddNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
val nodeNameEditText = view.findViewById<EditText>(R.id.node_name_edittext)
|
||||
val usernameEditText = view.findViewById<EditText>(R.id.username_edittext)
|
||||
val passwordEditText = view.findViewById<EditText>(R.id.password_edittext)
|
||||
val trustedDaemonCheckbox = view.findViewById<CheckBox>(R.id.trusted_node_checkbox)
|
||||
|
||||
val pastePasswordImageButton =
|
||||
view.findViewById<ImageButton>(R.id.paste_password_imagebutton)
|
||||
usernameEditText.addTextChangedListener(object : TextWatcher {
|
||||
|
@ -63,6 +66,8 @@ class AddNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
val name = nodeNameEditText.text.toString()
|
||||
val user = usernameEditText.text.toString()
|
||||
val pass = passwordEditText.text.toString()
|
||||
val trusted = trustedDaemonCheckbox.isChecked
|
||||
|
||||
if (name.isEmpty()) {
|
||||
Toast.makeText(context, "Enter node name", Toast.LENGTH_SHORT).show()
|
||||
return@setOnClickListener
|
||||
|
@ -85,6 +90,7 @@ class AddNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
jsonObject.put("rpcPort", portString.toInt())
|
||||
jsonObject.put("network", "mainnet")
|
||||
jsonObject.put("name", name)
|
||||
jsonObject.put("trusted", trusted)
|
||||
addNodeToSaved(jsonObject)
|
||||
if (listener != null) {
|
||||
listener?.onNodeAdded()
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.CheckBox
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.Toast
|
||||
|
@ -39,6 +40,7 @@ class EditNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
val nodeNameEditText = view.findViewById<EditText>(R.id.node_name_edittext)
|
||||
val usernameEditText = view.findViewById<EditText>(R.id.username_edittext)
|
||||
val passwordEditText = view.findViewById<EditText>(R.id.password_edittext)
|
||||
val trustedDaemonCheckBox = view.findViewById<CheckBox>(R.id.trusted_node_checkbox)
|
||||
val pastePasswordImageButton =
|
||||
view.findViewById<ImageButton>(R.id.paste_password_imagebutton)
|
||||
if (node == null) return
|
||||
|
@ -46,6 +48,7 @@ class EditNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
portEditText.setText("${node?.rpcPort}")
|
||||
nodeNameEditText.setText(node?.name)
|
||||
usernameEditText.setText(node?.username)
|
||||
trustedDaemonCheckBox.isChecked = node?.trusted ?: false
|
||||
if (node?.password?.isNotEmpty() == true) {
|
||||
passwordEditText.setText(node?.password)
|
||||
passwordEditText.visibility = View.VISIBLE
|
||||
|
@ -78,6 +81,7 @@ class EditNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
val nodeName = nodeNameEditText.text.toString()
|
||||
val user = usernameEditText.text.toString()
|
||||
val pass = passwordEditText.text.toString()
|
||||
val trusted = trustedDaemonCheckBox.isChecked
|
||||
if (nodeName.isEmpty()) {
|
||||
Toast.makeText(context, "Enter node name", Toast.LENGTH_SHORT).show()
|
||||
return@setOnClickListener
|
||||
|
@ -101,6 +105,7 @@ class EditNodeBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
jsonObject.put("rpcPort", portString.toInt())
|
||||
jsonObject.put("network", "mainnet")
|
||||
jsonObject.put("name", nodeName)
|
||||
jsonObject.put("trusted", trusted)
|
||||
listener?.onNodeEdited(node, fromJson(jsonObject))
|
||||
dismiss()
|
||||
} catch (e: JSONException) {
|
||||
|
|
|
@ -7,9 +7,12 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import net.mynero.wallet.R
|
||||
import net.mynero.wallet.adapter.NodeSelectionAdapter
|
||||
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.fromString
|
||||
import net.mynero.wallet.model.WalletManager
|
||||
import net.mynero.wallet.service.DaemonService
|
||||
import net.mynero.wallet.service.PrefService
|
||||
import net.mynero.wallet.util.Constants
|
||||
import org.json.JSONArray
|
||||
|
@ -90,18 +94,12 @@ class NodeSelectionBottomSheetDialog : BottomSheetDialogFragment(), NodeSelectio
|
|||
}
|
||||
|
||||
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())
|
||||
?.apply()
|
||||
WalletManager.instance?.setDaemon(node)
|
||||
node?.let { DaemonService.instance?.setDaemon(it) }
|
||||
activity?.runOnUiThread {
|
||||
adapter?.updateSelectedNode()
|
||||
}
|
||||
listener?.onNodeSelected()
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,16 @@ import android.widget.Button
|
|||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavDirections
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import net.mynero.wallet.MainActivity
|
||||
import net.mynero.wallet.R
|
||||
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.service.BalanceService
|
||||
import net.mynero.wallet.service.BlockchainService
|
||||
import net.mynero.wallet.service.DaemonService
|
||||
import net.mynero.wallet.service.HistoryService
|
||||
import net.mynero.wallet.service.PrefService
|
||||
import net.mynero.wallet.service.ProxyService
|
||||
import net.mynero.wallet.util.Constants
|
||||
import timber.log.Timber
|
||||
|
||||
class HomeFragment : Fragment(), TxInfoAdapterListener {
|
||||
private var startHeight: Long = 0
|
||||
|
@ -66,6 +73,26 @@ class HomeFragment : Fragment(), TxInfoAdapterListener {
|
|||
val historyService = HistoryService.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 ->
|
||||
if (balanceInfo != null) {
|
||||
unlockedBalanceTextView.text = balanceInfo.unlockedDisplay
|
||||
|
@ -101,7 +128,8 @@ class HomeFragment : Fragment(), TxInfoAdapterListener {
|
|||
}
|
||||
} else {
|
||||
progressBar.visibility = View.INVISIBLE
|
||||
progressBarText.visibility = View.GONE
|
||||
progressBarText.visibility = View.VISIBLE
|
||||
progressBarText.text = "Synchronized"
|
||||
}
|
||||
}
|
||||
val adapter = TransactionInfoAdapter(this)
|
||||
|
|
|
@ -14,6 +14,7 @@ import android.widget.CompoundButton
|
|||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
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.onboarding.OnboardingViewModel.SeedType
|
||||
import net.mynero.wallet.service.PrefService
|
||||
import net.mynero.wallet.service.ProxyService
|
||||
import net.mynero.wallet.util.Constants
|
||||
|
||||
class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListener {
|
||||
|
@ -186,11 +188,11 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USES_TOR, b)?.apply()
|
||||
removeProxyTextListeners()
|
||||
if (b) {
|
||||
if (PrefService.instance?.hasProxySet() == true) {
|
||||
if (ProxyService.instance?.hasProxySet() == true) {
|
||||
val proxyAddress =
|
||||
PrefService.instance?.proxyAddress ?: return@setOnCheckedChangeListener
|
||||
ProxyService.instance?.proxyAddress ?: return@setOnCheckedChangeListener
|
||||
val proxyPort =
|
||||
PrefService.instance?.proxyPort ?: return@setOnCheckedChangeListener
|
||||
ProxyService.instance?.proxyPort ?: return@setOnCheckedChangeListener
|
||||
initProxyStuff(proxyAddress, proxyPort)
|
||||
} else {
|
||||
initProxyStuff("127.0.0.1", "9050")
|
||||
|
@ -277,6 +279,11 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
override fun onNodeSelected() {
|
||||
val node = PrefService.instance?.node
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package net.mynero.wallet.fragment.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Patterns
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -12,12 +10,17 @@ import android.widget.CompoundButton
|
|||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
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.data.Node
|
||||
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.service.BalanceService
|
||||
import net.mynero.wallet.service.BlockchainService
|
||||
import net.mynero.wallet.service.DaemonService
|
||||
import net.mynero.wallet.service.HistoryService
|
||||
import net.mynero.wallet.service.PrefService
|
||||
import net.mynero.wallet.service.ProxyService
|
||||
import net.mynero.wallet.util.Constants
|
||||
import org.json.JSONArray
|
||||
import timber.log.Timber
|
||||
|
||||
class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListener, AddNodeListener,
|
||||
EditNodeListener {
|
||||
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 walletProxyPortEditText: EditText? = null
|
||||
private var selectNodeButton: Button? = null
|
||||
private var cachedProxyAddress: String = ""
|
||||
private var cachedProxyPort: String = ""
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
|
@ -103,12 +92,12 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
|||
donationSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_DONATE_PER_TX, b)?.apply()
|
||||
}
|
||||
val prefService = PrefService.instance
|
||||
val usesProxy = prefService?.getBoolean(Constants.PREF_USES_TOR, false) == true
|
||||
if (prefService?.hasProxySet() == true) {
|
||||
val proxyAddress = prefService.proxyAddress
|
||||
val proxyPort = prefService.proxyPort
|
||||
initProxyStuff(proxyAddress, proxyPort)
|
||||
val prefService = PrefService.instance ?: return
|
||||
val usesProxy = prefService.getBoolean(Constants.PREF_USES_TOR, false)
|
||||
cachedProxyAddress = ProxyService.instance?.proxyAddress ?: return
|
||||
cachedProxyPort = ProxyService.instance?.proxyPort ?: return
|
||||
if (ProxyService.instance?.hasProxySet() == true) {
|
||||
initProxyStuff(cachedProxyAddress, cachedProxyPort)
|
||||
}
|
||||
torSwitch.isChecked = usesProxy
|
||||
if (usesProxy) {
|
||||
|
@ -116,22 +105,19 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
|||
} else {
|
||||
proxySettingsLayout.visibility = View.GONE
|
||||
}
|
||||
addProxyTextListeners()
|
||||
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 (prefService?.hasProxySet() == true) {
|
||||
removeProxyTextListeners()
|
||||
val proxyAddress = prefService.proxyAddress
|
||||
val proxyPort = prefService.proxyPort
|
||||
if (ProxyService.instance?.hasProxySet() == true) {
|
||||
val proxyAddress = ProxyService.instance?.proxyAddress ?: return@setOnCheckedChangeListener
|
||||
val proxyPort = ProxyService.instance?.proxyPort ?: return@setOnCheckedChangeListener
|
||||
initProxyStuff(proxyAddress, proxyPort)
|
||||
addProxyTextListeners()
|
||||
}
|
||||
proxySettingsLayout.visibility = View.VISIBLE
|
||||
} else {
|
||||
proxySettingsLayout.visibility = View.GONE
|
||||
}
|
||||
mViewModel?.updateProxy(activity?.application as MoneroApplication)
|
||||
refreshProxy()
|
||||
}
|
||||
displaySeedButton.setOnClickListener {
|
||||
val usesPassword =
|
||||
|
@ -148,16 +134,6 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
|||
}
|
||||
}
|
||||
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
|
||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||
selectNodeButton?.setOnClickListener {
|
||||
|
@ -167,6 +143,25 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
|||
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) {
|
||||
|
@ -188,30 +183,22 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
|||
private fun initProxyStuff(proxyAddress: String, proxyPort: String) {
|
||||
val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
|
||||
if (validIpAddress) {
|
||||
mViewModel?.setProxyAddress(proxyAddress)
|
||||
mViewModel?.setProxyPort(proxyPort)
|
||||
walletProxyAddressEditText?.setText(proxyAddress)
|
||||
walletProxyPortEditText?.setText(proxyPort)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeProxyTextListeners() {
|
||||
walletProxyAddressEditText?.removeTextChangedListener(proxyAddressListener)
|
||||
walletProxyPortEditText?.removeTextChangedListener(proxyPortListener)
|
||||
}
|
||||
|
||||
private fun addProxyTextListeners() {
|
||||
walletProxyAddressEditText?.addTextChangedListener(proxyAddressListener)
|
||||
walletProxyPortEditText?.addTextChangedListener(proxyPortListener)
|
||||
}
|
||||
|
||||
override fun onNodeSelected() {
|
||||
val node = PrefService.instance?.node
|
||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||
mViewModel?.updateProxy(activity?.application as MoneroApplication)
|
||||
(activity?.application as MoneroApplication).executor?.execute {
|
||||
WalletManager.instance?.wallet?.init(0)
|
||||
WalletManager.instance?.wallet?.startRefresh()
|
||||
refreshProxy()
|
||||
|
||||
activity?.runOnUiThread {
|
||||
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
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@MainThread
|
||||
override fun postValue(value: T) {
|
||||
mPending.set(true)
|
||||
super.postValue(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for cases where T is Void, to make calls cleaner.
|
||||
*/
|
||||
|
|
|
@ -208,8 +208,20 @@ class Wallet {
|
|||
}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
import android.util.Log
|
||||
import net.mynero.wallet.model.PendingTransaction
|
||||
import net.mynero.wallet.model.TransactionOutput
|
||||
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.WalletManager
|
||||
import net.mynero.wallet.util.Constants
|
||||
import timber.log.Timber
|
||||
import java.security.SecureRandom
|
||||
|
||||
/**
|
||||
|
@ -57,11 +59,12 @@ class MoneroHandlerThread(name: String, val listener: Listener?, wallet: Wallet)
|
|||
currentNode?.address == "localhost" ||
|
||||
currentNode?.address == "127.0.0.1"
|
||||
if (usesTor && !isLocalIp) {
|
||||
val proxy = prefService.proxy
|
||||
val proxy = ProxyService.instance?.proxy
|
||||
proxy?.let { WalletManager.instance?.setProxy(it) }
|
||||
wallet.setProxy(proxy)
|
||||
}
|
||||
WalletManager.instance?.setDaemon(currentNode)
|
||||
currentNode?.trusted?.let { wallet.setTrustedDaemon(it) }
|
||||
wallet.init(0)
|
||||
wallet.setListener(this)
|
||||
wallet.startRefresh()
|
||||
|
@ -81,20 +84,36 @@ class MoneroHandlerThread(name: String, val listener: Listener?, wallet: Wallet)
|
|||
|
||||
override fun refreshed() {
|
||||
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 (triesLeft > 0) {
|
||||
wallet.startRefresh()
|
||||
triesLeft--
|
||||
tryRestartOrFail()
|
||||
} else {
|
||||
listener?.onConnectionFail()
|
||||
}
|
||||
val heightDiff = daemonHeight - chainHeight
|
||||
if(heightDiff >= 2) {
|
||||
tryRestartOrFail()
|
||||
} else {
|
||||
BlockchainService.instance?.daemonHeight = wallet.getDaemonBlockChainHeight()
|
||||
Timber.d("refreshed() Synchronized")
|
||||
wallet.setSynchronized()
|
||||
wallet.store()
|
||||
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) {
|
||||
|
|
|
@ -29,8 +29,8 @@ class PrefService(application: MoneroApplication) : ServiceBase(null) {
|
|||
val usesProxy = getBoolean(Constants.PREF_USES_TOR, false)
|
||||
var defaultNode = DefaultNodes.SAMOURAI
|
||||
if (usesProxy) {
|
||||
val proxyPort = proxyPort
|
||||
if (proxyPort.isNotEmpty()) {
|
||||
val proxyPort = ProxyService.instance?.proxyPort
|
||||
if (proxyPort?.isNotEmpty() == true) {
|
||||
val port = proxyPort.toInt()
|
||||
defaultNode = if (port == 4447) {
|
||||
DefaultNodes.MYNERO_I2P
|
||||
|
@ -60,35 +60,6 @@ class PrefService(application: MoneroApplication) : ServiceBase(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? {
|
||||
val value = preferences?.getString(key, "")
|
||||
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:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/node_address_hint"
|
||||
android:inputType="text"
|
||||
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_constraintTop_toBottomOf="@id/node_name_edittext"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/node_port_edittext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/node_port_hint"
|
||||
|
@ -83,6 +83,19 @@
|
|||
app:layout_constraintEnd_toStartOf="@id/paste_address_imagebutton"
|
||||
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
|
||||
android:id="@+id/add_node_button"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -101,6 +114,7 @@
|
|||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/node_username_hint"
|
||||
android:inputType="text"
|
||||
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_constraintStart_toStartOf="parent" />
|
||||
|
@ -123,11 +137,10 @@
|
|||
android:id="@+id/password_edittext"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/node_password_hint"
|
||||
android:inputType="textPassword"
|
||||
android:visibility="gone"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toTopOf="@id/add_node_button"
|
||||
app:layout_constraintEnd_toStartOf="@id/paste_password_imagebutton"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
@ -136,12 +149,10 @@
|
|||
android:id="@+id/paste_password_imagebutton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:minWidth="48dp"
|
||||
android:minHeight="48dp"
|
||||
android:visibility="gone"
|
||||
android:visibility="visible"
|
||||
android:src="@drawable/ic_content_paste_24dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/password_edittext"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
@ -59,20 +59,20 @@
|
|||
android:id="@+id/address_edittext"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/node_address_hint"
|
||||
android:inputType="text"
|
||||
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_constraintTop_toBottomOf="@id/node_name_edittext"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/node_port_edittext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/node_port_hint"
|
||||
|
@ -83,15 +83,29 @@
|
|||
app:layout_constraintEnd_toStartOf="@id/paste_address_imagebutton"
|
||||
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
|
||||
android:id="@+id/username_edittext"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/node_username_hint"
|
||||
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_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
@ -113,12 +127,10 @@
|
|||
android:id="@+id/password_edittext"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/node_password_hint"
|
||||
android:inputType="textPassword"
|
||||
android:visibility="gone"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintTop_toBottomOf="@id/username_edittext"
|
||||
app:layout_constraintBottom_toTopOf="@id/delete_node_button"
|
||||
app:layout_constraintEnd_toStartOf="@id/paste_password_imagebutton"
|
||||
|
@ -128,13 +140,11 @@
|
|||
android:id="@+id/paste_password_imagebutton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:minWidth="24dp"
|
||||
android:minHeight="24dp"
|
||||
android:minWidth="48dp"
|
||||
android:minHeight="48dp"
|
||||
android:padding="8dp"
|
||||
android:visibility="gone"
|
||||
android:visibility="visible"
|
||||
android:src="@drawable/ic_content_paste_24dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/password_edittext"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -146,7 +156,7 @@
|
|||
android:id="@+id/delete_node_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:background="@drawable/button_bg_left"
|
||||
android:text="@string/delete"
|
||||
|
@ -157,7 +167,7 @@
|
|||
android:id="@+id/done_editing_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="1dp"
|
||||
android:background="@drawable/button_bg_right"
|
||||
android:text="@string/done"
|
||||
|
|
|
@ -16,24 +16,13 @@
|
|||
android:text="@string/settings"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_textview"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="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
|
||||
android:id="@+id/wallet_settings_textview"
|
||||
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="date">Date</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="low">Low</string>
|
||||
<string name="medium">Medium</string>
|
||||
|
@ -134,6 +135,7 @@
|
|||
<string name="wallet_restore_height_label">Restore height</string>
|
||||
<string name="block_height">Block Height</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="previous_addresses">Previous addresses</string>
|
||||
<string name="donate_label">Donate to Mysu</string>
|
||||
|
|
Loading…
Reference in a new issue