Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature maya enter amount #1265

Merged
merged 63 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
7787641
refactor: move ScanActivity and related classes to common
HashEngineering Jan 16, 2024
85dcdb7
fix: align with Bitcoin Wallet code and replace deprecated functions
HashEngineering Jan 16, 2024
aab4935
refactor: use ScanActivity in common module
HashEngineering Jan 16, 2024
c857c40
refactor: move scan strings to common
HashEngineering Jan 16, 2024
e05027d
fix(maya): update strings for networks
HashEngineering Jan 16, 2024
60bbf85
refactor: Io and AddressUtil strings to common
HashEngineering Jan 16, 2024
3dc3cc3
refactor: move Bluetooth and PaymentIntent to common
HashEngineering Jan 16, 2024
e02c771
refactor: fix AndroidManifest.xml for ScanActivity
HashEngineering Jan 16, 2024
031eb8b
refactor: fix AndroidManifest.xml for ScanActivity
HashEngineering Jan 16, 2024
6085841
fix: use correct bitcoin address parameters
HashEngineering Jan 17, 2024
852464f
feat: add AddressInputFragment to common and use in maya
HashEngineering Jan 17, 2024
0b9f509
refactor: derive fragments from AddressInputFragment
HashEngineering Jan 17, 2024
321c23a
refactor: simplify AddressInputFragment and view model
HashEngineering Jan 17, 2024
4a2a370
refactor: make PaymentProcessors a class
HashEngineering Jan 17, 2024
a39466e
fix: support bitcoin segwit
HashEngineering Jan 17, 2024
46e0f0e
feat: add support for inputting addresses from other modules
HashEngineering Jan 20, 2024
220cd3d
fix: improve validation
HashEngineering Jan 23, 2024
1581ee7
Merge branch 'feature-maya-dest-address' of https://github.com/dashev…
HashEngineering Jan 23, 2024
99f768f
feat: look up on uphold
HashEngineering Jan 25, 2024
0f637f5
feat: cache accounts and addresses
HashEngineering Jan 26, 2024
a00467c
refactor: use coroutines instead of callbacks
HashEngineering Jan 26, 2024
c171d30
fix: clear config when token is revoked
HashEngineering Jan 26, 2024
b920955
Merge branch 'feature-maya' of https://github.com/dashevo/dash-wallet…
HashEngineering Jan 26, 2024
911fb10
fix: remove some changes in WalletActivity
HashEngineering Jan 28, 2024
9456bb7
feat: link to exchanges to login
HashEngineering Jan 30, 2024
a510907
feat: close Uphold if login_and_close
HashEngineering Jan 30, 2024
2faa275
feat: close Uphold if login_and_close
HashEngineering Jan 30, 2024
77cd30b
feat: move deeplink destination to IntegrationOverviewFragment
HashEngineering Jan 30, 2024
643f741
fix: uri support
HashEngineering Feb 1, 2024
7ee2e66
feat: add "connect" text for if address sources don't have any addresses
HashEngineering Feb 1, 2024
2e96506
fix: after connecting to an exchange, click will put the address in t…
HashEngineering Feb 6, 2024
04d0dc2
fix: remove unused functions in the ExchangeIntegrationProvider inter…
HashEngineering Feb 6, 2024
fbe7554
refactor: rename UpholdCardAddress to to UpholdAddress
HashEngineering Feb 6, 2024
561bb05
Rename .java to .kt
HashEngineering Feb 6, 2024
8f64026
refactor: remove Java UpholdAddress and use kotlin version
HashEngineering Feb 6, 2024
ccdaaff
docs: add license and comments
HashEngineering Feb 6, 2024
88e3e21
feat: add enter amount screen for maya swap
HashEngineering Feb 9, 2024
7031416
feat: add enter amount screen for maya swap - phase 1
HashEngineering Feb 20, 2024
61ce4a8
fix: the default payment intent parser
HashEngineering Feb 23, 2024
d634dff
fix: fixes for enter amount
HashEngineering Feb 26, 2024
149152b
fix: fix for exchange rates
HashEngineering Feb 26, 2024
9b008ce
fix: set guideline
HashEngineering Feb 26, 2024
0ae082f
feat: add inbound_addresses api and other fixes
HashEngineering Feb 27, 2024
6f092fd
fix: many improvements
HashEngineering Mar 4, 2024
ca31560
fix: use AmountView
HashEngineering Mar 5, 2024
2f0590c
fix: attempt to resolve rounding issues
HashEngineering Mar 6, 2024
236be26
fix: use Amount class and eliminate rounding errors
HashEngineering Mar 6, 2024
91aa743
fix: fix alignment and visitibility issues and remove trailing zeros …
HashEngineering Mar 7, 2024
4d4a52f
style: ktlint
HashEngineering Mar 7, 2024
e05c647
Merge branch 'feature-maya' of https://github.com/dashevo/dash-wallet…
HashEngineering Mar 7, 2024
7883760
refactor: Amount class and add anchor
HashEngineering Mar 7, 2024
42a5ef8
refactor: Amount class and add anchor
HashEngineering Mar 7, 2024
4beb824
fix: put more things in the scrolling area
HashEngineering Mar 18, 2024
bf9fff8
fix: eliminate various bugs with format
HashEngineering Mar 18, 2024
74db945
fix: fix the search function in the crypto list
HashEngineering Mar 18, 2024
b49b77b
fix: rearrange address input scrollable elements
HashEngineering Mar 19, 2024
90e2ebe
fix: adjust amount input to fit
HashEngineering Mar 19, 2024
c7d255e
fix: use CenteredImageSpan for SDK < 29
HashEngineering Mar 20, 2024
a97ce61
fix: repair max and other conversions
HashEngineering Mar 20, 2024
2369ee8
chore: remove unused code
HashEngineering Mar 25, 2024
e2b559f
style: ktlint
HashEngineering Mar 25, 2024
9117627
chore: remove more unused code and update Copyright
HashEngineering Mar 25, 2024
4c37ec5
chore: remove more unused code
HashEngineering Mar 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ abstract class AddressInputFragment : Fragment(R.layout.fragment_address_input)

