Skip to content

Commit

Permalink
Merge 4c69c91 into 0479f34
Browse files Browse the repository at this point in the history
  • Loading branch information
mpatc committed Sep 18, 2020
2 parents 0479f34 + 4c69c91 commit ef08dcb
Show file tree
Hide file tree
Showing 12 changed files with 276 additions and 69 deletions.
2 changes: 1 addition & 1 deletion android/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
/build
/captures
/keystore.jks
.externalNativeBuild
.externalNativeBuild
54 changes: 27 additions & 27 deletions android/.idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.electroncash.electroncash3

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Intent
import android.text.Editable
import android.text.TextWatcher
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModel
import com.google.zxing.integration.android.IntentIntegrator
import kotlinx.android.synthetic.main.load.*
import kotlinx.android.synthetic.main.main.*

// This provides a dialog to allow users to input a string, which is then broadcast
// on the bitcoin cash network. Strings are not validated,
// but broadcast_transaction2 should throw error which is toasted.
// Valid transaction quickly show up in transactions.

class ColdLoadDialog : AlertDialogFragment() {

class Model : ViewModel() {}

val model: Model by viewModels()

override fun onBuildDialog(builder: AlertDialog.Builder) {
builder.setTitle(R.string.load_transaction)
.setView(R.layout.load)
.setNegativeButton(android.R.string.cancel, null)
.setNeutralButton(R.string.qr_code, null)
.setPositiveButton(R.string.send, null)
}

override fun onShowDialog() {
super.onShowDialog()
val ourClipboard = getSystemService(ClipboardManager::class)

etTransaction.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
val currenttext = etTransaction.text
//checks if text is blank. further validations can be added here
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = currenttext.isNotBlank()
}

})
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { onOK() }
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener { scanQR(this) }
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
btnPaste.setOnClickListener {
val clipdata = ourClipboard.primaryClip
val cliptext = clipdata!!.getItemAt(0)
etTransaction.setText(cliptext.text)
}
}

// Receives the result of a QR scan.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
if (result != null && result.contents != null) {
etTransaction.setText(result.contents)
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}


fun onOK() {
// try to send user input to network to be broadcast,
// this should work even if tx is not vaild transaction, but nothing happens
try {
val tx = etTransaction.text.toString()
daemonModel.network.callAttr("broadcast_transaction", tx)
} catch (e: ToastException) {
e.show()
}
toast(R.string.the_string, Toast.LENGTH_LONG)
dismiss()
//send to transactions
// because if they just broadcasted one, that's probably where they want to go
(activity as MainActivity).navBottom.selectedItemId = R.id.navTransactions

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class ContactDialog : AlertDialogFragment() {
showDialog(activity!!, SendDialog().apply {
arguments = Bundle().apply {
putString("address", contact.addrUiString)
putBoolean("unbroadcasted", false)
}
})
dismiss()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ class MainActivity : AppCompatActivity(R.layout.main) {
}
R.id.menuChangePassword -> showDialog(this, PasswordChangeDialog())
R.id.menuShowSeed-> { showDialog(this, SeedPasswordDialog()) }
R.id.menuExportSigned-> { showDialog(this, SendDialog().apply {
arguments = Bundle().apply {putBoolean("unbroadcasted", true)}
}) }
R.id.menuLoadSigned-> { showDialog(this, ColdLoadDialog()) }
R.id.menuRename -> showDialog(this, WalletRenameDialog().apply {
arguments = Bundle().apply { putString("walletName", daemonModel.walletName) }
})
Expand Down
94 changes: 63 additions & 31 deletions android/app/src/main/java/org/electroncash/electroncash3/Send.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,33 +24,51 @@ import kotlin.properties.Delegates.notNull
val libPaymentRequest by lazy { libMod("paymentrequest") }

val MIN_FEE = 1 // sat/byte
var DONT_SEND = false



class SendDialog : AlertDialogFragment() {
class Model : ViewModel() {
var paymentRequest: PyObject? = null
}

val model: Model by viewModels()

init {
if (daemonModel.wallet!!.callAttr("is_watching_only").toBoolean()) {
throw ToastException(R.string.this_wallet_is)
} else if (daemonModel.wallet!!.callAttr("get_receiving_addresses")
.asList().isEmpty()) {
.asList().isEmpty()) {
// At least one receiving address is needed to call wallet.dummy_address.
throw ToastException(
R.string.electron_cash_is_generating_your_addresses__please_wait_)
R.string.electron_cash_is_generating_your_addresses__please_wait_)
}

}

override fun onBuildDialog(builder: AlertDialog.Builder) {
builder.setTitle(R.string.send)
.setView(R.layout.send)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, null)
.setNeutralButton(R.string.qr_code, null)
if (arguments != null) {
DONT_SEND = arguments!!.getBoolean("unbroadcasted")
} else {
DONT_SEND = false
}
if (!DONT_SEND) {
builder.setTitle(R.string.send)
.setView(R.layout.send)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, null)
.setNeutralButton(R.string.qr_code, null)
} else {
builder.setTitle(R.string.sign)
.setView(R.layout.send)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.sign, null)
.setNeutralButton(R.string.qr_code, null)
}
}


