Convert remaining screens to Kotlin

This commit is contained in:
pokkst 2023-12-06 17:48:45 -06:00
parent 2f400d7e8d
commit a1c43db4db
No known key found for this signature in database
GPG key ID: EC4FAAA66859FAA4
15 changed files with 965 additions and 988 deletions

View file

@ -40,8 +40,8 @@ class MainActivity : AppCompatActivity(), MoneroHandlerThread.Listener, Password
val walletKeysFile = File(applicationInfo.dataDir, Constants.WALLET_NAME + ".keys") val walletKeysFile = File(applicationInfo.dataDir, Constants.WALLET_NAME + ".keys")
if (walletKeysFile.exists()) { if (walletKeysFile.exists()) {
val promptPassword = val promptPassword =
PrefService.instance?.getBoolean(Constants.PREF_USES_PASSWORD, false) PrefService.instance?.getBoolean(Constants.PREF_USES_PASSWORD, false) == true
if (promptPassword == false) { if (!promptPassword) {
init(walletFile, "") init(walletFile, "")
} else { } else {
val passwordDialog = PasswordBottomSheetDialog() val passwordDialog = PasswordBottomSheetDialog()

View file

@ -96,7 +96,7 @@ class CoinsInfoAdapter(val listener: CoinsInfoAdapterListener?) :
} }
interface CoinsInfoAdapterListener { interface CoinsInfoAdapterListener {
fun onUtxoSelected(coinsInfo: CoinsInfo?) fun onUtxoSelected(coinsInfo: CoinsInfo)
} }
/** /**
@ -127,9 +127,9 @@ class CoinsInfoAdapter(val listener: CoinsInfoAdapterListener?) :
val globalIdxTextView = itemView.findViewById<TextView>(R.id.utxo_global_index_textview) val globalIdxTextView = itemView.findViewById<TextView>(R.id.utxo_global_index_textview)
val outpointTextView = itemView.findViewById<TextView>(R.id.utxo_outpoint_textview) val outpointTextView = itemView.findViewById<TextView>(R.id.utxo_outpoint_textview)
val streetModeEnabled = val streetModeEnabled =
PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) == true
val balanceString = val balanceString =
if (streetModeEnabled == true) Constants.STREET_MODE_BALANCE else Wallet.getDisplayAmount( if (streetModeEnabled) Constants.STREET_MODE_BALANCE else Wallet.getDisplayAmount(
coinsInfo.amount coinsInfo.amount
) )
amountTextView.text = amountTextView.text =
@ -167,7 +167,7 @@ class CoinsInfoAdapter(val listener: CoinsInfoAdapterListener?) :
if (!editing) return if (!editing) return
val unlocked = coinsInfo?.isUnlocked == true val unlocked = coinsInfo?.isUnlocked == true
if (unlocked) { if (unlocked) {
listener?.onUtxoSelected(coinsInfo) coinsInfo?.let { listener?.onUtxoSelected(it) }
} }
} }
@ -175,7 +175,7 @@ class CoinsInfoAdapter(val listener: CoinsInfoAdapterListener?) :
if (editing) return false if (editing) return false
val unlocked = coinsInfo?.isUnlocked == true val unlocked = coinsInfo?.isUnlocked == true
if (unlocked) { if (unlocked) {
listener?.onUtxoSelected(coinsInfo) coinsInfo?.let { listener?.onUtxoSelected(it) }
} }
return unlocked return unlocked
} }

View file

@ -91,8 +91,8 @@ class SubaddressAdapter(val listener: SubaddressAdapterListener?) :
val amount = subaddress.amount val amount = subaddress.amount
if (amount > 0) { if (amount > 0) {
val streetMode = val streetMode =
PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) == true
if (streetMode == true) { if (streetMode) {
addressAmountTextView.text = itemView.context.getString( addressAmountTextView.text = itemView.context.getString(
R.string.tx_list_amount_positive, R.string.tx_list_amount_positive,
Constants.STREET_MODE_BALANCE Constants.STREET_MODE_BALANCE

View file

@ -94,9 +94,9 @@ class TransactionInfoAdapter(val listener: TxInfoAdapterListener?) :
fun bind(txInfo: TransactionInfo) { fun bind(txInfo: TransactionInfo) {
val streetModeEnabled = val streetModeEnabled =
PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) == true
val displayAmount = val displayAmount =
if (streetModeEnabled == true) Constants.STREET_MODE_BALANCE else Helper.getDisplayAmount( if (streetModeEnabled) Constants.STREET_MODE_BALANCE else Helper.getDisplayAmount(
txInfo.amount, txInfo.amount,
Helper.DISPLAY_DIGITS_INFO Helper.DISPLAY_DIGITS_INFO
) )

View file

@ -30,17 +30,17 @@ class WalletKeysBottomSheetDialog : BottomSheetDialogFragment() {
val informationTextView = view.findViewById<TextView>(R.id.information_textview) // seed val informationTextView = view.findViewById<TextView>(R.id.information_textview) // seed
val viewKeyTextView = view.findViewById<TextView>(R.id.viewkey_textview) val viewKeyTextView = view.findViewById<TextView>(R.id.viewkey_textview)
val restoreHeightTextView = view.findViewById<TextView>(R.id.restore_height_textview) val restoreHeightTextView = view.findViewById<TextView>(R.id.restore_height_textview)
val wallet = WalletManager.instance!!.wallet val wallet = WalletManager.instance?.wallet
var seed = wallet!!.getSeed("") var seed = wallet?.getSeed("")
val usesOffset = PrefService.instance!!.getBoolean(Constants.PREF_USES_OFFSET, false) val usesOffset = PrefService.instance?.getBoolean(Constants.PREF_USES_OFFSET, false) == true
if (usesOffset) { if (usesOffset) {
seed = wallet.getSeed(password) seed = wallet?.getSeed(password)
view.findViewById<View>(R.id.wallet_seed_offset_textview).visibility = View.VISIBLE view.findViewById<View>(R.id.wallet_seed_offset_textview).visibility = View.VISIBLE
} }
val privateViewKey = wallet.getSecretViewKey() val privateViewKey = wallet?.getSecretViewKey()
informationTextView.text = seed informationTextView.text = seed
viewKeyTextView.text = privateViewKey viewKeyTextView.text = privateViewKey
restoreHeightTextView.text = "${wallet.getRestoreHeight()}" restoreHeightTextView.text = "${wallet?.getRestoreHeight()}"
copyViewKeyImageButton.setOnClickListener { copyViewKeyImageButton.setOnClickListener {
clipBoardCopy( clipBoardCopy(
context, "private view-key", privateViewKey context, "private view-key", privateViewKey

View file

@ -165,8 +165,9 @@ class HomeFragment : Fragment(), TxInfoAdapterListener {
val botImageView = view.findViewById<ImageView>(R.id.monerochan_imageview) val botImageView = view.findViewById<ImageView>(R.id.monerochan_imageview)
view.findViewById<View>(R.id.no_history_layout).visibility = view.findViewById<View>(R.id.no_history_layout).visibility =
if (display) View.VISIBLE else View.GONE if (display) View.VISIBLE else View.GONE
val displayMonerochan = PrefService.instance?.getBoolean(Constants.PREF_MONEROCHAN, true) val displayMonerochan =
if (displayMonerochan == true) { PrefService.instance?.getBoolean(Constants.PREF_MONEROCHAN, true) == true
if (displayMonerochan) {
botImageView.visibility = View.VISIBLE botImageView.visibility = View.VISIBLE
mnrjTextView.visibility = View.VISIBLE mnrjTextView.visibility = View.VISIBLE
textView.visibility = View.GONE textView.visibility = View.GONE

View file

@ -1,326 +1,297 @@
package net.mynero.wallet.fragment.onboarding; package net.mynero.wallet.fragment.onboarding
import android.app.Activity; import android.app.Activity
import android.os.Bundle; import android.os.Bundle
import android.text.Editable; import android.text.Editable
import android.text.TextWatcher; import android.text.TextWatcher
import android.util.Patterns; import android.util.Patterns
import android.view.LayoutInflater; import android.view.LayoutInflater
import android.view.View; import android.view.View
import android.view.ViewGroup; import android.view.ViewGroup
import android.widget.Button; import android.widget.Button
import android.widget.CheckBox; import android.widget.CheckBox
import android.widget.EditText; import android.widget.CompoundButton
import android.widget.ImageView; import android.widget.EditText
import android.widget.TextView; import android.widget.ImageView
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.widget.SwitchCompat
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import net.mynero.wallet.MoneroApplication
import net.mynero.wallet.R
import net.mynero.wallet.data.Node
import net.mynero.wallet.fragment.dialog.AddNodeBottomSheetDialog
import net.mynero.wallet.fragment.dialog.AddNodeBottomSheetDialog.AddNodeListener
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.util.Constants
import androidx.activity.OnBackPressedCallback; class OnboardingFragment : Fragment(), NodeSelectionDialogListener, AddNodeListener {
import androidx.annotation.NonNull; private var useOffset = true
import androidx.annotation.Nullable; private var mViewModel: OnboardingViewModel? = null
import androidx.appcompat.widget.SwitchCompat; private var proxyAddressListener: TextWatcher = object : TextWatcher {
import androidx.constraintlayout.widget.ConstraintLayout; override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
import androidx.fragment.app.Fragment; override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
import androidx.fragment.app.FragmentActivity; override fun afterTextChanged(editable: Editable) {
import androidx.lifecycle.ViewModelProvider;
import net.mynero.wallet.MoneroApplication;
import net.mynero.wallet.R;
import net.mynero.wallet.data.Node;
import net.mynero.wallet.fragment.dialog.AddNodeBottomSheetDialog;
import net.mynero.wallet.fragment.dialog.NodeSelectionBottomSheetDialog;
import net.mynero.wallet.service.PrefService;
import net.mynero.wallet.util.Constants;
public class OnboardingFragment extends Fragment implements NodeSelectionBottomSheetDialog.NodeSelectionDialogListener, AddNodeBottomSheetDialog.AddNodeListener {
private boolean useOffset = true;
private OnboardingViewModel mViewModel;
TextWatcher proxyAddressListener = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (mViewModel != null) { if (mViewModel != null) {
mViewModel.setProxyAddress(editable.toString()); mViewModel?.setProxyAddress(editable.toString())
mViewModel.updateProxy(((MoneroApplication) getActivity().getApplication())); mViewModel?.updateProxy(activity?.application as MoneroApplication)
} }
} }
};
TextWatcher proxyPortListener = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
} }
private var proxyPortListener: TextWatcher = object : TextWatcher {
@Override override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
} override fun afterTextChanged(editable: Editable) {
@Override
public void afterTextChanged(Editable editable) {
if (mViewModel != null) { if (mViewModel != null) {
mViewModel.setProxyPort(editable.toString()); mViewModel?.setProxyPort(editable.toString())
mViewModel.updateProxy(((MoneroApplication) getActivity().getApplication())); mViewModel?.updateProxy(activity?.application as MoneroApplication)
} }
} }
}; }
private EditText walletProxyAddressEditText; private var walletProxyAddressEditText: EditText? = null
private EditText walletProxyPortEditText; private var walletProxyPortEditText: EditText? = null
private EditText walletPasswordEditText; private var walletPasswordEditText: EditText? = null
private EditText walletPasswordConfirmEditText; private var walletPasswordConfirmEditText: EditText? = null
private EditText walletSeedEditText; private var walletSeedEditText: EditText? = null
private EditText walletRestoreHeightEditText; private var walletRestoreHeightEditText: EditText? = null
private Button createWalletButton; private var createWalletButton: Button? = null
private TextView moreOptionsDropdownTextView; private var moreOptionsDropdownTextView: TextView? = null
private SwitchCompat torSwitch; private var torSwitch: SwitchCompat? = null
private ConstraintLayout advancedOptionsLayout; private var advancedOptionsLayout: ConstraintLayout? = null
private ImageView moreOptionsChevronImageView; private var moreOptionsChevronImageView: ImageView? = null
private CheckBox seedOffsetCheckbox; private var seedOffsetCheckbox: CheckBox? = null
private Button selectNodeButton; private var selectNodeButton: Button? = null
private SwitchCompat showXmrchanSwitch; private var showXmrchanSwitch: SwitchCompat? = null
private ImageView xmrchanOnboardingImage; private var xmrchanOnboardingImage: ImageView? = null
private Button seedTypeButton; private var seedTypeButton: Button? = null
private TextView seedTypeDescTextView; private var seedTypeDescTextView: TextView? = null
override fun onCreateView(
@Override inflater: LayoutInflater, container: ViewGroup?,
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, savedInstanceState: Bundle?
@Nullable Bundle savedInstanceState) { ): View? {
return inflater.inflate(R.layout.fragment_onboarding, container, false); return inflater.inflate(R.layout.fragment_onboarding, container, false)
} }
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState)
super.onViewCreated(view, savedInstanceState); mViewModel = ViewModelProvider(this)[OnboardingViewModel::class.java]
mViewModel = new ViewModelProvider(this).get(OnboardingViewModel.class); selectNodeButton = view.findViewById(R.id.select_node_button)
selectNodeButton = view.findViewById(R.id.select_node_button); walletPasswordEditText = view.findViewById(R.id.wallet_password_edittext)
walletPasswordEditText = view.findViewById(R.id.wallet_password_edittext); walletPasswordConfirmEditText = view.findViewById(R.id.wallet_password_confirm_edittext)
walletPasswordConfirmEditText = view.findViewById(R.id.wallet_password_confirm_edittext); walletSeedEditText = view.findViewById(R.id.wallet_seed_edittext)
walletSeedEditText = view.findViewById(R.id.wallet_seed_edittext); walletRestoreHeightEditText = view.findViewById(R.id.wallet_restore_height_edittext)
walletRestoreHeightEditText = view.findViewById(R.id.wallet_restore_height_edittext); createWalletButton = view.findViewById(R.id.create_wallet_button)
createWalletButton = view.findViewById(R.id.create_wallet_button); moreOptionsDropdownTextView = view.findViewById(R.id.advanced_settings_dropdown_textview)
moreOptionsDropdownTextView = view.findViewById(R.id.advanced_settings_dropdown_textview); moreOptionsChevronImageView = view.findViewById(R.id.advanced_settings_chevron_imageview)
moreOptionsChevronImageView = view.findViewById(R.id.advanced_settings_chevron_imageview); torSwitch = view.findViewById(R.id.tor_onboarding_switch)
torSwitch = view.findViewById(R.id.tor_onboarding_switch); seedOffsetCheckbox = view.findViewById(R.id.seed_offset_checkbox)
seedOffsetCheckbox = view.findViewById(R.id.seed_offset_checkbox); walletProxyAddressEditText = view.findViewById(R.id.wallet_proxy_address_edittext)
walletProxyAddressEditText = view.findViewById(R.id.wallet_proxy_address_edittext); walletProxyPortEditText = view.findViewById(R.id.wallet_proxy_port_edittext)
walletProxyPortEditText = view.findViewById(R.id.wallet_proxy_port_edittext); advancedOptionsLayout = view.findViewById(R.id.more_options_layout)
advancedOptionsLayout = view.findViewById(R.id.more_options_layout); showXmrchanSwitch = view.findViewById(R.id.show_xmrchan_switch)
showXmrchanSwitch = view.findViewById(R.id.show_xmrchan_switch); xmrchanOnboardingImage = view.findViewById(R.id.xmrchan_onboarding_imageview)
xmrchanOnboardingImage = view.findViewById(R.id.xmrchan_onboarding_imageview); seedTypeButton = view.findViewById(R.id.seed_type_button)
seedTypeButton = view.findViewById(R.id.seed_type_button); seedTypeDescTextView = view.findViewById(R.id.seed_type_desc_textview)
seedTypeDescTextView = view.findViewById(R.id.seed_type_desc_textview); bindListeners()
bindObservers()
bindListeners();
bindObservers();
} }
private void bindObservers() { private fun bindObservers() {
mViewModel.showMoreOptions.observe(getViewLifecycleOwner(), show -> { mViewModel?.showMoreOptions?.observe(viewLifecycleOwner) { show: Boolean ->
if (show) { if (show) {
moreOptionsChevronImageView.setImageResource(R.drawable.ic_keyboard_arrow_up); moreOptionsChevronImageView?.setImageResource(R.drawable.ic_keyboard_arrow_up)
advancedOptionsLayout.setVisibility(View.VISIBLE); advancedOptionsLayout?.visibility = View.VISIBLE
} else { } else {
moreOptionsChevronImageView.setImageResource(R.drawable.ic_keyboard_arrow_down); moreOptionsChevronImageView?.setImageResource(R.drawable.ic_keyboard_arrow_down)
advancedOptionsLayout.setVisibility(View.GONE); advancedOptionsLayout?.visibility = View.GONE
} }
}); }
mViewModel?.enableCreateButton?.observe(viewLifecycleOwner) { enable: Boolean ->
mViewModel.enableCreateButton.observe(getViewLifecycleOwner(), enable -> { createWalletButton?.isEnabled = enable
createWalletButton.setEnabled(enable); }
}); mViewModel?.seedType?.observe(viewLifecycleOwner) { seedType: SeedType ->
seedTypeButton?.text = seedType.toString()
mViewModel.seedType.observe(getViewLifecycleOwner(), seedType -> { seedTypeDescTextView?.text = getText(seedType.descResId)
seedTypeButton.setText(seedType.toString()); if (seedType == SeedType.LEGACY) {
seedTypeDescTextView.setText(getText(seedType.getDescResId())); seedOffsetCheckbox?.visibility = View.VISIBLE
if (seedType == OnboardingViewModel.SeedType.LEGACY) { walletRestoreHeightEditText?.visibility = View.VISIBLE
seedOffsetCheckbox.setVisibility(View.VISIBLE); walletPasswordEditText?.hint = getString(R.string.password_optional)
walletRestoreHeightEditText.setVisibility(View.VISIBLE);
walletPasswordEditText.setHint(getString(R.string.password_optional));
} else { } else {
seedOffsetCheckbox.setVisibility(View.GONE); seedOffsetCheckbox?.visibility = View.GONE
walletRestoreHeightEditText.setVisibility(View.GONE); walletRestoreHeightEditText?.visibility = View.GONE
walletPasswordEditText.setHint(getString(R.string.password_non_optional)); walletPasswordEditText?.hint = getString(R.string.password_non_optional)
}
} }
});
} }
private void bindListeners() { private fun bindListeners() {
seedOffsetCheckbox.setChecked(useOffset); seedOffsetCheckbox?.isChecked = useOffset
// Disable onBack click // Disable onBack click
OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { val onBackPressedCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) {
@Override override fun handleOnBackPressed() {}
public void handleOnBackPressed() {
} }
}; val activity = activity
FragmentActivity activity = getActivity(); activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, onBackPressedCallback)
if (activity != null) moreOptionsDropdownTextView?.setOnClickListener { mViewModel?.onMoreOptionsClicked() }
activity.getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), onBackPressedCallback); moreOptionsChevronImageView?.setOnClickListener { mViewModel?.onMoreOptionsClicked() }
seedOffsetCheckbox?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
moreOptionsDropdownTextView.setOnClickListener(view12 -> mViewModel.onMoreOptionsClicked()); useOffset = b
moreOptionsChevronImageView.setOnClickListener(view12 -> mViewModel.onMoreOptionsClicked()); }
seedOffsetCheckbox.setOnCheckedChangeListener((compoundButton, b) -> useOffset = b); createWalletButton?.setOnClickListener {
prepareDefaultNode()
createWalletButton.setOnClickListener(view1 -> { onBackPressedCallback.isEnabled = false
prepareDefaultNode(); (getActivity()?.application as MoneroApplication).executor?.execute {
onBackPressedCallback.setEnabled(false);
((MoneroApplication) getActivity().getApplication()).getExecutor().execute(() -> {
createOrImportWallet( createOrImportWallet(
walletPasswordEditText.getText().toString(), walletPasswordEditText?.text.toString(),
walletPasswordConfirmEditText.getText().toString(), walletPasswordConfirmEditText?.text.toString(),
walletSeedEditText.getText().toString().trim(), walletSeedEditText?.text.toString().trim { it <= ' ' },
walletRestoreHeightEditText.getText().toString().trim() walletRestoreHeightEditText?.text.toString().trim { it <= ' ' }
); )
});
});
walletPasswordEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
} }
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
} }
walletPasswordEditText?.addTextChangedListener(object : TextWatcher {
@Override override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
public void afterTextChanged(Editable editable) { override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
String text = editable.toString(); override fun afterTextChanged(editable: Editable) {
val text = editable.toString()
if (text.isEmpty()) { if (text.isEmpty()) {
walletPasswordConfirmEditText.setText(null); walletPasswordConfirmEditText?.text = null
walletPasswordConfirmEditText.setVisibility(View.GONE); walletPasswordConfirmEditText?.visibility = View.GONE
} else { } else {
walletPasswordConfirmEditText.setVisibility(View.VISIBLE); walletPasswordConfirmEditText?.visibility = View.VISIBLE
} }
} }
}); })
walletSeedEditText.addTextChangedListener(new TextWatcher() { walletSeedEditText?.addTextChangedListener(object : TextWatcher {
@Override override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
} override fun afterTextChanged(editable: Editable) {
val text = editable.toString()
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
String text = editable.toString();
if (text.isEmpty()) { if (text.isEmpty()) {
createWalletButton.setText(R.string.create_wallet); createWalletButton?.setText(R.string.create_wallet)
} else { } else {
createWalletButton.setText(R.string.menu_restore); createWalletButton?.setText(R.string.menu_restore)
} }
} }
}); })
seedTypeButton?.setOnClickListener { toggleSeedType() }
seedTypeButton.setOnClickListener(v -> toggleSeedType()); torSwitch?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USES_TOR, b)?.apply()
torSwitch.setOnCheckedChangeListener((compoundButton, b) -> { removeProxyTextListeners()
PrefService.getInstance().edit().putBoolean(Constants.PREF_USES_TOR, b).apply();
removeProxyTextListeners();
if (b) { if (b) {
if (PrefService.getInstance().hasProxySet()) { if (PrefService.instance?.hasProxySet() == true) {
String proxyAddress = PrefService.getInstance().getProxyAddress(); val proxyAddress =
String proxyPort = PrefService.getInstance().getProxyPort(); PrefService.instance?.proxyAddress ?: return@setOnCheckedChangeListener
initProxyStuff(proxyAddress, proxyPort); val proxyPort =
PrefService.instance?.proxyPort ?: return@setOnCheckedChangeListener
initProxyStuff(proxyAddress, proxyPort)
} else { } else {
initProxyStuff("127.0.0.1", "9050"); initProxyStuff("127.0.0.1", "9050")
} }
addProxyTextListeners(); addProxyTextListeners()
} }
mViewModel?.updateProxy(getActivity()?.application as MoneroApplication)
mViewModel.updateProxy(((MoneroApplication) getActivity().getApplication())); }
}); showXmrchanSwitch?.isChecked =
PrefService.instance?.getBoolean(Constants.PREF_MONEROCHAN, true) == true
showXmrchanSwitch.setChecked(PrefService.getInstance().getBoolean(Constants.PREF_MONEROCHAN, true)); showXmrchanSwitch?.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
showXmrchanSwitch.setOnCheckedChangeListener((compoundButton, b) -> { PrefService.instance?.edit()?.putBoolean(Constants.PREF_MONEROCHAN, b)?.apply()
PrefService.getInstance().edit().putBoolean(Constants.PREF_MONEROCHAN, b).apply();
if (b) { if (b) {
xmrchanOnboardingImage.setVisibility(View.VISIBLE); xmrchanOnboardingImage?.visibility = View.VISIBLE
} else { } else {
xmrchanOnboardingImage.setVisibility(View.GONE); xmrchanOnboardingImage?.visibility = View.GONE
}
}
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()
dialog.listener = this
dialog.show(fragmentManager, "node_selection_dialog")
}
} }
});
Node node = PrefService.getInstance().getNode(); // should be using default here
selectNodeButton.setText(getString(R.string.node_button_text, node.getAddress()));
selectNodeButton.setOnClickListener(view1 -> {
NodeSelectionBottomSheetDialog dialog = new NodeSelectionBottomSheetDialog();
dialog.listener = this;
dialog.show(getActivity().getSupportFragmentManager(), "node_selection_dialog");
});
} }
private void toggleSeedType() { private fun toggleSeedType() {
OnboardingViewModel.SeedType seedType = mViewModel.seedType.getValue(); val seedType = mViewModel?.seedType?.value ?: return
if (seedType == null) return; var newSeedType = SeedType.UNKNOWN
OnboardingViewModel.SeedType newSeedType = OnboardingViewModel.SeedType.UNKNOWN; if (seedType == SeedType.POLYSEED) {
if (seedType == OnboardingViewModel.SeedType.POLYSEED) { newSeedType = SeedType.LEGACY
newSeedType = OnboardingViewModel.SeedType.LEGACY; } else if (seedType == SeedType.LEGACY) {
} else if (seedType == OnboardingViewModel.SeedType.LEGACY) { newSeedType = SeedType.POLYSEED
newSeedType = OnboardingViewModel.SeedType.POLYSEED; }
mViewModel?.setSeedType(newSeedType)
} }
mViewModel.setSeedType(newSeedType); private fun prepareDefaultNode() {
PrefService.instance?.node
} }
private void prepareDefaultNode() { private fun createOrImportWallet(
PrefService.getInstance().getNode(); walletPassword: String,
} confirmedPassword: String,
walletSeed: String,
private void createOrImportWallet(String walletPassword, String confirmedPassword, String walletSeed, String restoreHeightText) { restoreHeightText: String
Activity activity = getActivity(); ) {
val activity: Activity? = activity
if (activity != null) { if (activity != null) {
mViewModel.createOrImportWallet(activity, walletPassword, confirmedPassword, walletSeed, restoreHeightText, useOffset); mViewModel?.createOrImportWallet(
activity,
walletPassword,
confirmedPassword,
walletSeed,
restoreHeightText,
useOffset
)
} }
} }
private void removeProxyTextListeners() { private fun removeProxyTextListeners() {
walletProxyAddressEditText.removeTextChangedListener(proxyAddressListener); walletProxyAddressEditText?.removeTextChangedListener(proxyAddressListener)
walletProxyPortEditText.removeTextChangedListener(proxyPortListener); walletProxyPortEditText?.removeTextChangedListener(proxyPortListener)
} }
private void addProxyTextListeners() { private fun addProxyTextListeners() {
walletProxyAddressEditText.addTextChangedListener(proxyAddressListener); walletProxyAddressEditText?.addTextChangedListener(proxyAddressListener)
walletProxyPortEditText.addTextChangedListener(proxyPortListener); walletProxyPortEditText?.addTextChangedListener(proxyPortListener)
} }
private void initProxyStuff(String proxyAddress, String proxyPort) { private fun initProxyStuff(proxyAddress: String, proxyPort: String) {
boolean validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches(); val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
if (validIpAddress) { if (validIpAddress) {
mViewModel.setProxyAddress(proxyAddress); mViewModel?.setProxyAddress(proxyAddress)
mViewModel.setProxyPort(proxyPort); mViewModel?.setProxyPort(proxyPort)
walletProxyAddressEditText.setText(proxyAddress); walletProxyAddressEditText?.setText(proxyAddress)
walletProxyPortEditText.setText(proxyPort); walletProxyPortEditText?.setText(proxyPort)
} }
} }
@Override override fun onNodeSelected() {
public void onNodeSelected() { val node = PrefService.instance?.node
Node node = PrefService.getInstance().getNode(); selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
selectNodeButton.setText(getString(R.string.node_button_text, node.getAddress())); mViewModel?.updateProxy(activity?.application as MoneroApplication)
mViewModel.updateProxy(((MoneroApplication) getActivity().getApplication()));
} }
@Override override fun onClickedEditNode(node: Node?) {}
public void onClickedEditNode(Node node) { override fun onClickedAddNode() {
activity?.supportFragmentManager?.let { fragmentManager ->
val addNodeDialog = AddNodeBottomSheetDialog()
addNodeDialog.listener = this
addNodeDialog.show(fragmentManager, "add_node_dialog")
}
} }
@Override override fun onNodeAdded() {
public void onClickedAddNode() { activity?.supportFragmentManager?.let { fragmentManager ->
AddNodeBottomSheetDialog addNodeDialog = new AddNodeBottomSheetDialog(); val dialog = NodeSelectionBottomSheetDialog()
addNodeDialog.listener = this; dialog.listener = this
addNodeDialog.show(getActivity().getSupportFragmentManager(), "add_node_dialog"); dialog.show(fragmentManager, "node_selection_dialog")
} }
@Override
public void onNodeAdded() {
NodeSelectionBottomSheetDialog dialog = new NodeSelectionBottomSheetDialog();
dialog.listener = this;
dialog.show(getActivity().getSupportFragmentManager(), "node_selection_dialog");
} }
} }

View file

@ -1,179 +1,211 @@
package net.mynero.wallet.fragment.onboarding; package net.mynero.wallet.fragment.onboarding
import android.app.Activity; import android.app.Activity
import android.util.Patterns; import android.util.Patterns
import android.widget.Toast; import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import net.mynero.wallet.MainActivity
import net.mynero.wallet.MoneroApplication
import net.mynero.wallet.R
import net.mynero.wallet.model.Wallet
import net.mynero.wallet.model.WalletManager
import net.mynero.wallet.service.PrefService
import net.mynero.wallet.util.Constants
import net.mynero.wallet.util.RestoreHeight
import java.io.File
import java.util.Calendar
import androidx.lifecycle.LiveData; class OnboardingViewModel : ViewModel() {
import androidx.lifecycle.MutableLiveData; private val _showMoreOptions = MutableLiveData(false)
import androidx.lifecycle.ViewModel; private val _enableCreateButton = MutableLiveData(true)
private val _seedType = MutableLiveData(SeedType.POLYSEED)
import net.mynero.wallet.MainActivity; var showMoreOptions: LiveData<Boolean> = _showMoreOptions
import net.mynero.wallet.MoneroApplication; var enableCreateButton: LiveData<Boolean> = _enableCreateButton
import net.mynero.wallet.R; var seedType: LiveData<SeedType> = _seedType
import net.mynero.wallet.model.Wallet; private var proxyAddress = ""
import net.mynero.wallet.model.WalletManager; private var proxyPort = ""
import net.mynero.wallet.service.PrefService; fun onMoreOptionsClicked() {
import net.mynero.wallet.util.Constants; val currentValue = showMoreOptions.value ?: false
import net.mynero.wallet.util.RestoreHeight; val newValue = !currentValue
_showMoreOptions.value = newValue
import java.io.File;
import java.util.Calendar;
public class OnboardingViewModel extends ViewModel {
private final MutableLiveData<Boolean> _showMoreOptions = new MutableLiveData<>(false);
private final MutableLiveData<Boolean> _enableCreateButton = new MutableLiveData<>(true);
private final MutableLiveData<SeedType> _seedType = new MutableLiveData<>(SeedType.POLYSEED);
public LiveData<Boolean> showMoreOptions = _showMoreOptions;
public LiveData<Boolean> enableCreateButton = _enableCreateButton;
public LiveData<SeedType> seedType = _seedType;
private String proxyAddress = "";
private String proxyPort = "";
public void onMoreOptionsClicked() {
boolean currentValue = showMoreOptions.getValue() != null ? showMoreOptions.getValue() : false;
boolean newValue = !currentValue;
_showMoreOptions.setValue(newValue);
} }
public void updateProxy(MoneroApplication application) { fun updateProxy(application: MoneroApplication) {
application.getExecutor().execute(() -> { application.executor?.execute {
boolean usesProxy = PrefService.getInstance().getBoolean(Constants.PREF_USES_TOR, false); val usesProxy = PrefService.instance?.getBoolean(Constants.PREF_USES_TOR, false) == true
if (!usesProxy) { if (!usesProxy) {
return; return@execute
} }
if (proxyAddress.isEmpty()) proxyAddress = "127.0.0.1"
if (proxyAddress.isEmpty()) proxyAddress = "127.0.0.1"; if (proxyPort.isEmpty()) proxyPort = "9050"
if (proxyPort.isEmpty()) proxyPort = "9050"; val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
boolean validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches();
if (validIpAddress) { if (validIpAddress) {
String proxy = proxyAddress + ":" + proxyPort; val proxy = "$proxyAddress:$proxyPort"
PrefService.getInstance().edit().putString(Constants.PREF_PROXY, proxy).apply(); PrefService.instance?.edit()?.putString(Constants.PREF_PROXY, proxy)?.apply()
}
} }
});
} }
public void setSeedType(SeedType seedType) { fun setSeedType(seedType: SeedType?) {
this._seedType.setValue(seedType); _seedType.value = seedType
} }
fun setProxyAddress(address: String) {
public void setProxyAddress(String address) { proxyAddress = address
this.proxyAddress = address;
} }
public void setProxyPort(String port) { fun setProxyPort(port: String) {
this.proxyPort = port; proxyPort = port
} }
public void createOrImportWallet(Activity mainActivity, String walletPassword, String confirmedPassword, String walletSeed, String restoreHeightText, boolean useOffset) { fun createOrImportWallet(
MoneroApplication application = (MoneroApplication) mainActivity.getApplication(); mainActivity: Activity,
application.getExecutor().execute(() -> { walletPassword: String,
_enableCreateButton.postValue(false); confirmedPassword: String,
String offset = useOffset ? walletPassword : ""; walletSeed: String,
if (!walletPassword.isEmpty()) { restoreHeightText: String,
if (!walletPassword.equals(confirmedPassword)) { useOffset: Boolean
_enableCreateButton.postValue(true); ) {
mainActivity.runOnUiThread(() -> Toast.makeText(mainActivity, application.getString(R.string.invalid_confirmed_password), Toast.LENGTH_SHORT).show()); val application = mainActivity.application as MoneroApplication
return; application.executor?.execute {
_enableCreateButton.postValue(false)
val offset = if (useOffset) walletPassword else ""
if (walletPassword.isNotEmpty()) {
if (walletPassword != confirmedPassword) {
_enableCreateButton.postValue(true)
mainActivity.runOnUiThread {
Toast.makeText(
mainActivity,
application.getString(R.string.invalid_confirmed_password),
Toast.LENGTH_SHORT
).show()
} }
PrefService.getInstance().edit().putBoolean(Constants.PREF_USES_PASSWORD, true).apply(); return@execute
} }
long restoreHeight = getNewRestoreHeight(); PrefService.instance?.edit()?.putBoolean(Constants.PREF_USES_PASSWORD, true)
File walletFile = new File(mainActivity.getApplicationInfo().dataDir, Constants.WALLET_NAME); ?.apply()
Wallet wallet = null; }
if (!offset.isEmpty()) { var restoreHeight = newRestoreHeight
PrefService.getInstance().edit().putBoolean(Constants.PREF_USES_OFFSET, true).apply(); val walletFile = File(mainActivity.applicationInfo.dataDir, Constants.WALLET_NAME)
var wallet: Wallet? = null
if (offset.isNotEmpty()) {
PrefService.instance?.edit()?.putBoolean(Constants.PREF_USES_OFFSET, true)?.apply()
} }
if (walletSeed.isEmpty()) { if (walletSeed.isEmpty()) {
SeedType seedTypeValue = seedType.getValue(); val seedTypeValue = seedType.value ?: return@execute
if (seedTypeValue == null) return;
if (seedTypeValue == SeedType.POLYSEED) { if (seedTypeValue == SeedType.POLYSEED) {
if (offset.isEmpty()) { wallet = if (offset.isEmpty()) {
mainActivity.runOnUiThread(() -> { mainActivity.runOnUiThread {
_enableCreateButton.postValue(true); _enableCreateButton.postValue(true)
Toast.makeText(mainActivity, application.getString(R.string.invalid_empty_passphrase), Toast.LENGTH_SHORT).show(); Toast.makeText(
}); mainActivity,
return; application.getString(R.string.invalid_empty_passphrase),
Toast.LENGTH_SHORT
).show()
}
return@execute
} else { } else {
wallet = WalletManager.getInstance().createWalletPolyseed(walletFile, walletPassword, offset, Constants.MNEMONIC_LANGUAGE); WalletManager.instance?.createWalletPolyseed(
walletFile,
walletPassword,
offset,
Constants.MNEMONIC_LANGUAGE
)
} }
} else if (seedTypeValue == SeedType.LEGACY) { } else if (seedTypeValue == SeedType.LEGACY) {
File tmpWalletFile = new File(mainActivity.getApplicationInfo().dataDir, Constants.WALLET_NAME + "_tmp"); val tmpWalletFile =
Wallet tmpWallet = createTempWallet(tmpWalletFile); //we do this to get seed, then recover wallet so we can use seed offset File(mainActivity.applicationInfo.dataDir, Constants.WALLET_NAME + "_tmp")
wallet = WalletManager.getInstance().recoveryWallet(walletFile, walletPassword, tmpWallet.getSeed(""), offset, restoreHeight); val tmpWallet =
tmpWalletFile.delete(); createTempWallet(tmpWalletFile) //we do this to get seed, then recover wallet so we can use seed offset
tmpWallet?.let {
wallet = WalletManager.instance?.recoveryWallet(
walletFile,
walletPassword,
tmpWallet.getSeed("") ?: return@let,
offset,
restoreHeight
)
tmpWalletFile.delete()
}
} }
} else { } else {
if (getMnemonicType(walletSeed) == SeedType.UNKNOWN) { if (getMnemonicType(walletSeed) == SeedType.UNKNOWN) {
mainActivity.runOnUiThread(() -> { mainActivity.runOnUiThread {
_enableCreateButton.postValue(true); _enableCreateButton.postValue(true)
Toast.makeText(mainActivity, application.getString(R.string.invalid_mnemonic_code), Toast.LENGTH_SHORT).show(); Toast.makeText(
}); mainActivity,
return; application.getString(R.string.invalid_mnemonic_code),
Toast.LENGTH_SHORT
).show()
} }
if (!restoreHeightText.isEmpty()) { return@execute
restoreHeight = Long.parseLong(restoreHeightText);
} }
wallet = WalletManager.getInstance().recoveryWallet(walletFile, walletPassword, walletSeed, offset, restoreHeight); if (restoreHeightText.isNotEmpty()) {
restoreHeight = restoreHeightText.toLong()
} }
Wallet.Status walletStatus = wallet.getStatus(); wallet = WalletManager.instance?.recoveryWallet(
wallet.close(); walletFile,
boolean ok = walletStatus.isOk(); walletPassword,
walletFile.delete(); // cache is broken for some reason when recovering wallets. delete the file here. this happens in monerujo too. walletSeed,
offset,
if (ok) { restoreHeight
((MainActivity) mainActivity).init(walletFile, walletPassword); )
mainActivity.runOnUiThread(mainActivity::onBackPressed); }
val walletStatus = wallet?.status
wallet?.close()
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) {
(mainActivity as MainActivity).init(walletFile, walletPassword)
mainActivity.runOnUiThread { mainActivity.onBackPressed() }
} else { } else {
mainActivity.runOnUiThread(() -> { mainActivity.runOnUiThread {
_enableCreateButton.postValue(true); _enableCreateButton.postValue(true)
Toast.makeText(mainActivity, application.getString(R.string.create_wallet_failed, walletStatus.errorString), Toast.LENGTH_SHORT).show(); Toast.makeText(
}); mainActivity,
application.getString(
R.string.create_wallet_failed,
walletStatus?.errorString
),
Toast.LENGTH_SHORT
).show()
}
}
} }
});
} }
private long getNewRestoreHeight() { private val newRestoreHeight: Long
Calendar restoreDate = Calendar.getInstance(); get() {
restoreDate.add(Calendar.DAY_OF_MONTH, 0); val restoreDate = Calendar.getInstance()
return RestoreHeight.getInstance().getHeight(restoreDate.getTime()); restoreDate.add(Calendar.DAY_OF_MONTH, 0)
return RestoreHeight.instance?.getHeight(restoreDate.time) ?: 0
} }
public SeedType getMnemonicType(String seed) { private fun getMnemonicType(seed: String): SeedType {
String[] words = seed.split("\\s"); val words = seed.split("\\s".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
SeedType seedTypeValue = seedType.getValue(); val seedTypeValue = seedType.value ?: return SeedType.LEGACY
if (seedTypeValue == null) return SeedType.LEGACY; return if (words.size == 16 && seedTypeValue == SeedType.POLYSEED) {
if (words.length == 16 && seedTypeValue == SeedType.POLYSEED) { SeedType.POLYSEED
return SeedType.POLYSEED; } else if (words.size == 25 && seedTypeValue == SeedType.LEGACY) {
} else if (words.length == 25 && seedTypeValue == SeedType.LEGACY) { SeedType.LEGACY
return SeedType.LEGACY;
} else { } else {
return SeedType.UNKNOWN; SeedType.UNKNOWN
} }
} }
private Wallet createTempWallet(File tmpWalletFile) { private fun createTempWallet(tmpWalletFile: File): Wallet? {
return WalletManager.getInstance().createWallet(tmpWalletFile, "", Constants.MNEMONIC_LANGUAGE, 0); return WalletManager.instance?.createWallet(
tmpWalletFile,
"",
Constants.MNEMONIC_LANGUAGE,
0
)
} }
public enum SeedType { enum class SeedType(val descResId: Int) {
LEGACY(R.string.seed_desc_legacy), LEGACY(R.string.seed_desc_legacy), POLYSEED(R.string.seed_desc_polyseed), UNKNOWN(0)
POLYSEED(R.string.seed_desc_polyseed),
UNKNOWN(0);
private final int descResId;
SeedType(int descResId) {
this.descResId = descResId;
}
public int getDescResId() {
return descResId;
}
} }
} }

View file

@ -237,7 +237,10 @@ class SendFragment : Fragment() {
val address = if (destCount == 1) getAddressField(0).text.toString() else "Multiple" val address = if (destCount == 1) getAddressField(0).text.toString() else "Multiple"
addressTextView?.text = getString(R.string.tx_address_text, address) addressTextView?.text = getString(R.string.tx_address_text, address)
amountTextView?.text = amountTextView?.text =
getString(R.string.tx_amount_text, Helper.getDisplayAmount(pendingTx.getAmount())) getString(
R.string.tx_amount_text,
Helper.getDisplayAmount(pendingTx.getAmount())
)
feeTextView?.text = feeTextView?.text =
getString(R.string.tx_fee_text, Helper.getDisplayAmount(pendingTx.getFee())) getString(R.string.tx_fee_text, Helper.getDisplayAmount(pendingTx.getFee()))
} }

View file

@ -1,312 +1,291 @@
package net.mynero.wallet.fragment.settings; package net.mynero.wallet.fragment.settings
import android.os.Bundle; import android.os.Bundle
import android.text.Editable; import android.text.Editable
import android.text.TextWatcher; import android.text.TextWatcher
import android.util.Patterns; import android.util.Patterns
import android.view.LayoutInflater; import android.view.LayoutInflater
import android.view.View; import android.view.View
import android.view.ViewGroup; import android.view.ViewGroup
import android.widget.Button; import android.widget.Button
import android.widget.EditText; import android.widget.CompoundButton
import android.widget.TextView; import android.widget.EditText
import android.widget.Toast; import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.widget.SwitchCompat
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.NavHostFragment
import net.mynero.wallet.MoneroApplication
import net.mynero.wallet.R
import net.mynero.wallet.data.Node
import net.mynero.wallet.data.Node.Companion.fromJson
import net.mynero.wallet.fragment.dialog.AddNodeBottomSheetDialog
import net.mynero.wallet.fragment.dialog.AddNodeBottomSheetDialog.AddNodeListener
import net.mynero.wallet.fragment.dialog.EditNodeBottomSheetDialog
import net.mynero.wallet.fragment.dialog.EditNodeBottomSheetDialog.EditNodeListener
import net.mynero.wallet.fragment.dialog.NodeSelectionBottomSheetDialog
import net.mynero.wallet.fragment.dialog.NodeSelectionBottomSheetDialog.NodeSelectionDialogListener
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.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.HistoryService
import net.mynero.wallet.service.PrefService
import net.mynero.wallet.util.Constants
import org.json.JSONArray
import androidx.annotation.NonNull; class SettingsFragment : Fragment(), PasswordListener, NodeSelectionDialogListener, AddNodeListener,
import androidx.annotation.Nullable; EditNodeListener {
import androidx.appcompat.widget.SwitchCompat; private var mViewModel: SettingsViewModel? = null
import androidx.constraintlayout.widget.ConstraintLayout; private var proxyAddressListener: TextWatcher = object : TextWatcher {
import androidx.fragment.app.Fragment; override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
import androidx.fragment.app.FragmentActivity; override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
import androidx.fragment.app.FragmentManager; override fun afterTextChanged(editable: Editable) {
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;
import net.mynero.wallet.MoneroApplication;
import net.mynero.wallet.R;
import net.mynero.wallet.data.Node;
import net.mynero.wallet.fragment.dialog.AddNodeBottomSheetDialog;
import net.mynero.wallet.fragment.dialog.EditNodeBottomSheetDialog;
import net.mynero.wallet.fragment.dialog.NodeSelectionBottomSheetDialog;
import net.mynero.wallet.fragment.dialog.PasswordBottomSheetDialog;
import net.mynero.wallet.fragment.dialog.WalletKeysBottomSheetDialog;
import net.mynero.wallet.model.Wallet;
import net.mynero.wallet.model.WalletManager;
import net.mynero.wallet.service.BalanceService;
import net.mynero.wallet.service.BlockchainService;
import net.mynero.wallet.service.HistoryService;
import net.mynero.wallet.service.PrefService;
import net.mynero.wallet.util.Constants;
import org.json.JSONArray;
import org.json.JSONObject;
public class SettingsFragment extends Fragment implements PasswordBottomSheetDialog.PasswordListener, NodeSelectionBottomSheetDialog.NodeSelectionDialogListener, AddNodeBottomSheetDialog.AddNodeListener, EditNodeBottomSheetDialog.EditNodeListener {
private SettingsViewModel mViewModel;
TextWatcher proxyAddressListener = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (mViewModel != null) { if (mViewModel != null) {
mViewModel.setProxyAddress(editable.toString()); mViewModel?.setProxyAddress(editable.toString())
mViewModel.updateProxy(((MoneroApplication) getActivity().getApplication())); mViewModel?.updateProxy(activity?.application as MoneroApplication)
} }
} }
};
TextWatcher proxyPortListener = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
} }
private var proxyPortListener: TextWatcher = object : TextWatcher {
@Override override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
} override fun afterTextChanged(editable: Editable) {
@Override
public void afterTextChanged(Editable editable) {
if (mViewModel != null) { if (mViewModel != null) {
mViewModel.setProxyPort(editable.toString()); mViewModel?.setProxyPort(editable.toString())
mViewModel.updateProxy(((MoneroApplication) getActivity().getApplication())); mViewModel?.updateProxy(activity?.application as MoneroApplication)
} }
} }
}; }
private EditText walletProxyAddressEditText; private var walletProxyAddressEditText: EditText? = null
private EditText walletProxyPortEditText; private var walletProxyPortEditText: EditText? = null
private Button selectNodeButton; private var selectNodeButton: Button? = null
override fun onCreateView(
@Override inflater: LayoutInflater, container: ViewGroup?,
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, savedInstanceState: Bundle?
@Nullable Bundle savedInstanceState) { ): View? {
return inflater.inflate(R.layout.fragment_settings, container, false); return inflater.inflate(R.layout.fragment_settings, container, false)
} }
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState)
super.onViewCreated(view, savedInstanceState); mViewModel = ViewModelProvider(this)[SettingsViewModel::class.java]
mViewModel = new ViewModelProvider(this).get(SettingsViewModel.class); val displaySeedButton = view.findViewById<Button>(R.id.display_seed_button)
Button displaySeedButton = view.findViewById(R.id.display_seed_button); val displayUtxosButton = view.findViewById<Button>(R.id.display_utxos_button)
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)
selectNodeButton = view.findViewById(R.id.select_node_button); val monerochanSwitch = view.findViewById<SwitchCompat>(R.id.monerochan_switch)
SwitchCompat streetModeSwitch = view.findViewById(R.id.street_mode_switch); val donationSwitch = view.findViewById<SwitchCompat>(R.id.donate_per_tx_switch)
SwitchCompat monerochanSwitch = view.findViewById(R.id.monerochan_switch); val torSwitch = view.findViewById<SwitchCompat>(R.id.tor_switch)
SwitchCompat donationSwitch = view.findViewById(R.id.donate_per_tx_switch); val proxySettingsLayout =
SwitchCompat torSwitch = view.findViewById(R.id.tor_switch); view.findViewById<ConstraintLayout>(R.id.wallet_proxy_settings_layout)
ConstraintLayout proxySettingsLayout = view.findViewById(R.id.wallet_proxy_settings_layout); walletProxyAddressEditText = view.findViewById(R.id.wallet_proxy_address_edittext)
walletProxyAddressEditText = view.findViewById(R.id.wallet_proxy_address_edittext); walletProxyPortEditText = view.findViewById(R.id.wallet_proxy_port_edittext)
walletProxyPortEditText = view.findViewById(R.id.wallet_proxy_port_edittext); streetModeSwitch.isChecked =
PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) == true
streetModeSwitch.setChecked(PrefService.getInstance().getBoolean(Constants.PREF_STREET_MODE, false)); streetModeSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
streetModeSwitch.setOnCheckedChangeListener((compoundButton, b) -> { PrefService.instance?.edit()?.putBoolean(Constants.PREF_STREET_MODE, b)?.apply()
PrefService.getInstance().edit().putBoolean(Constants.PREF_STREET_MODE, b).apply(); BalanceService.instance?.refreshBalance()
BalanceService.instance.refreshBalance();
});
monerochanSwitch.setChecked(PrefService.getInstance().getBoolean(Constants.PREF_MONEROCHAN, true));
monerochanSwitch.setOnCheckedChangeListener((compoundButton, b) -> {
PrefService.getInstance().edit().putBoolean(Constants.PREF_MONEROCHAN, b).apply();
HistoryService.getInstance().refreshHistory();
});
donationSwitch.setChecked(PrefService.getInstance().getBoolean(Constants.PREF_DONATE_PER_TX, false));
donationSwitch.setOnCheckedChangeListener((compoundButton, b) -> PrefService.getInstance().edit().putBoolean(Constants.PREF_DONATE_PER_TX, b).apply());
PrefService prefService = PrefService.getInstance();
boolean usesProxy = prefService.getBoolean(Constants.PREF_USES_TOR, false);
if (prefService.hasProxySet()) {
String proxyAddress = prefService.getProxyAddress();
String proxyPort = prefService.getProxyPort();
initProxyStuff(proxyAddress, proxyPort);
} }
torSwitch.setChecked(usesProxy); 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
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)
}
torSwitch.isChecked = usesProxy
if (usesProxy) { if (usesProxy) {
proxySettingsLayout.setVisibility(View.VISIBLE); proxySettingsLayout.visibility = View.VISIBLE
} else { } else {
proxySettingsLayout.setVisibility(View.GONE); proxySettingsLayout.visibility = View.GONE
} }
addProxyTextListeners()
addProxyTextListeners(); torSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
prefService?.edit()?.putBoolean(Constants.PREF_USES_TOR, b)?.apply()
torSwitch.setOnCheckedChangeListener((compoundButton, b) -> {
prefService.edit().putBoolean(Constants.PREF_USES_TOR, b).apply();
if (b) { if (b) {
if (prefService.hasProxySet()) { if (prefService?.hasProxySet() == true) {
removeProxyTextListeners(); removeProxyTextListeners()
val proxyAddress = prefService.proxyAddress
String proxyAddress = prefService.getProxyAddress(); val proxyPort = prefService.proxyPort
String proxyPort = prefService.getProxyPort(); initProxyStuff(proxyAddress, proxyPort)
initProxyStuff(proxyAddress, proxyPort); addProxyTextListeners()
addProxyTextListeners();
} }
proxySettingsLayout.setVisibility(View.VISIBLE); proxySettingsLayout.visibility = View.VISIBLE
} else { } else {
proxySettingsLayout.setVisibility(View.GONE); proxySettingsLayout.visibility = View.GONE
} }
mViewModel?.updateProxy(activity?.application as MoneroApplication)
mViewModel.updateProxy(((MoneroApplication) getActivity().getApplication())); }
}); displaySeedButton.setOnClickListener {
val usesPassword =
displaySeedButton.setOnClickListener(view1 -> { PrefService.instance?.getBoolean(Constants.PREF_USES_PASSWORD, false) == true
boolean usesPassword = PrefService.getInstance().getBoolean(Constants.PREF_USES_PASSWORD, false);
if (usesPassword) { if (usesPassword) {
PasswordBottomSheetDialog passwordDialog = new PasswordBottomSheetDialog(); activity?.supportFragmentManager?.let { fragmentManager ->
passwordDialog.cancelable = true; val passwordDialog = PasswordBottomSheetDialog()
passwordDialog.listener = this; passwordDialog.cancelable = true
passwordDialog.show(getActivity().getSupportFragmentManager(), "password_dialog"); passwordDialog.listener = this
passwordDialog.show(fragmentManager, "password_dialog")
}
} else { } else {
displaySeedDialog(""); displaySeedDialog("")
}
}
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 {
activity?.supportFragmentManager?.let { fragmentManager ->
val dialog = NodeSelectionBottomSheetDialog()
dialog.listener = this
dialog.show(fragmentManager, "node_selection_dialog")
} }
});
displayUtxosButton.setOnClickListener(view1 -> {
navigate(R.id.nav_to_utxos);
});
TextView statusTextView = view.findViewById(R.id.status_textview);
BlockchainService.instance.connectionStatus.observe(getViewLifecycleOwner(), connectionStatus -> {
if (connectionStatus == Wallet.ConnectionStatus.ConnectionStatus_Connected) {
statusTextView.setText(getResources().getText(R.string.connected));
} else if (connectionStatus == Wallet.ConnectionStatus.ConnectionStatus_Disconnected) {
statusTextView.setText(getResources().getText(R.string.disconnected));
} else if (connectionStatus == Wallet.ConnectionStatus.ConnectionStatus_WrongVersion) {
statusTextView.setText(getResources().getText(R.string.version_mismatch));
} }
});
Node node = PrefService.getInstance().getNode(); // shouldn't use default value here
selectNodeButton.setText(getString(R.string.node_button_text, node.getAddress()));
selectNodeButton.setOnClickListener(view1 -> {
NodeSelectionBottomSheetDialog dialog = new NodeSelectionBottomSheetDialog();
dialog.listener = this;
dialog.show(getActivity().getSupportFragmentManager(), "node_selection_dialog");
});
} }
private void displaySeedDialog(String password) { private fun displaySeedDialog(password: String) {
WalletKeysBottomSheetDialog informationDialog = new WalletKeysBottomSheetDialog(); activity?.supportFragmentManager?.let { fragmentManager ->
informationDialog.password = password; val informationDialog = WalletKeysBottomSheetDialog()
informationDialog.show(getActivity().getSupportFragmentManager(), "information_seed_dialog"); informationDialog.password = password
informationDialog.show(fragmentManager, "information_seed_dialog")
}
} }
@Override override fun onPasswordSuccess(password: String) {
public void onPasswordSuccess(String password) { displaySeedDialog(password)
displaySeedDialog(password);
} }
@Override override fun onPasswordFail() {
public void onPasswordFail() { Toast.makeText(context, R.string.bad_password, Toast.LENGTH_SHORT).show()
Toast.makeText(getContext(), R.string.bad_password, Toast.LENGTH_SHORT).show();
} }
private void initProxyStuff(String proxyAddress, String proxyPort) { private fun initProxyStuff(proxyAddress: String, proxyPort: String) {
boolean validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches(); val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
if (validIpAddress) { if (validIpAddress) {
mViewModel.setProxyAddress(proxyAddress); mViewModel?.setProxyAddress(proxyAddress)
mViewModel.setProxyPort(proxyPort); mViewModel?.setProxyPort(proxyPort)
walletProxyAddressEditText.setText(proxyAddress); walletProxyAddressEditText?.setText(proxyAddress)
walletProxyPortEditText.setText(proxyPort); walletProxyPortEditText?.setText(proxyPort)
} }
} }
private void removeProxyTextListeners() { private fun removeProxyTextListeners() {
walletProxyAddressEditText.removeTextChangedListener(proxyAddressListener); walletProxyAddressEditText?.removeTextChangedListener(proxyAddressListener)
walletProxyPortEditText.removeTextChangedListener(proxyPortListener); walletProxyPortEditText?.removeTextChangedListener(proxyPortListener)
} }
private void addProxyTextListeners() { private fun addProxyTextListeners() {
walletProxyAddressEditText.addTextChangedListener(proxyAddressListener); walletProxyAddressEditText?.addTextChangedListener(proxyAddressListener)
walletProxyPortEditText.addTextChangedListener(proxyPortListener); walletProxyPortEditText?.addTextChangedListener(proxyPortListener)
} }
@Override override fun onNodeSelected() {
public void onNodeSelected() { val node = PrefService.instance?.node
Node node = PrefService.getInstance().getNode(); selectNodeButton?.text = getString(R.string.node_button_text, node?.address)
selectNodeButton.setText(getString(R.string.node_button_text, node.getAddress())); mViewModel?.updateProxy(activity?.application as MoneroApplication)
mViewModel.updateProxy(((MoneroApplication) getActivity().getApplication())); (activity?.application as MoneroApplication).executor?.execute {
((MoneroApplication) getActivity().getApplication()).getExecutor().execute(() -> { WalletManager.instance?.wallet?.init(0)
WalletManager.getInstance().getWallet().init(0); WalletManager.instance?.wallet?.startRefresh()
WalletManager.getInstance().getWallet().startRefresh(); }
});
} }
@Override override fun onClickedAddNode() {
public void onClickedAddNode() { activity?.supportFragmentManager?.let { fragmentManager ->
AddNodeBottomSheetDialog addNodeDialog = new AddNodeBottomSheetDialog(); val addNodeDialog = AddNodeBottomSheetDialog()
addNodeDialog.listener = this; addNodeDialog.listener = this
addNodeDialog.show(getActivity().getSupportFragmentManager(), "add_node_dialog"); addNodeDialog.show(fragmentManager, "add_node_dialog")
}
} }
@Override override fun onClickedEditNode(node: Node?) {
public void onClickedEditNode(Node node) { activity?.supportFragmentManager?.let { fragmentManager ->
EditNodeBottomSheetDialog editNodeDialog = new EditNodeBottomSheetDialog(); val editNodeDialog = EditNodeBottomSheetDialog()
editNodeDialog.listener = this; editNodeDialog.listener = this
editNodeDialog.node = node; editNodeDialog.node = node
editNodeDialog.show(getActivity().getSupportFragmentManager(), "edit_node_dialog"); editNodeDialog.show(fragmentManager, "edit_node_dialog")
} }
@Override
public void onNodeAdded() {
NodeSelectionBottomSheetDialog dialog = new NodeSelectionBottomSheetDialog();
dialog.listener = this;
dialog.show(getActivity().getSupportFragmentManager(), "node_selection_dialog");
} }
private void navigate(int destination) { override fun onNodeAdded() {
FragmentActivity activity = getActivity(); activity?.supportFragmentManager?.let { fragmentManager ->
val dialog = NodeSelectionBottomSheetDialog()
dialog.listener = this
dialog.show(fragmentManager, "node_selection_dialog")
}
}
private fun navigate(destination: Int) {
val activity = activity
if (activity != null) { if (activity != null) {
FragmentManager fm = activity.getSupportFragmentManager(); val fm = activity.supportFragmentManager
NavHostFragment navHostFragment = val navHostFragment = fm.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
(NavHostFragment) fm.findFragmentById(R.id.nav_host_fragment); navHostFragment?.navController?.navigate(destination)
if (navHostFragment != null) {
navHostFragment.getNavController().navigate(destination);
}
} }
} }
@Override override fun onNodeDeleted(node: Node?) {
public void onNodeDeleted(Node node) {
try { try {
String nodesArray = PrefService.getInstance().getString(Constants.PREF_CUSTOM_NODES, "[]"); val nodesArray = PrefService.instance?.getString(Constants.PREF_CUSTOM_NODES, "[]")
JSONArray jsonArray = new JSONArray(nodesArray); val jsonArray = JSONArray(nodesArray)
for (int i = 0; i < jsonArray.length(); i++) { for (i in 0 until jsonArray.length()) {
JSONObject nodeJsonObject = jsonArray.getJSONObject(i); val nodeJsonObject = jsonArray.getJSONObject(i)
Node savedNode = Node.fromJson(nodeJsonObject); val savedNode = fromJson(nodeJsonObject)
if (savedNode.toNodeString().equals(node.toNodeString())) if (savedNode?.toNodeString() == node?.toNodeString()) jsonArray.remove(i)
jsonArray.remove(i);
} }
saveNodesAndReopen(jsonArray); saveNodesAndReopen(jsonArray)
} catch (Exception e) { } catch (e: Exception) {
e.printStackTrace(); e.printStackTrace()
} }
} }
@Override override fun onNodeEdited(oldNode: Node?, newNode: Node?) {
public void onNodeEdited(Node oldNode, Node newNode) {
try { try {
String nodesArray = PrefService.getInstance().getString(Constants.PREF_CUSTOM_NODES, "[]"); val nodesArray = PrefService.instance?.getString(Constants.PREF_CUSTOM_NODES, "[]")
JSONArray jsonArray = new JSONArray(nodesArray); val jsonArray = JSONArray(nodesArray)
for (int i = 0; i < jsonArray.length(); i++) { for (i in 0 until jsonArray.length()) {
JSONObject nodeJsonObject = jsonArray.getJSONObject(i); val nodeJsonObject = jsonArray.getJSONObject(i)
Node savedNode = Node.fromJson(nodeJsonObject); val savedNode = fromJson(nodeJsonObject)
if (savedNode.toNodeString().equals(oldNode.toNodeString())) if (savedNode?.toNodeString() == oldNode?.toNodeString()) jsonArray.put(
jsonArray.put(i, newNode.toJson()); i,
newNode?.toJson()
)
} }
saveNodesAndReopen(jsonArray); saveNodesAndReopen(jsonArray)
} catch (Exception e) { } catch (e: Exception) {
e.printStackTrace(); e.printStackTrace()
} }
} }
private void saveNodesAndReopen(JSONArray jsonArray) { private fun saveNodesAndReopen(jsonArray: JSONArray) {
PrefService.getInstance().edit().putString(Constants.PREF_CUSTOM_NODES, jsonArray.toString()).apply(); PrefService.instance?.edit()?.putString(Constants.PREF_CUSTOM_NODES, jsonArray.toString())
onNodeAdded(); ?.apply()
onNodeAdded()
} }
} }

View file

@ -1,50 +1,43 @@
package net.mynero.wallet.fragment.settings; package net.mynero.wallet.fragment.settings
import android.util.Patterns; import android.util.Patterns
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModel; import net.mynero.wallet.MoneroApplication
import net.mynero.wallet.model.WalletManager
import net.mynero.wallet.MoneroApplication; import net.mynero.wallet.service.PrefService
import net.mynero.wallet.data.Node; import net.mynero.wallet.util.Constants
import net.mynero.wallet.model.WalletManager;
import net.mynero.wallet.service.PrefService;
import net.mynero.wallet.util.Constants;
public class SettingsViewModel extends ViewModel {
private String proxyAddress = "";
private String proxyPort = "";
public void updateProxy(MoneroApplication application) {
application.getExecutor().execute(() -> {
boolean usesProxy = PrefService.getInstance().getBoolean(Constants.PREF_USES_TOR, false);
Node curretNode = PrefService.getInstance().getNode();
boolean isNodeLocalIp = curretNode.getAddress().startsWith("10.") || curretNode.getAddress().startsWith("192.168.") || curretNode.getAddress().equals("localhost") || curretNode.getAddress().equals("127.0.0.1");
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) { if (!usesProxy || isNodeLocalIp) {
WalletManager.getInstance().setProxy(""); WalletManager.instance?.setProxy("")
WalletManager.getInstance().getWallet().setProxy(""); WalletManager.instance?.wallet?.setProxy("")
return; return@execute
} }
if (proxyAddress.isEmpty()) proxyAddress = "127.0.0.1"
if (proxyAddress.isEmpty()) proxyAddress = "127.0.0.1"; if (proxyPort.isEmpty()) proxyPort = "9050"
if (proxyPort.isEmpty()) proxyPort = "9050"; val validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches()
boolean validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches();
if (validIpAddress) { if (validIpAddress) {
String proxy = proxyAddress + ":" + proxyPort; val proxy = "$proxyAddress:$proxyPort"
PrefService.getInstance().edit().putString(Constants.PREF_PROXY, proxy).apply(); PrefService.instance?.edit()?.putString(Constants.PREF_PROXY, proxy)?.apply()
WalletManager.getInstance().setProxy(proxy); WalletManager.instance?.setProxy(proxy)
WalletManager.getInstance().getWallet().setProxy(proxy); WalletManager.instance?.wallet?.setProxy(proxy)
}
} }
});
} }
public void setProxyAddress(String address) { fun setProxyAddress(address: String) {
this.proxyAddress = address; proxyAddress = address
} }
public void setProxyPort(String port) { fun setProxyPort(port: String) {
this.proxyPort = port; proxyPort = port
} }
} }

View file

@ -1,162 +1,167 @@
package net.mynero.wallet.fragment.transaction; package net.mynero.wallet.fragment.transaction
import static net.mynero.wallet.util.DateHelper.DATETIME_FORMATTER; import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import net.mynero.wallet.R
import net.mynero.wallet.model.TransactionInfo
import net.mynero.wallet.model.WalletManager
import net.mynero.wallet.service.HistoryService
import net.mynero.wallet.service.PrefService
import net.mynero.wallet.util.Constants
import net.mynero.wallet.util.DateHelper
import net.mynero.wallet.util.Helper
import java.util.Calendar
import java.util.Date
import java.util.Objects
import android.content.Context; class TransactionFragment : Fragment() {
import android.os.Bundle; private var mViewModel: TransactionViewModel? = null
import android.view.LayoutInflater; private var transactionInfo: TransactionInfo? = null
import android.view.View; override fun onCreateView(
import android.view.ViewGroup; inflater: LayoutInflater, container: ViewGroup?,
import android.widget.ImageButton; savedInstanceState: Bundle?
import android.widget.TextView; ): View? {
return inflater.inflate(R.layout.fragment_transaction, container, false)
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import net.mynero.wallet.R;
import net.mynero.wallet.model.TransactionInfo;
import net.mynero.wallet.model.Wallet;
import net.mynero.wallet.model.WalletManager;
import net.mynero.wallet.service.HistoryService;
import net.mynero.wallet.service.PrefService;
import net.mynero.wallet.util.Constants;
import net.mynero.wallet.util.Helper;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.TimeZone;
public class TransactionFragment extends Fragment {
private TransactionViewModel mViewModel;
private TransactionInfo transactionInfo = null;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_transaction, container, false);
} }
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState)
super.onViewCreated(view, savedInstanceState); val cal = Calendar.getInstance()
Calendar cal = Calendar.getInstance(); val tz = cal.timeZone //get the local time zone.
TimeZone tz = cal.getTimeZone(); //get the local time zone. DateHelper.DATETIME_FORMATTER.timeZone = tz
DATETIME_FORMATTER.setTimeZone(tz); mViewModel = ViewModelProvider(this)[TransactionViewModel::class.java]
val args = arguments
mViewModel = new ViewModelProvider(this).get(TransactionViewModel.class);
Bundle args = getArguments();
if (args != null) { if (args != null) {
this.transactionInfo = getArguments().getParcelable(Constants.NAV_ARG_TXINFO); transactionInfo = arguments?.getParcelable(Constants.NAV_ARG_TXINFO)
}
bindObservers(view)
bindListeners(view)
} }
bindObservers(view); private fun bindListeners(view: View) {
bindListeners(view); val copyTxHashImageButton = view.findViewById<ImageButton>(R.id.copy_txhash_imagebutton)
} copyTxHashImageButton.setOnClickListener {
val txInfo = transactionInfo
private void bindListeners(View view) {
ImageButton copyTxHashImageButton = view.findViewById(R.id.copy_txhash_imagebutton);
copyTxHashImageButton.setOnClickListener(view1 -> {
TransactionInfo txInfo = this.transactionInfo;
if (txInfo != null) { if (txInfo != null) {
Helper.clipBoardCopy(getContext(), "transaction_hash", txInfo.hash); Helper.clipBoardCopy(context, "transaction_hash", txInfo.hash)
} }
}); }
val copyTxAddressImageButton =
ImageButton copyTxAddressImageButton = view.findViewById(R.id.copy_txaddress_imagebutton); view.findViewById<ImageButton>(R.id.copy_txaddress_imagebutton)
TextView addressTextView = view.findViewById(R.id.transaction_address_textview); val addressTextView = view.findViewById<TextView>(R.id.transaction_address_textview)
copyTxAddressImageButton.setOnClickListener(view1 -> { copyTxAddressImageButton.setOnClickListener {
TransactionInfo txInfo = this.transactionInfo; val txInfo = transactionInfo
if (txInfo != null) { if (txInfo != null) {
String destination = addressTextView.getText().toString(); val destination = addressTextView.text.toString()
Helper.clipBoardCopy(getContext(), "transaction_address", destination); Helper.clipBoardCopy(context, "transaction_address", destination)
}
} }
});
} }
private void bindObservers(View view) { private fun bindObservers(view: View) {
TextView txActionTextView = view.findViewById(R.id.transaction_action_textview); val txActionTextView = view.findViewById<TextView>(R.id.transaction_action_textview)
TextView confLabel2 = view.findViewById(R.id.transaction_conf_label2_textview); val confLabel2 = view.findViewById<TextView>(R.id.transaction_conf_label2_textview)
TextView txHashTextView = view.findViewById(R.id.transaction_hash_textview); val txHashTextView = view.findViewById<TextView>(R.id.transaction_hash_textview)
TextView txConfTextView = view.findViewById(R.id.transaction_conf_textview); val txConfTextView = view.findViewById<TextView>(R.id.transaction_conf_textview)
TextView txAddressTextView = view.findViewById(R.id.transaction_address_textview); val txAddressTextView = view.findViewById<TextView>(R.id.transaction_address_textview)
ImageButton copyTxAddressImageButton = view.findViewById(R.id.copy_txaddress_imagebutton); val copyTxAddressImageButton =
TextView txDateTextView = view.findViewById(R.id.transaction_date_textview); view.findViewById<ImageButton>(R.id.copy_txaddress_imagebutton)
TextView txAmountTextView = view.findViewById(R.id.transaction_amount_textview); val txDateTextView = view.findViewById<TextView>(R.id.transaction_date_textview)
TextView blockHeightTextView = view.findViewById(R.id.tx_block_height_textview); val txAmountTextView = view.findViewById<TextView>(R.id.transaction_amount_textview)
val blockHeightTextView = view.findViewById<TextView>(R.id.tx_block_height_textview)
HistoryService.getInstance().history.observe(getViewLifecycleOwner(), transactionInfos -> { HistoryService.instance?.history?.observe(viewLifecycleOwner) { transactionInfos: List<TransactionInfo> ->
TransactionInfo newTransactionInfo = findNewestVersionOfTransaction(this.transactionInfo, transactionInfos); val newTransactionInfo = findNewestVersionOfTransaction(
if (newTransactionInfo == null) return; transactionInfo, transactionInfos
)
txHashTextView.setText(newTransactionInfo.hash); ?: return@observe
txConfTextView.setText("" + newTransactionInfo.confirmations); txHashTextView.text = newTransactionInfo.hash
txDateTextView.setText(getDateTime(newTransactionInfo.timestamp)); txConfTextView.text = "${newTransactionInfo.confirmations}"
txDateTextView.text = getDateTime(newTransactionInfo.timestamp)
if (newTransactionInfo.confirmations > 1) { if (newTransactionInfo.confirmations > 1) {
confLabel2.setText(getString(R.string.transaction_conf_desc2_confirmed)); confLabel2.text = getString(R.string.transaction_conf_desc2_confirmed)
blockHeightTextView.setText("" + newTransactionInfo.blockheight); blockHeightTextView.text = "${newTransactionInfo.blockheight}"
blockHeightTextView.setVisibility(View.VISIBLE); blockHeightTextView.visibility = View.VISIBLE
} else if (newTransactionInfo.confirmations == 1) { } else if (newTransactionInfo.confirmations == 1L) {
confLabel2.setText(getString(R.string.transaction_conf_1_desc2_confirmed)); confLabel2.text = getString(R.string.transaction_conf_1_desc2_confirmed)
blockHeightTextView.setText("" + newTransactionInfo.blockheight); blockHeightTextView.text = "${newTransactionInfo.blockheight}"
blockHeightTextView.setVisibility(View.VISIBLE); blockHeightTextView.visibility = View.VISIBLE
} else { } else {
blockHeightTextView.setVisibility(View.GONE); blockHeightTextView.visibility = View.GONE
confLabel2.setText(getString(R.string.transaction_conf_desc2_unconfirmed)); confLabel2.text = getString(R.string.transaction_conf_desc2_unconfirmed)
} }
val ctx = context
Context ctx = getContext();
if (ctx != null) { if (ctx != null) {
boolean streetModeEnabled = PrefService.getInstance().getBoolean(Constants.PREF_STREET_MODE, false); val streetModeEnabled =
String balanceString = streetModeEnabled ? Constants.STREET_MODE_BALANCE : Helper.getDisplayAmount(newTransactionInfo.amount, 12); PrefService.instance?.getBoolean(Constants.PREF_STREET_MODE, false) == true
if (newTransactionInfo.direction == TransactionInfo.Direction.Direction_In) { val balanceString =
txActionTextView.setText(getString(R.string.transaction_action_recv)); if (streetModeEnabled) Constants.STREET_MODE_BALANCE else Helper.getDisplayAmount(
txAmountTextView.setTextColor(ContextCompat.getColor(ctx, R.color.oled_positiveColor)); newTransactionInfo.amount,
12
)
if (newTransactionInfo.direction === TransactionInfo.Direction.Direction_In) {
txActionTextView.text = getString(R.string.transaction_action_recv)
txAmountTextView.setTextColor(
ContextCompat.getColor(
ctx,
R.color.oled_positiveColor
)
)
} else { } else {
txActionTextView.setText(getString(R.string.transaction_action_sent)); txActionTextView.text = getString(R.string.transaction_action_sent)
txAmountTextView.setTextColor(ContextCompat.getColor(ctx, R.color.oled_negativeColor)); txAmountTextView.setTextColor(
ContextCompat.getColor(
ctx,
R.color.oled_negativeColor
)
)
} }
txAmountTextView.setText(balanceString); txAmountTextView.text = balanceString
} }
var destination: String? = "-"
String destination = "-"; val wallet = WalletManager.instance?.wallet
Wallet wallet = WalletManager.getInstance().getWallet();
if (newTransactionInfo.txKey == null) { if (newTransactionInfo.txKey == null) {
newTransactionInfo.txKey = wallet.getTxKey(newTransactionInfo.hash); newTransactionInfo.txKey = wallet?.getTxKey(newTransactionInfo.hash)
} }
if (newTransactionInfo.address == null && newTransactionInfo.direction == TransactionInfo.Direction.Direction_In) { if (newTransactionInfo.address == null && newTransactionInfo.direction === TransactionInfo.Direction.Direction_In) {
destination = wallet.getSubaddress(newTransactionInfo.accountIndex, newTransactionInfo.addressIndex); destination = wallet?.getSubaddress(
} else if (newTransactionInfo.address != null && newTransactionInfo.direction == TransactionInfo.Direction.Direction_In) { newTransactionInfo.accountIndex,
destination = newTransactionInfo.address; newTransactionInfo.addressIndex
} else if (newTransactionInfo.transfers != null && newTransactionInfo.direction == TransactionInfo.Direction.Direction_Out) { )
if (newTransactionInfo.transfers.size() == 1) { } else if (newTransactionInfo.address != null && newTransactionInfo.direction === TransactionInfo.Direction.Direction_In) {
destination = newTransactionInfo.transfers.get(0).address; destination = newTransactionInfo.address
} else if (newTransactionInfo.transfers != null && newTransactionInfo.direction === TransactionInfo.Direction.Direction_Out) {
if (newTransactionInfo.transfers?.size == 1) {
destination = newTransactionInfo.transfers?.get(0)?.address
} }
} }
txAddressTextView.text = Objects.requireNonNullElse(destination, "-")
txAddressTextView.setText(Objects.requireNonNullElse(destination, "-"));
if (destination == null) { if (destination == null) {
copyTxAddressImageButton.setVisibility(View.INVISIBLE); copyTxAddressImageButton.visibility = View.INVISIBLE
}
} }
});
} }
private TransactionInfo findNewestVersionOfTransaction(TransactionInfo oldTransactionInfo, List<TransactionInfo> transactionInfoList) { private fun findNewestVersionOfTransaction(
for (TransactionInfo transactionInfo : transactionInfoList) { oldTransactionInfo: TransactionInfo?,
if (transactionInfo.hash.equals(oldTransactionInfo.hash)) { transactionInfoList: List<TransactionInfo>
this.transactionInfo = transactionInfo; ): TransactionInfo? {
return this.transactionInfo; for (transactionInfo in transactionInfoList) {
if (transactionInfo.hash == oldTransactionInfo?.hash) {
this.transactionInfo = transactionInfo
return this.transactionInfo
} }
} }
return null; return null
} }
private String getDateTime(long time) { private fun getDateTime(time: Long): String {
return DATETIME_FORMATTER.format(new Date(time * 1000)); return DateHelper.DATETIME_FORMATTER.format(Date(time * 1000))
} }
} }

View file

@ -1,6 +1,5 @@
package net.mynero.wallet.fragment.transaction; package net.mynero.wallet.fragment.transaction
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel
public class TransactionViewModel extends ViewModel { class TransactionViewModel : ViewModel()
}

View file

@ -1,170 +1,166 @@
package net.mynero.wallet.fragment.utxos; package net.mynero.wallet.fragment.utxos
import android.os.Bundle; import android.os.Bundle
import android.view.LayoutInflater; import android.view.LayoutInflater
import android.view.View; import android.view.View
import android.view.ViewGroup; import android.view.ViewGroup
import android.widget.Button; import android.widget.Button
import android.widget.Toast; import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import net.mynero.wallet.R
import net.mynero.wallet.adapter.CoinsInfoAdapter
import net.mynero.wallet.adapter.CoinsInfoAdapter.CoinsInfoAdapterListener
import net.mynero.wallet.fragment.dialog.SendBottomSheetDialog
import net.mynero.wallet.model.CoinsInfo
import net.mynero.wallet.service.AddressService
import net.mynero.wallet.service.UTXOService
import net.mynero.wallet.util.MoneroThreadPoolExecutor
import net.mynero.wallet.util.UriData
import androidx.annotation.NonNull; class UtxosFragment : Fragment(), CoinsInfoAdapterListener, SendBottomSheetDialog.Listener {
import androidx.annotation.Nullable; private val adapter = CoinsInfoAdapter(this)
import androidx.fragment.app.Fragment; private var mViewModel: UtxosViewModel? = null
import androidx.lifecycle.ViewModelProvider; private var sendUtxosButton: Button? = null
import androidx.recyclerview.widget.LinearLayoutManager; private var churnUtxosButton: Button? = null
import androidx.recyclerview.widget.RecyclerView; private var freezeUtxosButton: Button? = null
override fun onCreateView(
import net.mynero.wallet.R; inflater: LayoutInflater, container: ViewGroup?,
import net.mynero.wallet.adapter.CoinsInfoAdapter; savedInstanceState: Bundle?
import net.mynero.wallet.fragment.dialog.SendBottomSheetDialog; ): View? {
import net.mynero.wallet.model.CoinsInfo; return inflater.inflate(R.layout.fragment_utxos, container, false)
import net.mynero.wallet.service.AddressService;
import net.mynero.wallet.service.UTXOService;
import net.mynero.wallet.util.MoneroThreadPoolExecutor;
import net.mynero.wallet.util.UriData;
import java.util.ArrayList;
import java.util.HashMap;
public class UtxosFragment extends Fragment implements CoinsInfoAdapter.CoinsInfoAdapterListener, SendBottomSheetDialog.Listener {
private final CoinsInfoAdapter adapter = new CoinsInfoAdapter(this);
private UtxosViewModel mViewModel;
private Button sendUtxosButton;
private Button churnUtxosButton;
private Button freezeUtxosButton;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_utxos, container, false);
} }
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState)
super.onViewCreated(view, savedInstanceState); mViewModel = ViewModelProvider(this)[UtxosViewModel::class.java]
mViewModel = new ViewModelProvider(this).get(UtxosViewModel.class); bindListeners(view)
bindListeners(view); bindObservers(view)
bindObservers(view);
} }
private void bindListeners(View view) { private fun bindListeners(view: View) {
freezeUtxosButton = view.findViewById(R.id.freeze_utxos_button); freezeUtxosButton = view.findViewById(R.id.freeze_utxos_button)
sendUtxosButton = view.findViewById(R.id.send_utxos_button); sendUtxosButton = view.findViewById(R.id.send_utxos_button)
churnUtxosButton = view.findViewById(R.id.churn_utxos_button); churnUtxosButton = view.findViewById(R.id.churn_utxos_button)
sendUtxosButton.setVisibility(View.GONE); sendUtxosButton?.visibility = View.GONE
churnUtxosButton.setVisibility(View.GONE); churnUtxosButton?.visibility = View.GONE
freezeUtxosButton.setVisibility(View.GONE); freezeUtxosButton?.visibility = View.GONE
freezeUtxosButton.setOnClickListener(view1 -> { freezeUtxosButton?.setOnClickListener {
Toast.makeText(getContext(), "Toggling freeze status, please wait.", Toast.LENGTH_SHORT).show(); Toast.makeText(context, "Toggling freeze status, please wait.", Toast.LENGTH_SHORT)
MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR.execute(() -> { .show()
UTXOService.getInstance().toggleFrozen(adapter.selectedUtxos); MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR?.execute {
getActivity().runOnUiThread(() -> { UTXOService.instance?.toggleFrozen(adapter.selectedUtxos)
adapter.clear(); activity?.runOnUiThread {
sendUtxosButton.setVisibility(View.GONE); adapter.clear()
churnUtxosButton.setVisibility(View.GONE); sendUtxosButton?.visibility = View.GONE
freezeUtxosButton.setVisibility(View.GONE); churnUtxosButton?.visibility = View.GONE
}); freezeUtxosButton?.visibility = View.GONE
});
});
sendUtxosButton.setOnClickListener(view1 -> {
ArrayList<String> selectedKeyImages = new ArrayList<>();
for (CoinsInfo coinsInfo : adapter.selectedUtxos.values()) {
selectedKeyImages.add(coinsInfo.getKeyImage());
} }
SendBottomSheetDialog sendDialog = new SendBottomSheetDialog();
sendDialog.listener = this;
sendDialog.selectedUtxos = selectedKeyImages;
sendDialog.show(getActivity().getSupportFragmentManager(), null);
});
churnUtxosButton.setOnClickListener(view1 -> {
ArrayList<String> selectedKeyImages = new ArrayList<>();
for (CoinsInfo coinsInfo : adapter.selectedUtxos.values()) {
selectedKeyImages.add(coinsInfo.getKeyImage());
} }
SendBottomSheetDialog sendDialog = new SendBottomSheetDialog(); }
sendDialog.listener = this; sendUtxosButton?.setOnClickListener {
sendDialog.isChurning = true; val selectedKeyImages = ArrayList<String>()
sendDialog.uriData = UriData.parse(AddressService.instance.currentSubaddress().address); for (coinsInfo in adapter.selectedUtxos.values) {
sendDialog.selectedUtxos = selectedKeyImages; coinsInfo.keyImage?.let { keyImage -> selectedKeyImages.add(keyImage) }
sendDialog.show(getActivity().getSupportFragmentManager(), null); }
}); activity?.supportFragmentManager?.let { fragmentManager ->
val sendDialog = SendBottomSheetDialog()
sendDialog.listener = this
sendDialog.selectedUtxos = selectedKeyImages
sendDialog.show(fragmentManager, null)
} }
private void bindObservers(View view) { }
RecyclerView utxosRecyclerView = view.findViewById(R.id.transaction_history_recyclerview); churnUtxosButton?.setOnClickListener {
UTXOService utxoService = UTXOService.getInstance(); val selectedKeyImages = ArrayList<String>()
utxosRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); for (coinsInfo in adapter.selectedUtxos.values) {
utxosRecyclerView.setAdapter(adapter); coinsInfo.keyImage?.let { keyImage -> selectedKeyImages.add(keyImage) }
if (utxoService != null) { }
utxoService.utxos.observe(getViewLifecycleOwner(), utxos -> { activity?.supportFragmentManager?.let { fragmentManager ->
HashMap<String, CoinsInfo> filteredUtxos = new HashMap<>(); val sendDialog = SendBottomSheetDialog()
for (CoinsInfo coinsInfo : utxos) { sendDialog.listener = this
if (!coinsInfo.isSpent()) { sendDialog.isChurning = true
filteredUtxos.put(coinsInfo.getPubKey(), coinsInfo); sendDialog.uriData =
AddressService.instance?.currentSubaddress()?.address?.let { address ->
UriData.parse(address)
}
sendDialog.selectedUtxos = selectedKeyImages
sendDialog.show(fragmentManager, null)
}
}
}
private fun bindObservers(view: View) {
val utxosRecyclerView =
view.findViewById<RecyclerView>(R.id.transaction_history_recyclerview)
val utxoService = UTXOService.instance
utxosRecyclerView.layoutManager = LinearLayoutManager(activity)
utxosRecyclerView.adapter = adapter
utxoService?.utxos?.observe(viewLifecycleOwner) { utxos: List<CoinsInfo> ->
val filteredUtxos = HashMap<String?, CoinsInfo>()
for (coinsInfo in utxos) {
if (!coinsInfo.isSpent) {
filteredUtxos[coinsInfo.pubKey] = coinsInfo
} }
} }
if (filteredUtxos.isEmpty()) { if (filteredUtxos.isEmpty()) {
utxosRecyclerView.setVisibility(View.GONE); utxosRecyclerView.visibility = View.GONE
} else { } else {
adapter.submitList(filteredUtxos); adapter.submitList(filteredUtxos)
utxosRecyclerView.setVisibility(View.VISIBLE); utxosRecyclerView.visibility = View.VISIBLE
} }
});
} }
} }
@Override override fun onUtxoSelected(coinsInfo: CoinsInfo) {
public void onUtxoSelected(CoinsInfo coinsInfo) { val selected = adapter.contains(coinsInfo)
boolean selected = adapter.contains(coinsInfo);
if (selected) { if (selected) {
adapter.deselectUtxo(coinsInfo); adapter.deselectUtxo(coinsInfo)
} else { } else {
adapter.selectUtxo(coinsInfo); adapter.selectUtxo(coinsInfo)
} }
var frozenExists = false
boolean frozenExists = false, unfrozenExists = false, bothExist = false; var unfrozenExists = false
for (CoinsInfo selectedUtxo : adapter.selectedUtxos.values()) { for (selectedUtxo in adapter.selectedUtxos.values) {
if (selectedUtxo.isFrozen() || UTXOService.getInstance().isCoinFrozen(selectedUtxo)) if (selectedUtxo.isFrozen || UTXOService.instance?.isCoinFrozen(selectedUtxo) == true)
frozenExists = true; frozenExists = true
else { else {
unfrozenExists = true; unfrozenExists = true
} }
} }
bothExist = frozenExists && unfrozenExists; val bothExist: Boolean = frozenExists && unfrozenExists
if (adapter.selectedUtxos.isEmpty()) { if (adapter.selectedUtxos.isEmpty()) {
sendUtxosButton.setVisibility(View.GONE); sendUtxosButton?.visibility = View.GONE
churnUtxosButton.setVisibility(View.GONE); churnUtxosButton?.visibility = View.GONE
freezeUtxosButton.setVisibility(View.GONE); freezeUtxosButton?.visibility = View.GONE
freezeUtxosButton.setBackgroundResource(R.drawable.button_bg_left); freezeUtxosButton?.setBackgroundResource(R.drawable.button_bg_left)
} else { } else {
if (frozenExists) { if (frozenExists) {
freezeUtxosButton.setBackgroundResource(R.drawable.button_bg); freezeUtxosButton?.setBackgroundResource(R.drawable.button_bg)
sendUtxosButton.setVisibility(View.GONE); sendUtxosButton?.visibility = View.GONE
churnUtxosButton.setVisibility(View.GONE); churnUtxosButton?.visibility = View.GONE
} else { } else {
freezeUtxosButton.setBackgroundResource(R.drawable.button_bg_left); freezeUtxosButton?.setBackgroundResource(R.drawable.button_bg_left)
sendUtxosButton.setVisibility(View.VISIBLE); sendUtxosButton?.visibility = View.VISIBLE
churnUtxosButton.setVisibility(View.VISIBLE); churnUtxosButton?.visibility = View.VISIBLE
} }
freezeUtxosButton.setVisibility(View.VISIBLE); freezeUtxosButton?.visibility = View.VISIBLE
} }
if (bothExist) { if (bothExist) {
freezeUtxosButton.setText(R.string.toggle_freeze); freezeUtxosButton?.setText(R.string.toggle_freeze)
} else if (frozenExists) { } else if (frozenExists) {
freezeUtxosButton.setText(R.string.unfreeze); freezeUtxosButton?.setText(R.string.unfreeze)
} else if (unfrozenExists) { } else if (unfrozenExists) {
freezeUtxosButton.setText(R.string.freeze); freezeUtxosButton?.setText(R.string.freeze)
} }
} }
@Override override fun onSentTransaction() {
public void onSentTransaction() { adapter.clear()
adapter.clear(); churnUtxosButton?.visibility = View.GONE
churnUtxosButton.setVisibility(View.GONE); sendUtxosButton?.visibility = View.GONE
sendUtxosButton.setVisibility(View.GONE); freezeUtxosButton?.visibility = View.GONE
freezeUtxosButton.setVisibility(View.GONE);
} }
} }

View file

@ -1,7 +1,5 @@
package net.mynero.wallet.fragment.utxos; package net.mynero.wallet.fragment.utxos
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel
public class UtxosViewModel extends ViewModel { class UtxosViewModel : ViewModel()
}