mirror of
https://codeberg.org/anoncontributorxmr/mysu.git
synced 2024-12-22 13:07:46 +00:00
Refactoring settings/onboarding screens
This commit is contained in:
parent
3b77ae3673
commit
bd67d6d4bd
9 changed files with 468 additions and 577 deletions
|
@ -1,10 +1,8 @@
|
|||
package net.mynero.wallet.fragment.onboarding
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Patterns
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -18,13 +16,12 @@ import android.widget.Toast
|
|||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import net.mynero.wallet.MoneroApplication
|
||||
import net.mynero.wallet.R
|
||||
import net.mynero.wallet.data.Node
|
||||
import net.mynero.wallet.fragment.dialog.AddNodeBottomSheetDialog
|
||||
|
@ -32,9 +29,9 @@ import net.mynero.wallet.fragment.dialog.AddNodeBottomSheetDialog.AddNodeListene
|
|||
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.model.EnumTorState
|
||||
import net.mynero.wallet.service.PrefService
|
||||
import net.mynero.wallet.service.ProxyService
|
||||
import net.mynero.wallet.util.Constants
|
||||
|
||||
class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListener {
|
||||
private var useOffset = true
|
||||
|
@ -56,6 +53,7 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
private var xmrchanOnboardingImage: ImageView? = null
|
||||
private var seedTypeButton: Button? = null
|
||||
private var seedTypeDescTextView: TextView? = null
|
||||
private var useBundledTor: CheckBox? = null
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
|
@ -83,11 +81,38 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
xmrchanOnboardingImage = view.findViewById(R.id.xmrchan_onboarding_imageview)
|
||||
seedTypeButton = view.findViewById(R.id.seed_type_button)
|
||||
seedTypeDescTextView = view.findViewById(R.id.seed_type_desc_textview)
|
||||
useBundledTor = view.findViewById(R.id.bundled_tor_checkbox)
|
||||
|
||||
seedOffsetCheckbox?.isChecked = useOffset
|
||||
showXmrchanSwitch?.isChecked = true
|
||||
val usingProxy = ProxyService.instance?.usingProxy == true
|
||||
val usingBundledTor = ProxyService.instance?.useBundledTor == true
|
||||
|
||||
torSwitch?.isChecked = usingProxy
|
||||
useBundledTor?.isChecked = usingBundledTor
|
||||
useBundledTor?.isEnabled = usingProxy
|
||||
walletProxyAddressEditText?.isEnabled = usingProxy && !usingBundledTor
|
||||
walletProxyPortEditText?.isEnabled = usingProxy && !usingBundledTor
|
||||
walletProxyPortEditText?.visibility = if (usingBundledTor) View.GONE else View.VISIBLE
|
||||
walletProxyAddressEditText?.visibility = if (usingBundledTor) View.GONE else View.VISIBLE
|
||||
|
||||
val node = PrefService.instance?.node // should be using default here
|
||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||
|
||||
bindListeners()
|
||||
bindObservers()
|
||||
}
|
||||
|
||||
private fun bindObservers() {
|
||||
mViewModel?.passphrase?.observe(viewLifecycleOwner) { text ->
|
||||
if (text.isEmpty()) {
|
||||
walletPasswordConfirmEditText?.text = null
|
||||
walletPasswordConfirmEditText?.visibility = View.GONE
|
||||
} else {
|
||||
walletPasswordConfirmEditText?.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
mViewModel?.showMoreOptions?.observe(viewLifecycleOwner) { show: Boolean ->
|
||||
if (show) {
|
||||
moreOptionsChevronImageView?.setImageResource(R.drawable.ic_keyboard_arrow_up)
|
||||
|
@ -97,9 +122,11 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
advancedOptionsLayout?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
mViewModel?.enableButton?.observe(viewLifecycleOwner) { enable: Boolean ->
|
||||
createWalletButton?.isEnabled = enable
|
||||
}
|
||||
|
||||
mViewModel?.seedType?.observe(viewLifecycleOwner) { seedType: SeedType ->
|
||||
seedTypeButton?.text = seedType.toString()
|
||||
seedTypeDescTextView?.text = getText(seedType.descResId)
|
||||
|
@ -116,59 +143,92 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
}
|
||||
}
|
||||
|
||||
mViewModel?.showMonerochan?.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
xmrchanOnboardingImage?.visibility = View.VISIBLE
|
||||
} else {
|
||||
xmrchanOnboardingImage?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
mViewModel?.useBundledTor?.observe(viewLifecycleOwner) { isChecked ->
|
||||
walletProxyPortEditText?.visibility = if (isChecked) View.GONE else View.VISIBLE
|
||||
walletProxyAddressEditText?.visibility = if (isChecked) View.GONE else View.VISIBLE
|
||||
}
|
||||
|
||||
mViewModel?.useProxy?.observe(viewLifecycleOwner) { useProxy ->
|
||||
useBundledTor?.isEnabled = useProxy
|
||||
walletProxyAddressEditText?.isEnabled = useProxy
|
||||
walletProxyPortEditText?.isEnabled = useProxy
|
||||
}
|
||||
|
||||
val samouraiTorManager = ProxyService.instance?.samouraiTorManager
|
||||
samouraiTorManager?.getTorStateLiveData()?.observeForever {
|
||||
println("STATE CHANGE:: ${it.state.name}")
|
||||
val indicatorCircle = view?.findViewById<CircularProgressIndicator>(R.id.onboarding_tor_loading_progressindicator)
|
||||
val torIcon = view?.findViewById<ImageView>(R.id.onboarding_tor_icon)
|
||||
|
||||
samouraiTorManager?.getTorStateLiveData()?.observe(viewLifecycleOwner) { state ->
|
||||
samouraiTorManager.getProxy()?.address()?.let { socketAddress ->
|
||||
if(socketAddress.toString().isEmpty()) return@let
|
||||
println("PROXY INIT")
|
||||
val proxyString = socketAddress.toString().substring(1)
|
||||
val address = proxyString.split(":")[0]
|
||||
val port = proxyString.split(":")[1]
|
||||
if(mViewModel?.useProxy?.value == true && mViewModel?.useBundledTor?.value == true) {
|
||||
mViewModel?.setProxyAddress(address)
|
||||
mViewModel?.setProxyPort(port)
|
||||
torIcon?.visibility = View.VISIBLE
|
||||
indicatorCircle?.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
indicatorCircle?.isIndeterminate = state.progressIndicator == 0
|
||||
indicatorCircle?.progress = state.progressIndicator
|
||||
|
||||
when (state.state) {
|
||||
EnumTorState.OFF -> {
|
||||
torIcon?.visibility = View.INVISIBLE
|
||||
indicatorCircle?.visibility = View.INVISIBLE
|
||||
}
|
||||
EnumTorState.STARTING -> {
|
||||
torIcon?.visibility = View.INVISIBLE
|
||||
indicatorCircle?.visibility = View.VISIBLE
|
||||
}
|
||||
EnumTorState.STOPPING -> {
|
||||
torIcon?.visibility = View.INVISIBLE
|
||||
indicatorCircle?.visibility = View.VISIBLE
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindListeners() {
|
||||
val useBundledTor = view?.findViewById<CheckBox>(R.id.bundled_tor_checkbox)
|
||||
|
||||
seedOffsetCheckbox?.isChecked = useOffset
|
||||
// Disable onBack click
|
||||
val onBackPressedCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {}
|
||||
}
|
||||
val activity = activity
|
||||
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, onBackPressedCallback)
|
||||
|
||||
moreOptionsDropdownTextView?.setOnClickListener { mViewModel?.onMoreOptionsClicked() }
|
||||
|
||||
moreOptionsChevronImageView?.setOnClickListener { mViewModel?.onMoreOptionsClicked() }
|
||||
|
||||
seedOffsetCheckbox?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
useOffset = b
|
||||
}
|
||||
|
||||
createWalletButton?.setOnClickListener {
|
||||
onBackPressedCallback.isEnabled = false
|
||||
(getActivity()?.application as MoneroApplication).executor?.execute {
|
||||
createOrImportWallet(
|
||||
walletSeedEditText?.text.toString().trim { it <= ' ' },
|
||||
walletRestoreHeightEditText?.text.toString().trim { it <= ' ' }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
walletPasswordEditText?.addTextChangedListener(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) {
|
||||
val text = editable.toString()
|
||||
mViewModel?.setPassphrase(text)
|
||||
if (text.isEmpty()) {
|
||||
walletPasswordConfirmEditText?.text = null
|
||||
walletPasswordConfirmEditText?.visibility = View.GONE
|
||||
} else {
|
||||
walletPasswordConfirmEditText?.visibility = View.VISIBLE
|
||||
}
|
||||
mViewModel?.setPassphrase(editable.toString())
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -176,10 +236,10 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
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) {
|
||||
val text = editable.toString()
|
||||
mViewModel?.setConfirmedPassphrase(text)
|
||||
mViewModel?.setConfirmedPassphrase(editable.toString())
|
||||
}
|
||||
})
|
||||
|
||||
walletSeedEditText?.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
||||
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
||||
|
@ -192,19 +252,13 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
seedTypeButton?.setOnClickListener { toggleSeedType() }
|
||||
torSwitch?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
if (b) {
|
||||
useBundledTor?.visibility = View.VISIBLE
|
||||
walletProxyAddressEditText?.visibility = View.VISIBLE
|
||||
walletProxyPortEditText?.visibility = View.VISIBLE
|
||||
} else {
|
||||
useBundledTor?.visibility = View.GONE
|
||||
walletProxyAddressEditText?.visibility = View.GONE
|
||||
walletProxyPortEditText?.visibility = View.GONE
|
||||
}
|
||||
|
||||
torSwitch?.setOnCheckedChangeListener { _, b: Boolean ->
|
||||
mViewModel?.setUseProxy(b)
|
||||
}
|
||||
|
||||
walletProxyPortEditText?.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
||||
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
||||
|
@ -213,6 +267,7 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
mViewModel?.setProxyPort(text)
|
||||
}
|
||||
})
|
||||
|
||||
walletProxyAddressEditText?.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
||||
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
||||
|
@ -221,16 +276,11 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
mViewModel?.setProxyAddress(text)
|
||||
}
|
||||
})
|
||||
showXmrchanSwitch?.isChecked = true
|
||||
|
||||
showXmrchanSwitch?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
if (b) {
|
||||
xmrchanOnboardingImage?.visibility = View.VISIBLE
|
||||
} else {
|
||||
xmrchanOnboardingImage?.visibility = View.GONE
|
||||
mViewModel?.setMonerochan(b)
|
||||
}
|
||||
}
|
||||
val node = PrefService.instance?.node // should be using default here
|
||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||
|
||||
selectNodeButton?.setOnClickListener {
|
||||
activity?.supportFragmentManager?.let { fragmentManager ->
|
||||
val dialog = NodeSelectionBottomSheetDialog()
|
||||
|
@ -240,13 +290,7 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
}
|
||||
|
||||
useBundledTor?.setOnCheckedChangeListener { _, isChecked ->
|
||||
walletProxyPortEditText?.visibility = if (isChecked) View.GONE else View.VISIBLE
|
||||
walletProxyAddressEditText?.visibility = if (isChecked) View.GONE else View.VISIBLE
|
||||
|
||||
if(isChecked) {
|
||||
ProxyService.instance?.samouraiTorManager?.start()
|
||||
} else {
|
||||
ProxyService.instance?.samouraiTorManager?.stop()
|
||||
if(!isChecked) {
|
||||
mViewModel?.setProxyAddress("")
|
||||
mViewModel?.setProxyPort("")
|
||||
}
|
||||
|
@ -270,11 +314,10 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
walletSeed: String,
|
||||
restoreHeightText: String
|
||||
) {
|
||||
val activity: Activity? = activity
|
||||
if (activity != null) {
|
||||
activity?.let { act ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
mViewModel?.createOrImportWallet(
|
||||
activity,
|
||||
act,
|
||||
walletSeed,
|
||||
restoreHeightText,
|
||||
useOffset
|
||||
|
@ -288,10 +331,9 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||
Toast.makeText(
|
||||
activity,
|
||||
getString(R.string.node_selected),
|
||||
getString(R.string.node_selected, node?.name ?: node?.host),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
refreshProxy()
|
||||
}
|
||||
|
||||
override fun onClickedEditNode(node: Node?) {}
|
||||
|
@ -310,10 +352,4 @@ class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListe
|
|||
dialog.show(fragmentManager, "node_selection_dialog")
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshProxy() {
|
||||
val proxyAddress = walletProxyAddressEditText?.text.toString()
|
||||
val proxyPort = walletProxyPortEditText?.text.toString()
|
||||
ProxyService.instance?.updateProxy(proxyAddress, proxyPort)
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package net.mynero.wallet.fragment.onboarding
|
||||
|
||||
import android.app.Activity
|
||||
import android.util.Patterns
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
@ -9,7 +8,7 @@ import androidx.lifecycle.ViewModel
|
|||
import net.mynero.wallet.MainActivity
|
||||
import net.mynero.wallet.MoneroApplication
|
||||
import net.mynero.wallet.R
|
||||
import net.mynero.wallet.livedata.combineLatestIgnoreNull
|
||||
import net.mynero.wallet.livedata.combineLiveDatas
|
||||
import net.mynero.wallet.model.Wallet
|
||||
import net.mynero.wallet.model.WalletManager
|
||||
import net.mynero.wallet.service.PrefService
|
||||
|
@ -30,11 +29,19 @@ class OnboardingViewModel : ViewModel() {
|
|||
private val _useBundledTor = MutableLiveData(false)
|
||||
val useBundledTor: LiveData<Boolean> = _useBundledTor
|
||||
private val _passphrase = MutableLiveData("")
|
||||
val passphrase: LiveData<String> = _passphrase
|
||||
private val _confirmedPassphrase = MutableLiveData("")
|
||||
private val _showMonerochan = MutableLiveData(true)
|
||||
val showMonerochan: LiveData<Boolean> = _showMonerochan
|
||||
var showMoreOptions: LiveData<Boolean> = _showMoreOptions
|
||||
var seedType: LiveData<SeedType> = _seedType
|
||||
|
||||
val enableButton = combineLatestIgnoreNull(
|
||||
init {
|
||||
_useProxy.value = ProxyService.instance?.usingProxy
|
||||
_useBundledTor.value = ProxyService.instance?.useBundledTor
|
||||
}
|
||||
|
||||
val enableButton = combineLiveDatas(
|
||||
seedType,
|
||||
_useProxy,
|
||||
_proxyAddress,
|
||||
|
@ -44,14 +51,14 @@ class OnboardingViewModel : ViewModel() {
|
|||
_confirmedPassphrase,
|
||||
_creatingWallet
|
||||
) { seedType, useProxy, proxyAddress, proxyPort, useBundledTor, passphrase, confirmedPassphrase, creatingWallet ->
|
||||
if(seedType == null || useProxy == null || proxyAddress == null || proxyPort == null || useBundledTor == null || passphrase == null || confirmedPassphrase == null || creatingWallet == null) return@combineLatestIgnoreNull false
|
||||
if((passphrase.isNotEmpty() || confirmedPassphrase.isNotEmpty()) && passphrase != confirmedPassphrase) return@combineLatestIgnoreNull false
|
||||
if(creatingWallet) return@combineLatestIgnoreNull false
|
||||
if(seedType == SeedType.POLYSEED && passphrase.isEmpty()) return@combineLatestIgnoreNull false
|
||||
if(useProxy && (proxyAddress.isEmpty() || proxyPort.isEmpty())) return@combineLatestIgnoreNull false
|
||||
if(useBundledTor && (proxyAddress.isEmpty() || proxyPort.isEmpty())) return@combineLatestIgnoreNull false
|
||||
if(seedType == null || useProxy == null || proxyAddress == null || proxyPort == null || useBundledTor == null || passphrase == null || confirmedPassphrase == null || creatingWallet == null) return@combineLiveDatas false
|
||||
if((passphrase.isNotEmpty() || confirmedPassphrase.isNotEmpty()) && passphrase != confirmedPassphrase) return@combineLiveDatas false
|
||||
if(creatingWallet) return@combineLiveDatas false
|
||||
if(seedType == SeedType.POLYSEED && (passphrase.isEmpty() || confirmedPassphrase.isEmpty())) return@combineLiveDatas false
|
||||
if(useProxy && (proxyAddress.isEmpty() || proxyPort.isEmpty())) return@combineLiveDatas false
|
||||
if(useBundledTor && (proxyAddress.isEmpty() || proxyPort.isEmpty())) return@combineLiveDatas false
|
||||
|
||||
return@combineLatestIgnoreNull true
|
||||
return@combineLiveDatas true
|
||||
}
|
||||
|
||||
fun onMoreOptionsClicked() {
|
||||
|
@ -72,7 +79,6 @@ class OnboardingViewModel : ViewModel() {
|
|||
) {
|
||||
val passphrase = _passphrase.value ?: return
|
||||
val confirmedPassphrase = _confirmedPassphrase.value ?: return
|
||||
val useProxy = _useProxy.value ?: return
|
||||
|
||||
val application = mainActivity.application as MoneroApplication
|
||||
_creatingWallet.postValue(true)
|
||||
|
@ -172,15 +178,6 @@ class OnboardingViewModel : ViewModel() {
|
|||
val ok = walletStatus?.isOk
|
||||
walletFile.delete() // cache is broken for some reason when recovering wallets. delete the file here. this happens in monerujo too.
|
||||
if (ok == true) {
|
||||
var editor = PrefService.instance?.edit()
|
||||
?.putBoolean(Constants.PREF_USE_BUNDLED_TOR, _useBundledTor.value == true)
|
||||
?.putBoolean(Constants.PREF_USES_PROXY, useProxy)
|
||||
if(useProxy) {
|
||||
editor = editor?.putString(Constants.PREF_PROXY, "${_proxyAddress.value}:${_proxyPort.value}")
|
||||
}
|
||||
|
||||
editor?.apply()
|
||||
|
||||
(mainActivity as MainActivity).init(walletFile, passphrase)
|
||||
mainActivity.runOnUiThread { mainActivity.onBackPressed() }
|
||||
} else {
|
||||
|
@ -228,18 +225,42 @@ class OnboardingViewModel : ViewModel() {
|
|||
|
||||
fun setProxyAddress(address: String) {
|
||||
_proxyAddress.value = address
|
||||
val port = _proxyPort.value ?: return
|
||||
val proxyAddress = "$address:$port"
|
||||
if(proxyAddress == ":") return
|
||||
PrefService.instance?.edit()?.putString(Constants.PREF_PROXY, proxyAddress)?.apply()
|
||||
}
|
||||
|
||||
fun setProxyPort(port: String) {
|
||||
_proxyPort.value = port
|
||||
val address = _proxyAddress.value ?: return
|
||||
val proxyAddress = "$address:$port"
|
||||
if(proxyAddress == ":") return
|
||||
PrefService.instance?.edit()?.putString(Constants.PREF_PROXY, proxyAddress)?.apply()
|
||||
}
|
||||
|
||||
fun setUseBundledTor(useBundled: Boolean) {
|
||||
_useBundledTor.value = useBundled
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USE_BUNDLED_TOR, useBundled)?.apply()
|
||||
|
||||
val samouraiTorManager = ProxyService.instance?.samouraiTorManager
|
||||
if(useBundled && useProxy.value == true) {
|
||||
samouraiTorManager?.start()
|
||||
} else {
|
||||
samouraiTorManager?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
fun setUseProxy(useProxy: Boolean) {
|
||||
_useProxy.value = useProxy
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USES_PROXY, useProxy)?.apply()
|
||||
|
||||
val samouraiTorManager = ProxyService.instance?.samouraiTorManager
|
||||
if(useProxy && useBundledTor.value == true) {
|
||||
samouraiTorManager?.start()
|
||||
} else {
|
||||
samouraiTorManager?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
fun setPassphrase(passphrase: String) {
|
||||
|
@ -250,6 +271,11 @@ class OnboardingViewModel : ViewModel() {
|
|||
_confirmedPassphrase.value = confirmedPassphrase
|
||||
}
|
||||
|
||||
fun setMonerochan(b: Boolean) {
|
||||
_showMonerochan.value = b
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_MONEROCHAN, b)?.apply()
|
||||
}
|
||||
|
||||
enum class SeedType(val descResId: Int) {
|
||||
LEGACY(R.string.seed_desc_legacy), POLYSEED(R.string.seed_desc_polyseed), UNKNOWN(0)
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ import android.widget.Button
|
|||
import android.widget.CheckBox
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.Switch
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
|
@ -17,6 +19,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
import net.mynero.wallet.R
|
||||
import net.mynero.wallet.data.Node
|
||||
import net.mynero.wallet.data.Node.Companion.fromJson
|
||||
|
@ -29,6 +32,7 @@ import net.mynero.wallet.fragment.dialog.NodeSelectionBottomSheetDialog.NodeSele
|
|||
import net.mynero.wallet.fragment.dialog.PasswordBottomSheetDialog
|
||||
import net.mynero.wallet.fragment.dialog.PasswordBottomSheetDialog.PasswordListener
|
||||
import net.mynero.wallet.fragment.dialog.WalletKeysBottomSheetDialog
|
||||
import net.mynero.wallet.model.EnumTorState
|
||||
import net.mynero.wallet.service.BalanceService
|
||||
import net.mynero.wallet.service.HistoryService
|
||||
import net.mynero.wallet.service.PrefService
|
||||
|
@ -44,6 +48,14 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
|||
private var selectNodeButton: Button? = null
|
||||
private var cachedProxyAddress: String = ""
|
||||
private var cachedProxyPort: String = ""
|
||||
private var streetModeSwitch: SwitchCompat? = null
|
||||
private var monerochanSwitch: SwitchCompat? = null
|
||||
private var donationSwitch: SwitchCompat? = null
|
||||
private var useBundledTor: CheckBox? = null
|
||||
private var displaySeedButton: Button? = null
|
||||
private var displayUtxosButton: Button? = null
|
||||
private var torSwitch: SwitchCompat? = null
|
||||
private var proxySettingsLayout: ConstraintLayout? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
|
@ -55,68 +67,76 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mViewModel = ViewModelProvider(this)[SettingsViewModel::class.java]
|
||||
val displaySeedButton = view.findViewById<Button>(R.id.display_seed_button)
|
||||
val displayUtxosButton = view.findViewById<Button>(R.id.display_utxos_button)
|
||||
displaySeedButton = view.findViewById(R.id.display_seed_button)
|
||||
displayUtxosButton = view.findViewById(R.id.display_utxos_button)
|
||||
selectNodeButton = view.findViewById(R.id.select_node_button)
|
||||
val streetModeSwitch = view.findViewById<SwitchCompat>(R.id.street_mode_switch)
|
||||
val monerochanSwitch = view.findViewById<SwitchCompat>(R.id.monerochan_switch)
|
||||
val donationSwitch = view.findViewById<SwitchCompat>(R.id.donate_per_tx_switch)
|
||||
val torSwitch = view.findViewById<SwitchCompat>(R.id.tor_switch)
|
||||
val proxySettingsLayout =
|
||||
view.findViewById<ConstraintLayout>(R.id.wallet_proxy_settings_layout)
|
||||
streetModeSwitch = view.findViewById(R.id.street_mode_switch)
|
||||
monerochanSwitch = view.findViewById(R.id.monerochan_switch)
|
||||
donationSwitch = view.findViewById(R.id.donate_per_tx_switch)
|
||||
torSwitch = view.findViewById(R.id.tor_switch)
|
||||
proxySettingsLayout = view.findViewById(R.id.wallet_proxy_settings_layout)
|
||||
walletProxyAddressEditText = view.findViewById(R.id.wallet_proxy_address_edittext)
|
||||
walletProxyPortEditText = view.findViewById(R.id.wallet_proxy_port_edittext)
|
||||
val useBundledTor = view.findViewById<CheckBox>(R.id.bundled_tor_checkbox)
|
||||
useBundledTor = view.findViewById(R.id.bundled_tor_checkbox)
|
||||
|
||||
useBundledTor.isChecked = ProxyService.instance?.useBundledTor == true
|
||||
walletProxyPortEditText?.visibility = if (useBundledTor.isChecked) View.GONE else View.VISIBLE
|
||||
walletProxyAddressEditText?.visibility = if (useBundledTor.isChecked) View.GONE else View.VISIBLE
|
||||
useBundledTor?.isChecked = ProxyService.instance?.useBundledTor == true
|
||||
walletProxyPortEditText?.visibility = if (useBundledTor?.isChecked == true) View.GONE else View.VISIBLE
|
||||
walletProxyAddressEditText?.visibility = if (useBundledTor?.isChecked == true) View.GONE else View.VISIBLE
|
||||
streetModeSwitch?.isChecked = PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) == true
|
||||
monerochanSwitch?.isChecked = PrefService.instance?.getBoolean(Constants.PREF_MONEROCHAN, true) == true
|
||||
donationSwitch?.isChecked = PrefService.instance?.getBoolean(Constants.PREF_DONATE_PER_TX, false) == true
|
||||
|
||||
streetModeSwitch.isChecked =
|
||||
PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) == true
|
||||
streetModeSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_STREET_MODE, b)?.apply()
|
||||
BalanceService.instance?.refreshBalance()
|
||||
}
|
||||
monerochanSwitch.isChecked =
|
||||
PrefService.instance?.getBoolean(Constants.PREF_MONEROCHAN, true) == true
|
||||
monerochanSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_MONEROCHAN, b)?.apply()
|
||||
HistoryService.instance?.refreshHistory()
|
||||
}
|
||||
donationSwitch.isChecked =
|
||||
PrefService.instance?.getBoolean(Constants.PREF_DONATE_PER_TX, false) == true
|
||||
donationSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_DONATE_PER_TX, b)?.apply()
|
||||
}
|
||||
val prefService = PrefService.instance ?: return
|
||||
val usesProxy = ProxyService.instance?.usingProxy == true
|
||||
cachedProxyAddress = ProxyService.instance?.proxyAddress ?: return
|
||||
cachedProxyPort = ProxyService.instance?.proxyPort ?: return
|
||||
if (ProxyService.instance?.hasProxySet() == true) {
|
||||
initProxyStuff(cachedProxyAddress, cachedProxyPort)
|
||||
}
|
||||
torSwitch.isChecked = usesProxy
|
||||
if (usesProxy) {
|
||||
proxySettingsLayout.visibility = View.VISIBLE
|
||||
} else {
|
||||
proxySettingsLayout.visibility = View.GONE
|
||||
}
|
||||
torSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
prefService.edit()?.putBoolean(Constants.PREF_USES_PROXY, b)?.apply()
|
||||
if (b) {
|
||||
if (ProxyService.instance?.hasProxySet() == true) {
|
||||
val proxyAddress = ProxyService.instance?.proxyAddress ?: return@setOnCheckedChangeListener
|
||||
val proxyPort = ProxyService.instance?.proxyPort ?: return@setOnCheckedChangeListener
|
||||
initProxyStuff(proxyAddress, proxyPort)
|
||||
}
|
||||
proxySettingsLayout.visibility = View.VISIBLE
|
||||
} else {
|
||||
proxySettingsLayout.visibility = View.GONE
|
||||
torSwitch?.isChecked = usesProxy
|
||||
proxySettingsLayout?.visibility = if (usesProxy) View.VISIBLE else View.GONE
|
||||
val node = PrefService.instance?.node // shouldn't use default value here
|
||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||
|
||||
bindListeners()
|
||||
bindObservers()
|
||||
}
|
||||
|
||||
private fun bindListeners() {
|
||||
val onBackPressedCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
refreshProxy()
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
displaySeedButton.setOnClickListener {
|
||||
}
|
||||
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, onBackPressedCallback)
|
||||
|
||||
donationSwitch?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_DONATE_PER_TX, b)?.apply()
|
||||
}
|
||||
|
||||
streetModeSwitch?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_STREET_MODE, b)?.apply()
|
||||
BalanceService.instance?.refreshBalance()
|
||||
}
|
||||
|
||||
monerochanSwitch?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_MONEROCHAN, b)?.apply()
|
||||
HistoryService.instance?.refreshHistory()
|
||||
}
|
||||
|
||||
selectNodeButton?.setOnClickListener {
|
||||
activity?.supportFragmentManager?.let { fragmentManager ->
|
||||
val dialog = NodeSelectionBottomSheetDialog()
|
||||
dialog.listener = this
|
||||
dialog.show(fragmentManager, "node_selection_dialog")
|
||||
}
|
||||
}
|
||||
|
||||
useBundledTor?.setOnCheckedChangeListener { _, isChecked ->
|
||||
mViewModel?.setUseBundledTor(isChecked)
|
||||
}
|
||||
|
||||
displaySeedButton?.setOnClickListener {
|
||||
val usesPassword =
|
||||
PrefService.instance?.getBoolean(Constants.PREF_USES_PASSWORD, false) == true
|
||||
if (usesPassword) {
|
||||
|
@ -130,37 +150,66 @@ class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListen
|
|||
displaySeedDialog("")
|
||||
}
|
||||
}
|
||||
displayUtxosButton.setOnClickListener { navigate(R.id.nav_to_utxos) }
|
||||
val node = PrefService.instance?.node // shouldn't use default value here
|
||||
selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
|
||||
selectNodeButton?.setOnClickListener {
|
||||
activity?.supportFragmentManager?.let { fragmentManager ->
|
||||
val dialog = NodeSelectionBottomSheetDialog()
|
||||
dialog.listener = this
|
||||
dialog.show(fragmentManager, "node_selection_dialog")
|
||||
|
||||
displayUtxosButton?.setOnClickListener { navigate(R.id.nav_to_utxos) }
|
||||
|
||||
torSwitch?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
|
||||
mViewModel?.setUseProxy(b)
|
||||
}
|
||||
}
|
||||
|
||||
useBundledTor?.setOnCheckedChangeListener { _, isChecked ->
|
||||
private fun bindObservers() {
|
||||
mViewModel?.useProxy?.observe(viewLifecycleOwner) { b ->
|
||||
if (b) {
|
||||
if (ProxyService.instance?.hasProxySet() == true) {
|
||||
val proxyAddress = ProxyService.instance?.proxyAddress ?: return@observe
|
||||
val proxyPort = ProxyService.instance?.proxyPort ?: return@observe
|
||||
initProxyStuff(proxyAddress, proxyPort)
|
||||
}
|
||||
proxySettingsLayout?.visibility = View.VISIBLE
|
||||
} else {
|
||||
proxySettingsLayout?.visibility = View.GONE
|
||||
}
|
||||
refreshProxy()
|
||||
}
|
||||
|
||||
mViewModel?.useBundledTor?.observe(viewLifecycleOwner) { isChecked ->
|
||||
walletProxyPortEditText?.visibility = if (isChecked) View.GONE else View.VISIBLE
|
||||
walletProxyAddressEditText?.visibility = if (isChecked) View.GONE else View.VISIBLE
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USE_BUNDLED_TOR, isChecked)?.apply()
|
||||
}
|
||||
|
||||
if(isChecked) {
|
||||
ProxyService.instance?.samouraiTorManager?.start()
|
||||
} else {
|
||||
ProxyService.instance?.samouraiTorManager?.stop()
|
||||
val samouraiTorManager = ProxyService.instance?.samouraiTorManager
|
||||
val indicatorCircle = view?.findViewById<CircularProgressIndicator>(R.id.settings_tor_loading_progressindicator)
|
||||
val torIcon = view?.findViewById<ImageView>(R.id.settings_tor_icon)
|
||||
|
||||
samouraiTorManager?.getTorStateLiveData()?.observe(viewLifecycleOwner) { state ->
|
||||
samouraiTorManager.getProxy()?.address()?.let { socketAddress ->
|
||||
if(socketAddress.toString().isEmpty()) return@let
|
||||
if(mViewModel?.useProxy?.value == true && mViewModel?.useBundledTor?.value == true) {
|
||||
torIcon?.visibility = View.VISIBLE
|
||||
indicatorCircle?.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
val onBackPressedCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
refreshProxy()
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
}
|
||||
indicatorCircle?.isIndeterminate = state.progressIndicator == 0
|
||||
indicatorCircle?.progress = state.progressIndicator
|
||||
|
||||
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, onBackPressedCallback)
|
||||
when (state.state) {
|
||||
EnumTorState.OFF -> {
|
||||
torIcon?.visibility = View.INVISIBLE
|
||||
indicatorCircle?.visibility = View.INVISIBLE
|
||||
}
|
||||
EnumTorState.STARTING -> {
|
||||
torIcon?.visibility = View.INVISIBLE
|
||||
indicatorCircle?.visibility = View.VISIBLE
|
||||
}
|
||||
EnumTorState.STOPPING -> {
|
||||
torIcon?.visibility = View.INVISIBLE
|
||||
indicatorCircle?.visibility = View.VISIBLE
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshProxy() {
|
||||
|
|
|
@ -1,12 +1,47 @@
|
|||
package net.mynero.wallet.fragment.settings
|
||||
|
||||
import android.util.Patterns
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import net.mynero.wallet.MoneroApplication
|
||||
import net.mynero.wallet.model.WalletManager
|
||||
import net.mynero.wallet.service.PrefService
|
||||
import net.mynero.wallet.service.ProxyService
|
||||
import net.mynero.wallet.util.Constants
|
||||
|
||||
class SettingsViewModel : ViewModel() {
|
||||
private val _useProxy = MutableLiveData(false)
|
||||
val useProxy: LiveData<Boolean> = _useProxy
|
||||
private val _useBundledTor = MutableLiveData(false)
|
||||
val useBundledTor: LiveData<Boolean> = _useBundledTor
|
||||
|
||||
init {
|
||||
_useProxy.value = ProxyService.instance?.usingProxy
|
||||
_useBundledTor.value = ProxyService.instance?.useBundledTor
|
||||
}
|
||||
|
||||
fun setUseProxy(use: Boolean) {
|
||||
_useProxy.value = use
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USES_PROXY, use)?.apply()
|
||||
|
||||
val samouraiTorManager = ProxyService.instance?.samouraiTorManager
|
||||
if(use && useBundledTor.value == true) {
|
||||
samouraiTorManager?.start()
|
||||
} else {
|
||||
samouraiTorManager?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
fun setUseBundledTor(use: Boolean) {
|
||||
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USE_BUNDLED_TOR, use)?.apply()
|
||||
_useBundledTor.value = use
|
||||
|
||||
val samouraiTorManager = ProxyService.instance?.samouraiTorManager
|
||||
if(use && useProxy.value == true) {
|
||||
samouraiTorManager?.start()
|
||||
} else {
|
||||
samouraiTorManager?.stop()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package net.mynero.wallet.livedata
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
|
||||
fun <T1, T2, T3, T4, T5, T6, T7, T8, S> combineLiveDatas(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
source4: LiveData<T4>,
|
||||
source5: LiveData<T5>,
|
||||
source6: LiveData<T6>,
|
||||
source7: LiveData<T7>,
|
||||
source8: LiveData<T8>,
|
||||
func: (T1?, T2?, T3?, T4?, T5?, T6?, T7?, T8?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source2) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source3) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source4) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source5) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source6) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source7) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source8) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -1,414 +0,0 @@
|
|||
package net.mynero.wallet.livedata
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
|
||||
fun <T1, T2, S> combineLatest(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
func: (T1?, T2?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
result.value = func.invoke(source1.value, source2.value)
|
||||
}
|
||||
result.addSource(source2) {
|
||||
result.value = func.invoke(source1.value, source2.value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, S> combineLatest(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
func: (T1?, T2?, T3?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value)
|
||||
}
|
||||
result.addSource(source2) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value)
|
||||
}
|
||||
result.addSource(source3) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, T4, S> combineLatest(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
source4: LiveData<T4>,
|
||||
func: (T1?, T2?, T3?, T4?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value)
|
||||
}
|
||||
result.addSource(source2) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value)
|
||||
}
|
||||
result.addSource(source3) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value)
|
||||
}
|
||||
result.addSource(source4) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, T4, T5, S> combineLatest(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
source4: LiveData<T4>,
|
||||
source5: LiveData<T5>,
|
||||
func: (T1?, T2?, T3?, T4?, T5?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value, source5.value)
|
||||
}
|
||||
result.addSource(source2) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value, source5.value)
|
||||
}
|
||||
result.addSource(source3) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value, source5.value)
|
||||
}
|
||||
result.addSource(source4) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value, source5.value)
|
||||
}
|
||||
result.addSource(source5) {
|
||||
result.value = func.invoke(source1.value, source2.value, source3.value, source4.value, source5.value)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, S> combineLatestIgnoreNull(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
func: (T1?, T2?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
func.invoke(source1.value, source2.value)?.run { result.value = this }
|
||||
}
|
||||
result.addSource(source2) {
|
||||
func.invoke(source1.value, source2.value)?.run { result.value = this }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, S> combineLatestIgnoreNull(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
func: (T1?, T2?, T3?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
func(source1.value, source2.value, source3.value)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source2) {
|
||||
func(source1.value, source2.value, source3.value)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source3) {
|
||||
func(source1.value, source2.value, source3.value)?.run { result.value = this }
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, T4, S> combineLatestIgnoreNull(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
source4: LiveData<T4>,
|
||||
func: (T1?, T2?, T3?, T4?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
func(source1.value, source2.value, source3.value, source4.value)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source2) {
|
||||
func(source1.value, source2.value, source3.value, source4.value)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source3) {
|
||||
func(source1.value, source2.value, source3.value, source4.value)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source4) {
|
||||
func(source1.value, source2.value, source3.value, source4.value)?.run { result.value = this }
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, T4, T5, S> combineLatestIgnoreNull(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
source4: LiveData<T4>,
|
||||
source5: LiveData<T5>,
|
||||
func: (T1?, T2?, T3?, T4?, T5?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source2) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source3) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source4) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source5) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, T4, T5, T6, S> combineLatestIgnoreNull(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
source4: LiveData<T4>,
|
||||
source5: LiveData<T5>,
|
||||
source6: LiveData<T6>,
|
||||
func: (T1?, T2?, T3?, T4?, T5?, T6?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source2) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source3) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source4) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source5) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source6) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, T4, T5, T6, T7, T8, S> combineLatestIgnoreNull(
|
||||
source1: LiveData<T1>,
|
||||
source2: LiveData<T2>,
|
||||
source3: LiveData<T3>,
|
||||
source4: LiveData<T4>,
|
||||
source5: LiveData<T5>,
|
||||
source6: LiveData<T6>,
|
||||
source7: LiveData<T7>,
|
||||
source8: LiveData<T8>,
|
||||
func: (T1?, T2?, T3?, T4?, T5?, T6?, T7?, T8?) -> S?
|
||||
): LiveData<S> {
|
||||
val result = MediatorLiveData<S>()
|
||||
result.addSource(source1) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source2) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source3) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source4) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source5) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source6) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source7) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
result.addSource(source8) {
|
||||
func(
|
||||
source1.value,
|
||||
source2.value,
|
||||
source3.value,
|
||||
source4.value,
|
||||
source5.value,
|
||||
source6.value,
|
||||
source7.value,
|
||||
source8.value
|
||||
)?.run { result.value = this }
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -17,10 +17,8 @@ class ProxyService(activity: MainActivity) : ServiceBase(null) {
|
|||
|
||||
activity.runOnUiThread {
|
||||
samouraiTorManager?.getTorStateLiveData()?.observeForever {
|
||||
println("STATE CHANGE:: ${it.state.name}")
|
||||
samouraiTorManager?.getProxy()?.address()?.let { socketAddress ->
|
||||
if(socketAddress.toString().isEmpty()) return@let
|
||||
println("PROXY INIT")
|
||||
val proxyString = socketAddress.toString().substring(1)
|
||||
val address = proxyString.split(":")[0]
|
||||
val port = proxyString.split(":")[1]
|
||||
|
|
|
@ -23,17 +23,38 @@
|
|||
android:paddingTop="24dp">
|
||||
<TextView
|
||||
android:id="@+id/create_wallet_textview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/create_wallet"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@id/wallet_password_edittext"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/onboarding_tor_loading_progressindicator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/onboarding_tor_icon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@drawable/tor"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="@id/onboarding_tor_loading_progressindicator"
|
||||
app:layout_constraintStart_toStartOf="@id/onboarding_tor_loading_progressindicator"
|
||||
app:layout_constraintTop_toTopOf="@id/onboarding_tor_loading_progressindicator"
|
||||
app:layout_constraintBottom_toBottomOf="@id/onboarding_tor_loading_progressindicator"/>
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/onboarding_tor_loading_progressindicator"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:indeterminate="true"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/create_wallet_textview"
|
||||
app:layout_constraintBottom_toBottomOf="@id/create_wallet_textview"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/wallet_password_edittext"
|
||||
android:layout_width="0dp"
|
||||
|
@ -248,7 +269,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp"
|
||||
android:text="@string/use_bundled_tor"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/wallet_proxy_address_edittext"
|
||||
|
@ -260,7 +280,6 @@
|
|||
android:background="@drawable/edittext_bg"
|
||||
android:hint="@string/wallet_proxy_address_hint"
|
||||
android:minHeight="48dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/wallet_proxy_port_edittext"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -275,7 +294,6 @@
|
|||
android:layout_marginTop="8dp"
|
||||
android:inputType="number"
|
||||
android:minHeight="48dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -19,9 +19,29 @@
|
|||
android:layout_marginEnd="24dp"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/settings_tor_loading_progressindicator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<ImageView
|
||||
android:id="@+id/settings_tor_icon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@drawable/tor"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="@id/settings_tor_loading_progressindicator"
|
||||
app:layout_constraintStart_toStartOf="@id/settings_tor_loading_progressindicator"
|
||||
app:layout_constraintTop_toTopOf="@id/settings_tor_loading_progressindicator"
|
||||
app:layout_constraintBottom_toBottomOf="@id/settings_tor_loading_progressindicator"/>
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/settings_tor_loading_progressindicator"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:indeterminate="true"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/settings_textview"
|
||||
app:layout_constraintBottom_toBottomOf="@id/settings_textview"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/wallet_settings_textview"
|
||||
|
|
Loading…
Reference in a new issue