binding.showClipboardBtn.isVisible = it.hasClipboardText && it.clipboardText.isEmpty()
binding.clipboardContentContainer.isVisible = it.clipboardText.isNotEmpty()
binding.scrollContainer.isVisible = it.hasClipboardText || binding.addressSourceContainer.isVisible

if (it.clipboardText.isNotEmpty()) {
val spannable = SpannableString(it.clipboardText)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ package org.dash.wallet.common.ui.enter_amount
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.CLIPBOARD_SERVICE
import android.os.Build
import android.text.SpannableString
import android.text.Spanned
import android.text.style.ImageSpan
import android.text.style.RelativeSizeSpan
import android.util.AttributeSet
import android.util.Log
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import android.widget.PopupMenu
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import org.bitcoinj.core.Coin
Expand All @@ -38,11 +44,15 @@ import org.dash.wallet.common.databinding.AmountViewBinding
import org.dash.wallet.common.util.Constants
import org.dash.wallet.common.util.GenericUtils
import org.dash.wallet.common.util.toFormattedString
import org.slf4j.LoggerFactory
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.text.NumberFormat
import java.util.*
import kotlin.math.min

class AmountView(context: Context, attrs: AttributeSet) : ConstraintLayout(context, attrs) {
private val log = LoggerFactory.getLogger(AmountView::class.java)
private val binding = AmountViewBinding.inflate(LayoutInflater.from(context), this)
val dashFormat: MonetaryFormat = MonetaryFormat().withLocale(GenericUtils.getDeviceLocale())
.noCode().minDecimals(6).optionalDecimals()
Expand All @@ -55,6 +65,19 @@ class AmountView(context: Context, attrs: AttributeSet) : ConstraintLayout(conte

private var currencySymbol = "$"
private var isCurrencySymbolFirst = true
var currencyDigits = GenericUtils.getCurrencyDigits()
set(value) {
field = value
updateAmount()
}

private val cryptoFormat: DecimalFormat = DecimalFormat(
"0.########",
DecimalFormatSymbols(GenericUtils.getDeviceLocale())
).apply {
isDecimalSeparatorAlwaysShown = false
isGroupingUsed = false
}

private var _input = "0"
var input: String
Expand All @@ -63,6 +86,9 @@ class AmountView(context: Context, attrs: AttributeSet) : ConstraintLayout(conte
_input = value.ifEmpty { "0" }
updateAmount()
}
private fun getLocalizedInput(scale: Int): String = cryptoFormat.format(
GenericUtils.toScaledBigDecimal(_input, localized = false, scale)
)

var fiatAmount: Fiat = Fiat.valueOf(Constants.DEFAULT_EXCHANGE_CURRENCY, 0)
private set
Expand Down Expand Up @@ -98,9 +124,9 @@ class AmountView(context: Context, attrs: AttributeSet) : ConstraintLayout(conte
fiatAmount = exchangeRate!!.coinToFiat(dashAmount)
_input = fiatFormat.minDecimals(0)
.optionalDecimals(0, 2).format(fiatAmount).toString()
binding.inputAmount.text = formatInputWithCurrency()
setIconWithText(formatInputWithCurrency())
} else {
binding.inputAmount.text = resources.getString(R.string.rate_not_available)
setIconWithText(resources.getString(R.string.rate_not_available))
}
}
}
Expand Down Expand Up @@ -163,7 +189,8 @@ class AmountView(context: Context, attrs: AttributeSet) : ConstraintLayout(conte
}

private fun updateAmount() {
binding.inputAmount.text = formatInputWithCurrency()
// binding.inputAmount.text = formatInputWithCurrency()
setIconWithText(formatInputWithCurrency())
val rate = exchangeRate
val pair = parseAmounts(input, rate)
dashAmount = pair.first
Expand All @@ -178,8 +205,10 @@ class AmountView(context: Context, attrs: AttributeSet) : ConstraintLayout(conte
}
} else {
binding.resultAmount.text = resources.getString(R.string.rate_not_available)
Log.e(AmountView::class.java.name, "Exchange rate is not initialized")
log.warn("Exchange rate is not initialized")
}
binding.inputAmount.requestLayout()
binding.inputAmount.invalidate()
}