override fun onShowDialog() {
if (arguments != null) {
val address = arguments!!.getString("address")
Expand All @@ -60,6 +78,9 @@ class SendDialog : AlertDialogFragment() {
}
arguments = null
}
if (DONT_SEND) {
toast("The DONTSEND flag is true")
}
setPaymentRequest(model.paymentRequest)

etAmount.addTextChangedListener(object : TextWatcher {
Expand Down Expand Up @@ -284,36 +305,47 @@ class SendPasswordDialog : PasswordDialog<Unit>() {
}

override fun onPassword(password: String) {
val wallet = daemonModel.wallet!!
wallet.callAttr("sign_transaction", model.tx, password)
if (! daemonModel.isConnected()) {
throw ToastException(R.string.not_connected)
}
val pr = sendDialog.model.paymentRequest
val result = if (pr != null) {
checkExpired(pr)
val refundAddr = wallet.callAttr("get_receiving_addresses").asList().get(0)
pr.callAttr("send_payment", model.tx.toString(), refundAddr)
} else {
daemonModel.network.callAttr("broadcast_transaction", model.tx)
}.asList()
if (!DONT_SEND) {
val wallet = daemonModel.wallet!!
wallet.callAttr("sign_transaction", model.tx, password)
if (!daemonModel.isConnected()) {
throw ToastException(R.string.not_connected)
}
val pr = sendDialog.model.paymentRequest
val result = if (pr != null) {
checkExpired(pr)
val refundAddr = wallet.callAttr("get_receiving_addresses").asList().get(0)
pr.callAttr("send_payment", model.tx.toString(), refundAddr)
} else {
daemonModel.network.callAttr("broadcast_transaction", model.tx)
}.asList()

val success = result.get(0).toBoolean()
if (success) {
setDescription(model.tx.callAttr("txid").toString(), model.description)
} else {
var message = result.get(1).toString()
val reError = Regex("^error: (.*)")
if (message.contains(reError)) {
message = message.replace(reError, "$1")
val success = result.get(0).toBoolean()
if (success) {
setDescription(model.tx.callAttr("txid").toString(), model.description)
} else {
var message = result.get(1).toString()
val reError = Regex("^error: (.*)")
if (message.contains(reError)) {
message = message.replace(reError, "$1")
}
throw ToastException(message)
}
throw ToastException(message)
} else {
val wallet = daemonModel.wallet!!
wallet.callAttr("sign_transaction", model.tx, password)
}
}

override fun onPostExecute(result: Unit) {
sendDialog.dismiss()
toast(R.string.payment_sent, Toast.LENGTH_SHORT)
if (!DONT_SEND) {
sendDialog.dismiss()
toast(R.string.payment_sent, Toast.LENGTH_SHORT)
} else {
sendDialog.dismiss()
copyToClipboard(model.tx.toString(), R.string.signed_transaction)

}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ class TransactionsFragment : Fragment(R.layout.transactions), MainFragment {

btnSend.setOnClickListener {
try {
showDialog(activity!!, SendDialog())
showDialog(activity!!, SendDialog().apply {
arguments = Bundle().apply {putBoolean("unbroadcasted", false)}
})
} catch (e: ToastException) { e.show() }
}
btnRequest.setOnClickListener { newRequest(activity!!) }
Expand Down
18 changes: 9 additions & 9 deletions android/app/src/main/java/org/electroncash/electroncash3/Util.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ fun <T: DialogFragment> findDialog(activity: FragmentActivity, fragClass: KClass
return null
} else if (frag::class != fragClass) {
throw ClassCastException(
"Expected ${fragClass.java.name}, got ${frag::class.java.name}")
"Expected ${fragClass.java.name}, got ${frag::class.java.name}")
} else {
@Suppress("UNCHECKED_CAST")
return frag as T?
Expand All @@ -94,7 +94,7 @@ fun copyToClipboard(text: CharSequence, what: Int? = null) {
@Suppress("DEPRECATION")
(getSystemService(ClipboardManager::class)).text = text
val message = if (what == null) app.getString(R.string.text_copied)
else app.getString(R.string._s_copied, app.getString(what))
else app.getString(R.string._s_copied, app.getString(what))
toast(message, Toast.LENGTH_SHORT)
}

Expand All @@ -109,8 +109,8 @@ fun setupVerticalList(rv: RecyclerView) {

// Dialog theme has listDivider set to null, so use the base app theme instead.
rv.addItemDecoration(
DividerItemDecoration(ContextThemeWrapper(rv.context, R.style.AppTheme),
DividerItemDecoration.VERTICAL))
DividerItemDecoration(ContextThemeWrapper(rv.context, R.style.AppTheme),
DividerItemDecoration.VERTICAL))
}


Expand All @@ -128,15 +128,15 @@ open class BoundAdapter<T: Any>(val layoutId: Int)
}

override fun getItemCount() =
list.size
list.size

fun getItem(position: Int) =
list.get(position)
list.get(position)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BoundViewHolder<T> {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate<ViewDataBinding>(
layoutInflater, layoutId, parent, false)
layoutInflater, layoutId, parent, false)
return BoundViewHolder(binding)
}

Expand All @@ -160,13 +160,13 @@ class MenuAdapter(context: Context, val menu: Menu)
if (context === app) {
// This resulted in white-on-white text on older API levels (e.g. 18).
throw IllegalArgumentException(
"Can't use application context: theme will not be applied to views")
"Can't use application context: theme will not be applied to views")
}
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
}

constructor(context: Context, menuId: Int)
: this(context, inflateMenu(menuId))
: this(context, inflateMenu(menuId))

override fun getItemId(position: Int): Long {
return menu.getItem(position).itemId.toLong()
Expand Down
Loading

0 comments on commit ef08dcb

Please sign in to comment.