private fun parseAmounts(input: String, rate: ExchangeRate?): Pair<Coin, Fiat?> {
Expand Down Expand Up @@ -207,17 +236,11 @@ class AmountView(context: Context, attrs: AttributeSet) : ConstraintLayout(conte
binding.resultCurrencyToggle.isVisible = showCurrencySelector && dashToFiat

if (dashToFiat) {
binding.inputSymbolDash.isVisible = isCurrencySymbolFirst
binding.inputSymbolDashPostfix.isVisible = !isCurrencySymbolFirst

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The symbol is now inserted into the Text Span, rather than being in a separate view.

binding.resultSymbolDash.isVisible = false
binding.resultSymbolDashPostfix.isVisible = false
} else {
binding.resultSymbolDash.isVisible = isCurrencySymbolFirst
binding.resultSymbolDashPostfix.isVisible = !isCurrencySymbolFirst

binding.inputSymbolDash.isVisible = false
binding.inputSymbolDashPostfix.isVisible = false
}
}

Expand Down Expand Up @@ -256,4 +279,65 @@ class AmountView(context: Context, attrs: AttributeSet) : ConstraintLayout(conte
false
}
}

private fun setIconWithText(text: String, iconSize: Int = 22) {
val context = binding.inputAmount.context
val scale = resources.displayMetrics.scaledDensity
val maxTextWidth = binding.inputAmount.width
var spannableString = SpannableString(text) // Space for the icon

// show Dash Icon if DASH is the primary currency
if (dashToFiat) {
// TODO: adjust for dark mode

val roomLeft = maxTextWidth - binding.inputAmount.paint.measureText("$text ") - (iconSize * scale)
val sizeRelative = if (roomLeft < 0) {
val ratio = min(1.0f, (maxTextWidth + roomLeft) / maxTextWidth)
if (ratio == Float.NEGATIVE_INFINITY) {
1.0f
} else {
ratio
}
} else {
1.0f
}
val sizeSpan = RelativeSizeSpan(sizeRelative)
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_dash_d_black)?.apply {
setBounds(0, 0, (iconSize * scale * sizeRelative).toInt(), (iconSize * scale * sizeRelative).toInt())
}
val imageSpan = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
drawable?.let { ImageSpan(it, ImageSpan.ALIGN_CENTER) }
} else {
drawable?.let { CenteredImageSpan(it, binding.inputAmount.context) }
}
imageSpan?.let {
if (GenericUtils.isCurrencySymbolFirst()) {
spannableString = SpannableString(" $text")
spannableString.setSpan(it, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
spannableString.setSpan(sizeSpan, 1, spannableString.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
} else {
spannableString = SpannableString("$text ")
val len = spannableString.length
spannableString.setSpan(it, len - 1, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
spannableString.setSpan(sizeSpan, 0, len - 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
}
}
} else {
val roomLeft = maxTextWidth - binding.inputAmount.paint.measureText("$text")
val sizeRelative = if (roomLeft < 0) {
val ratio = min(1.0f, (maxTextWidth + roomLeft) / maxTextWidth)
if (ratio == Float.NEGATIVE_INFINITY) {
1.0f
} else {
ratio
}
} else {
1.0f
}
log.info("resizing number: {} to {}", text, sizeRelative)
val sizeSpan = RelativeSizeSpan(sizeRelative)
spannableString.setSpan(sizeSpan, 0, spannableString.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
}
binding.inputAmount.text = spannableString
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.dash.wallet.common.ui.enter_amount

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.text.style.ReplacementSpan

class CenteredImageSpan(private val drawable: Drawable, private val context: Context) : ReplacementSpan() {
override fun getSize(
paint: Paint,
text: CharSequence?,
start: Int,
end: Int,
fm: Paint.FontMetricsInt?
): Int {
val rect = drawable.bounds

fm?.let {
val textHeight = fm.bottom - fm.top
val centerY = fm.top + textHeight / 2

val drawableHeight = rect.bottom - rect.top
val drawableCenterY = rect.top + drawableHeight / 2

// Calculate offset to align image center to text center
val alignmentOffset = drawableCenterY - centerY

it.ascent = fm.ascent + alignmentOffset
it.top = fm.top + alignmentOffset
it.bottom = fm.bottom + alignmentOffset
it.descent = fm.descent + alignmentOffset
}

return rect.right
}

override fun draw(
canvas: Canvas,
text: CharSequence?,
start: Int,
end: Int,
x: Float,
top: Int,
y: Int,
bottom: Int,
paint: Paint
) {
canvas.save()

val fm = paint.fontMetricsInt
val textHeight = fm.descent - fm.ascent
val centerY = y + fm.descent - textHeight / 2

val drawableHeight = drawable.bounds.height()
val drawableCenterY = drawable.bounds.top + drawableHeight / 2

// Align the center of the drawable with the center of the text
val transY = centerY - drawableCenterY

canvas.translate(x, transY.toFloat())
drawable.draw(canvas)

canvas.restore()
}
}
4 changes: 2 additions & 2 deletions common/src/main/java/org/dash/wallet/common/util/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ object Constants {
@JvmField
val NETWORK_PARAMETERS: NetworkParameters = MainNetParams.get()
@JvmField
var ANYPAY_SCHEME = "pay"
val ANYPAY_SCHEME = "pay"
@JvmField
var DASH_SCHEME = "dash"
val DASH_SCHEME = "dash"
}
43 changes: 43 additions & 0 deletions common/src/main/java/org/dash/wallet/common/util/GenericUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ package org.dash.wallet.common.util

import android.os.Build
import android.os.LocaleList
import java.math.BigDecimal
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.NumberFormat
import java.text.ParseException
import java.util.*


/**
* @author Andreas Schildbach
*/
Expand Down Expand Up @@ -55,6 +59,10 @@ object GenericUtils {
return Locale(deviceLocaleLanguage, countryCode)
}

fun getDefaultLocale(): Locale {
return Locale.US
}

/**
* To perform some operations on our fiat values (ex: parse to double, convert fiat to Coin), it needs to be properly formatted
* In case our fiat value is in a currency that has a comma, we need to strip it away so as to have our value as a decimal
Expand Down Expand Up @@ -93,4 +101,39 @@ object GenericUtils {
// the formatter translates 0.01 to 1.00%
return percentFormat.format(percent / 100)
}

fun isCurrencySymbolFirst(): Boolean {
val locale = getDeviceLocale()
// val currency: Currency = Currency.getInstance(locale)
val currencyFormat = NumberFormat.getCurrencyInstance(locale)

val pattern = (currencyFormat as DecimalFormat).toPattern()
println("Currency Pattern: $pattern")

return pattern.startsWith("¤")
}

fun getCurrencyDigits(): Int {
val locale = getDeviceLocale()
val currency: Currency? = Currency.getInstance(locale)
return currency?.defaultFractionDigits ?: 0
}

fun stringToBigDecimal(value: String): BigDecimal {
return try {
val format = NumberFormat.getNumberInstance(getDeviceLocale())
val number = format.parse(value)
if (number != null) BigDecimal(number.toString()) else BigDecimal.ZERO
} catch (e: ParseException) {
BigDecimal.ZERO
}
}

fun toScaledBigDecimal(value: String, localized: Boolean = false, scale: Int = 8): BigDecimal {
return if (localized) {
stringToBigDecimal(value).setScale(scale, RoundingMode.HALF_UP)
} else {
value.toBigDecimal().setScale(scale, RoundingMode.HALF_UP)
}
}
}
28 changes: 4 additions & 24 deletions common/src/main/res/layout/amount_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<LinearLayout
android:id="@+id/input_container"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:clickable="true"
android:focusable="true"
Expand All @@ -35,37 +35,17 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/result_container">

<ImageView
android:id="@+id/input_symbol_dash"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_marginEnd="8dp"
android:src="@drawable/ic_dash_d_white"
android:layout_gravity="center_vertical"
app:tint="@color/content_primary"
tools:tint="@color/content_primary" />

<TextView
android:id="@+id/input_amount"
style="@style/Headline3.Medium"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:textAlignment="center"
android:gravity="center"
android:maxLines="1"
android:lines="1"
tools:text="0" />

<ImageView
android:id="@+id/input_symbol_dash_postfix"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_marginStart="8dp"
android:src="@drawable/ic_dash_d_white"
android:layout_gravity="center_vertical"
android:visibility="gone"
app:tint="@color/content_primary"
tools:tint="@color/content_primary" />

<ImageView
android:id="@+id/input_currency_toggle"
android:layout_width="10dp"
Expand Down
Loading
Loading