fix: align currency and calc widget with ios - #884

Merged
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881
May 7, 2026
Merged

fix: align currency and calc widget with ios#884
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881

Conversation

@piotr-iohk

@piotr-iohkpiotr-iohk commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#881

Description

This PR:

  1. Shows currency symbols in the "Other Currencies" section of the local currency settings (previously only currency codes were displayed)
  2. Truncates 3+ character fiat symbols in the calculator widget icon badge to prevent layout overflow, matching iOS behavior from:
  3. Pre-fills new calculator widgets with a default BTC value of 10 000 and auto-derives the fiat equivalent on first load
  4. Removes auto-clear-on-focus behavior from both BTC and fiat inputs so values persist when switching between fields
  5. Hardens calculator field input by sanitizing pasted and typed values for BTC/fiat and preventing classic-mode fiat from being rehydrated back to zero after clearing
  6. Switches fiat input keyboard to decimal type and uses space as grouping separator instead of comma

Preview

Screen.Recording.2026-04-03.at.17.45.25.mov

QA Notes

1. Currency settings symbols

  1. Go to Settings -> Local currency
  2. Scroll to "Other Currencies"
  3. Verify each currency shows its symbol in parentheses (e.g. "AED (د.إ)")
  4. Verify "Most Used" section still shows symbols as before

2. Calculator widget symbol truncation

  1. Add a calculator widget on the home screen
  2. Change local currency to CHF or XDR
  3. Verify the fiat icon badge shows a single character ("C" or "X"), not the full code
  4. Change to a 1-2 char symbol currency (USD, EUR, PLN) and verify it renders normally
Screen_recording_20260423_071500.webm

3. Calculator widget default value

  1. Remove existing calculator widget (if any)
  2. Add a new calculator widget
  3. Verify BTC field shows "10 000" and fiat field shows the converted amount
  4. Verify both fields are editable without clearing on focus
Screen_recording_20260423_073524.webm

4. Calculator input behavior

  1. Tap fiat field, type a value (e.g. "12.34") — verify decimal input works
  2. Tap BTC field — verify fiat value is preserved (not cleared)
  3. Tap fiat field again — verify BTC value is preserved
  4. Delete all in fiat field — verify you can type a new value including "."
  5. Verify fiat uses space grouping (e.g. "1 234.56" not "1,234.56")
Screen_recording_20260423_080014.webm

5. Calculator paste and clear edge cases

  1. In MODERN denomination, paste malformed BTC input containing punctuation (for example 1000087188..........,,,,,)
  2. Verify BTC shows only the sanitized sat value and does not display pasted punctuation
  3. In CLASSIC denomination, clear fiat completely and verify it stays empty instead of snapping back to 0
  4. Paste 8 into the empty fiat field in CLASSIC denomination and verify it behaves consistently
Screen_recording_20260423_081652.webm

@piotr-iohkpiotr-iohk added this to the 2.2.0 milestone Apr 2, 2026
@piotr-iohkpiotr-iohk self-assigned this Apr 3, 2026
@piotr-iohk
piotr-iohk marked this pull request as ready for review April 3, 2026 15:57
…onents/CalculatorCard.kt
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
@piotr-iohkpiotr-iohk removed this from the 2.2.0 milestone Apr 7, 2026
@piotr-iohk
piotr-iohk marked this pull request as draft April 7, 2026 17:19
@ovitrifovitrif added this to the 2.3.0 milestone Apr 7, 2026
@jvsena42jvsena42 assigned jvsena42 and unassigned piotr-iohk and jvsena42Apr 22, 2026
@jvsena42
jvsena42 marked this pull request as ready for review April 23, 2026 11:18

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

Found 3 issues. See inline comments.

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

@ovitrif

ovitrif commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

@ovitrif

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

Addressing in:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, but I found some issues in fiat input.

issuesFiat.mp4
  1. Delete key deletes all decimals
  2. Delete key when value is 0 adds a decimal first
  3. Can't add decimal if it shows only one
  4. Needs lots of taps on delete key when decimals are hidden

Issue seems to be that, while it doesn't show the 2nd decimal in cases like 1.9, the value is there: 1.90.

1 & 23 & 4
issuesFiat.mp4
issuesFiat2.mp4

Comment on lines +74 to +95
internal fun sanitizeDecimalInput(
raw: String,
locale: Locale = Locale.getDefault(),
maxDecimalPlaces: Int? = null,
): String {
val localDecimal = DecimalFormatSymbols.getInstance(locale).decimalSeparator
val normalized = if (localDecimal == ',') raw.replace(',', '.') else raw
val filtered = normalized.filter { it.isDigit() || it == '.' }
val dotIndex = filtered.indexOf('.')
val singleDot = if (dotIndex == -1) {
filtered
} else {
filtered.substring(0, dotIndex + 1) +
filtered.substring(dotIndex + 1).replace(".", "")
}
if (maxDecimalPlaces == null) return singleDot
val cappedDot = singleDot.indexOf('.')
if (cappedDot == -1) return singleDot
val fraction = singleDot.substring(cappedDot + 1)
if (fraction.length <= maxDecimalPlaces) return singleDot
return singleDot.substring(0, cappedDot + 1) + fraction.take(maxDecimalPlaces)
}

@ovitrifovitrifMay 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: would've been nice to add unit tests, even if it's low complexity, it's still logic.

@ovitrif

Copy link
Copy Markdown
Collaborator

I will add the fixes in my PR which also moves logic to viewmodel:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Merging, more fixes and polishing to be done by PR(s) addressing:

@ovitrif
ovitrif disabled auto-merge May 7, 2026 16:36
@ovitrif
ovitrif merged commit 41ff9c9 into masterMay 7, 2026
18 of 20 checks passed
@ovitrif
ovitrif deleted the fix/currency-widget-consistency-881 branch May 7, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: currency settings and calculator widget inconsistent with iOS

3 participants

@piotr-iohk@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix: align currency and calc widget with ios - #884

Merged
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881
May 7, 2026
Merged

fix: align currency and calc widget with ios#884
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881

Conversation

@piotr-iohk

@piotr-iohkpiotr-iohk commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#881

Description

This PR:

  1. Shows currency symbols in the "Other Currencies" section of the local currency settings (previously only currency codes were displayed)
  2. Truncates 3+ character fiat symbols in the calculator widget icon badge to prevent layout overflow, matching iOS behavior from:
  3. Pre-fills new calculator widgets with a default BTC value of 10 000 and auto-derives the fiat equivalent on first load
  4. Removes auto-clear-on-focus behavior from both BTC and fiat inputs so values persist when switching between fields
  5. Hardens calculator field input by sanitizing pasted and typed values for BTC/fiat and preventing classic-mode fiat from being rehydrated back to zero after clearing
  6. Switches fiat input keyboard to decimal type and uses space as grouping separator instead of comma

Preview

Screen.Recording.2026-04-03.at.17.45.25.mov

QA Notes

1. Currency settings symbols

  1. Go to Settings -> Local currency
  2. Scroll to "Other Currencies"
  3. Verify each currency shows its symbol in parentheses (e.g. "AED (د.إ)")
  4. Verify "Most Used" section still shows symbols as before

2. Calculator widget symbol truncation

  1. Add a calculator widget on the home screen
  2. Change local currency to CHF or XDR
  3. Verify the fiat icon badge shows a single character ("C" or "X"), not the full code
  4. Change to a 1-2 char symbol currency (USD, EUR, PLN) and verify it renders normally
Screen_recording_20260423_071500.webm

3. Calculator widget default value

  1. Remove existing calculator widget (if any)
  2. Add a new calculator widget
  3. Verify BTC field shows "10 000" and fiat field shows the converted amount
  4. Verify both fields are editable without clearing on focus
Screen_recording_20260423_073524.webm

4. Calculator input behavior

  1. Tap fiat field, type a value (e.g. "12.34") — verify decimal input works
  2. Tap BTC field — verify fiat value is preserved (not cleared)
  3. Tap fiat field again — verify BTC value is preserved
  4. Delete all in fiat field — verify you can type a new value including "."
  5. Verify fiat uses space grouping (e.g. "1 234.56" not "1,234.56")
Screen_recording_20260423_080014.webm

5. Calculator paste and clear edge cases

  1. In MODERN denomination, paste malformed BTC input containing punctuation (for example 1000087188..........,,,,,)
  2. Verify BTC shows only the sanitized sat value and does not display pasted punctuation
  3. In CLASSIC denomination, clear fiat completely and verify it stays empty instead of snapping back to 0
  4. Paste 8 into the empty fiat field in CLASSIC denomination and verify it behaves consistently
Screen_recording_20260423_081652.webm

@piotr-iohkpiotr-iohk added this to the 2.2.0 milestone Apr 2, 2026
@piotr-iohkpiotr-iohk self-assigned this Apr 3, 2026
@piotr-iohk
piotr-iohk marked this pull request as ready for review April 3, 2026 15:57
…onents/CalculatorCard.kt
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
@piotr-iohkpiotr-iohk removed this from the 2.2.0 milestone Apr 7, 2026
@piotr-iohk
piotr-iohk marked this pull request as draft April 7, 2026 17:19
@ovitrifovitrif added this to the 2.3.0 milestone Apr 7, 2026
@jvsena42jvsena42 assigned jvsena42 and unassigned piotr-iohk and jvsena42Apr 22, 2026
@jvsena42
jvsena42 marked this pull request as ready for review April 23, 2026 11:18

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

Found 3 issues. See inline comments.

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

@ovitrif

ovitrif commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

@ovitrif

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

Addressing in:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, but I found some issues in fiat input.

issuesFiat.mp4
  1. Delete key deletes all decimals
  2. Delete key when value is 0 adds a decimal first
  3. Can't add decimal if it shows only one
  4. Needs lots of taps on delete key when decimals are hidden

Issue seems to be that, while it doesn't show the 2nd decimal in cases like 1.9, the value is there: 1.90.

1 & 23 & 4
issuesFiat.mp4
issuesFiat2.mp4

Comment on lines +74 to +95
internal fun sanitizeDecimalInput(
raw: String,
locale: Locale = Locale.getDefault(),
maxDecimalPlaces: Int? = null,
): String {
val localDecimal = DecimalFormatSymbols.getInstance(locale).decimalSeparator
val normalized = if (localDecimal == ',') raw.replace(',', '.') else raw
val filtered = normalized.filter { it.isDigit() || it == '.' }
val dotIndex = filtered.indexOf('.')
val singleDot = if (dotIndex == -1) {
filtered
} else {
filtered.substring(0, dotIndex + 1) +
filtered.substring(dotIndex + 1).replace(".", "")
}
if (maxDecimalPlaces == null) return singleDot
val cappedDot = singleDot.indexOf('.')
if (cappedDot == -1) return singleDot
val fraction = singleDot.substring(cappedDot + 1)
if (fraction.length <= maxDecimalPlaces) return singleDot
return singleDot.substring(0, cappedDot + 1) + fraction.take(maxDecimalPlaces)
}

@ovitrifovitrifMay 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: would've been nice to add unit tests, even if it's low complexity, it's still logic.

@ovitrif

Copy link
Copy Markdown
Collaborator

I will add the fixes in my PR which also moves logic to viewmodel:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Merging, more fixes and polishing to be done by PR(s) addressing:

@ovitrif
ovitrif disabled auto-merge May 7, 2026 16:36
@ovitrif
ovitrif merged commit 41ff9c9 into masterMay 7, 2026
18 of 20 checks passed
@ovitrif
ovitrif deleted the fix/currency-widget-consistency-881 branch May 7, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: currency settings and calculator widget inconsistent with iOS

3 participants

@piotr-iohk@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: align currency and calc widget with ios - #884

Merged
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881
May 7, 2026
Merged

fix: align currency and calc widget with ios#884
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881

Conversation

@piotr-iohk

@piotr-iohkpiotr-iohk commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#881

Description

This PR:

  1. Shows currency symbols in the "Other Currencies" section of the local currency settings (previously only currency codes were displayed)
  2. Truncates 3+ character fiat symbols in the calculator widget icon badge to prevent layout overflow, matching iOS behavior from:
  3. Pre-fills new calculator widgets with a default BTC value of 10 000 and auto-derives the fiat equivalent on first load
  4. Removes auto-clear-on-focus behavior from both BTC and fiat inputs so values persist when switching between fields
  5. Hardens calculator field input by sanitizing pasted and typed values for BTC/fiat and preventing classic-mode fiat from being rehydrated back to zero after clearing
  6. Switches fiat input keyboard to decimal type and uses space as grouping separator instead of comma

Preview

Screen.Recording.2026-04-03.at.17.45.25.mov

QA Notes

1. Currency settings symbols

  1. Go to Settings -> Local currency
  2. Scroll to "Other Currencies"
  3. Verify each currency shows its symbol in parentheses (e.g. "AED (د.إ)")
  4. Verify "Most Used" section still shows symbols as before

2. Calculator widget symbol truncation

  1. Add a calculator widget on the home screen
  2. Change local currency to CHF or XDR
  3. Verify the fiat icon badge shows a single character ("C" or "X"), not the full code
  4. Change to a 1-2 char symbol currency (USD, EUR, PLN) and verify it renders normally
Screen_recording_20260423_071500.webm

3. Calculator widget default value

  1. Remove existing calculator widget (if any)
  2. Add a new calculator widget
  3. Verify BTC field shows "10 000" and fiat field shows the converted amount
  4. Verify both fields are editable without clearing on focus
Screen_recording_20260423_073524.webm

4. Calculator input behavior

  1. Tap fiat field, type a value (e.g. "12.34") — verify decimal input works
  2. Tap BTC field — verify fiat value is preserved (not cleared)
  3. Tap fiat field again — verify BTC value is preserved
  4. Delete all in fiat field — verify you can type a new value including "."
  5. Verify fiat uses space grouping (e.g. "1 234.56" not "1,234.56")
Screen_recording_20260423_080014.webm

5. Calculator paste and clear edge cases

  1. In MODERN denomination, paste malformed BTC input containing punctuation (for example 1000087188..........,,,,,)
  2. Verify BTC shows only the sanitized sat value and does not display pasted punctuation
  3. In CLASSIC denomination, clear fiat completely and verify it stays empty instead of snapping back to 0
  4. Paste 8 into the empty fiat field in CLASSIC denomination and verify it behaves consistently
Screen_recording_20260423_081652.webm

@piotr-iohkpiotr-iohk added this to the 2.2.0 milestone Apr 2, 2026
@piotr-iohkpiotr-iohk self-assigned this Apr 3, 2026
@piotr-iohk
piotr-iohk marked this pull request as ready for review April 3, 2026 15:57
…onents/CalculatorCard.kt
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
@piotr-iohkpiotr-iohk removed this from the 2.2.0 milestone Apr 7, 2026
@piotr-iohk
piotr-iohk marked this pull request as draft April 7, 2026 17:19
@ovitrifovitrif added this to the 2.3.0 milestone Apr 7, 2026
@jvsena42jvsena42 assigned jvsena42 and unassigned piotr-iohk and jvsena42Apr 22, 2026
@jvsena42
jvsena42 marked this pull request as ready for review April 23, 2026 11:18

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

Found 3 issues. See inline comments.

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

@ovitrif

ovitrif commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

@ovitrif

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

Addressing in:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, but I found some issues in fiat input.

issuesFiat.mp4
  1. Delete key deletes all decimals
  2. Delete key when value is 0 adds a decimal first
  3. Can't add decimal if it shows only one
  4. Needs lots of taps on delete key when decimals are hidden

Issue seems to be that, while it doesn't show the 2nd decimal in cases like 1.9, the value is there: 1.90.

1 & 23 & 4
issuesFiat.mp4
issuesFiat2.mp4

Comment on lines +74 to +95
internal fun sanitizeDecimalInput(
raw: String,
locale: Locale = Locale.getDefault(),
maxDecimalPlaces: Int? = null,
): String {
val localDecimal = DecimalFormatSymbols.getInstance(locale).decimalSeparator
val normalized = if (localDecimal == ',') raw.replace(',', '.') else raw
val filtered = normalized.filter { it.isDigit() || it == '.' }
val dotIndex = filtered.indexOf('.')
val singleDot = if (dotIndex == -1) {
filtered
} else {
filtered.substring(0, dotIndex + 1) +
filtered.substring(dotIndex + 1).replace(".", "")
}
if (maxDecimalPlaces == null) return singleDot
val cappedDot = singleDot.indexOf('.')
if (cappedDot == -1) return singleDot
val fraction = singleDot.substring(cappedDot + 1)
if (fraction.length <= maxDecimalPlaces) return singleDot
return singleDot.substring(0, cappedDot + 1) + fraction.take(maxDecimalPlaces)
}

@ovitrifovitrifMay 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: would've been nice to add unit tests, even if it's low complexity, it's still logic.

@ovitrif

Copy link
Copy Markdown
Collaborator

I will add the fixes in my PR which also moves logic to viewmodel:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Merging, more fixes and polishing to be done by PR(s) addressing:

@ovitrif
ovitrif disabled auto-merge May 7, 2026 16:36
@ovitrif
ovitrif merged commit 41ff9c9 into masterMay 7, 2026
18 of 20 checks passed
@ovitrif
ovitrif deleted the fix/currency-widget-consistency-881 branch May 7, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: currency settings and calculator widget inconsistent with iOS

3 participants

@piotr-iohk@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: align currency and calc widget with ios - #884

Merged
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881
May 7, 2026
Merged

fix: align currency and calc widget with ios#884
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881

Conversation

@piotr-iohk

@piotr-iohkpiotr-iohk commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#881

Description

This PR:

  1. Shows currency symbols in the "Other Currencies" section of the local currency settings (previously only currency codes were displayed)
  2. Truncates 3+ character fiat symbols in the calculator widget icon badge to prevent layout overflow, matching iOS behavior from:
  3. Pre-fills new calculator widgets with a default BTC value of 10 000 and auto-derives the fiat equivalent on first load
  4. Removes auto-clear-on-focus behavior from both BTC and fiat inputs so values persist when switching between fields
  5. Hardens calculator field input by sanitizing pasted and typed values for BTC/fiat and preventing classic-mode fiat from being rehydrated back to zero after clearing
  6. Switches fiat input keyboard to decimal type and uses space as grouping separator instead of comma

Preview

Screen.Recording.2026-04-03.at.17.45.25.mov

QA Notes

1. Currency settings symbols

  1. Go to Settings -> Local currency
  2. Scroll to "Other Currencies"
  3. Verify each currency shows its symbol in parentheses (e.g. "AED (د.إ)")
  4. Verify "Most Used" section still shows symbols as before

2. Calculator widget symbol truncation

  1. Add a calculator widget on the home screen
  2. Change local currency to CHF or XDR
  3. Verify the fiat icon badge shows a single character ("C" or "X"), not the full code
  4. Change to a 1-2 char symbol currency (USD, EUR, PLN) and verify it renders normally
Screen_recording_20260423_071500.webm

3. Calculator widget default value

  1. Remove existing calculator widget (if any)
  2. Add a new calculator widget
  3. Verify BTC field shows "10 000" and fiat field shows the converted amount
  4. Verify both fields are editable without clearing on focus
Screen_recording_20260423_073524.webm

4. Calculator input behavior

  1. Tap fiat field, type a value (e.g. "12.34") — verify decimal input works
  2. Tap BTC field — verify fiat value is preserved (not cleared)
  3. Tap fiat field again — verify BTC value is preserved
  4. Delete all in fiat field — verify you can type a new value including "."
  5. Verify fiat uses space grouping (e.g. "1 234.56" not "1,234.56")
Screen_recording_20260423_080014.webm

5. Calculator paste and clear edge cases

  1. In MODERN denomination, paste malformed BTC input containing punctuation (for example 1000087188..........,,,,,)
  2. Verify BTC shows only the sanitized sat value and does not display pasted punctuation
  3. In CLASSIC denomination, clear fiat completely and verify it stays empty instead of snapping back to 0
  4. Paste 8 into the empty fiat field in CLASSIC denomination and verify it behaves consistently
Screen_recording_20260423_081652.webm

@piotr-iohkpiotr-iohk added this to the 2.2.0 milestone Apr 2, 2026
@piotr-iohkpiotr-iohk self-assigned this Apr 3, 2026
@piotr-iohk
piotr-iohk marked this pull request as ready for review April 3, 2026 15:57
…onents/CalculatorCard.kt
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
@piotr-iohkpiotr-iohk removed this from the 2.2.0 milestone Apr 7, 2026
@piotr-iohk
piotr-iohk marked this pull request as draft April 7, 2026 17:19
@ovitrifovitrif added this to the 2.3.0 milestone Apr 7, 2026
@jvsena42jvsena42 assigned jvsena42 and unassigned piotr-iohk and jvsena42Apr 22, 2026
@jvsena42
jvsena42 marked this pull request as ready for review April 23, 2026 11:18

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

Found 3 issues. See inline comments.

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

@ovitrif

ovitrif commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

@ovitrif

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

Addressing in:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, but I found some issues in fiat input.

issuesFiat.mp4
  1. Delete key deletes all decimals
  2. Delete key when value is 0 adds a decimal first
  3. Can't add decimal if it shows only one
  4. Needs lots of taps on delete key when decimals are hidden

Issue seems to be that, while it doesn't show the 2nd decimal in cases like 1.9, the value is there: 1.90.

1 & 23 & 4
issuesFiat.mp4
issuesFiat2.mp4

Comment on lines +74 to +95
internal fun sanitizeDecimalInput(
raw: String,
locale: Locale = Locale.getDefault(),
maxDecimalPlaces: Int? = null,
): String {
val localDecimal = DecimalFormatSymbols.getInstance(locale).decimalSeparator
val normalized = if (localDecimal == ',') raw.replace(',', '.') else raw
val filtered = normalized.filter { it.isDigit() || it == '.' }
val dotIndex = filtered.indexOf('.')
val singleDot = if (dotIndex == -1) {
filtered
} else {
filtered.substring(0, dotIndex + 1) +
filtered.substring(dotIndex + 1).replace(".", "")
}
if (maxDecimalPlaces == null) return singleDot
val cappedDot = singleDot.indexOf('.')
if (cappedDot == -1) return singleDot
val fraction = singleDot.substring(cappedDot + 1)
if (fraction.length <= maxDecimalPlaces) return singleDot
return singleDot.substring(0, cappedDot + 1) + fraction.take(maxDecimalPlaces)
}

@ovitrifovitrifMay 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: would've been nice to add unit tests, even if it's low complexity, it's still logic.

@ovitrif

Copy link
Copy Markdown
Collaborator

I will add the fixes in my PR which also moves logic to viewmodel:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Merging, more fixes and polishing to be done by PR(s) addressing:

@ovitrif
ovitrif disabled auto-merge May 7, 2026 16:36
@ovitrif
ovitrif merged commit 41ff9c9 into masterMay 7, 2026
18 of 20 checks passed
@ovitrif
ovitrif deleted the fix/currency-widget-consistency-881 branch May 7, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: currency settings and calculator widget inconsistent with iOS

3 participants

@piotr-iohk@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix: align currency and calc widget with ios - #884

Merged
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881
May 7, 2026
Merged

fix: align currency and calc widget with ios#884
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881

Conversation

@piotr-iohk

@piotr-iohkpiotr-iohk commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#881

Description

This PR:

  1. Shows currency symbols in the "Other Currencies" section of the local currency settings (previously only currency codes were displayed)
  2. Truncates 3+ character fiat symbols in the calculator widget icon badge to prevent layout overflow, matching iOS behavior from:
  3. Pre-fills new calculator widgets with a default BTC value of 10 000 and auto-derives the fiat equivalent on first load
  4. Removes auto-clear-on-focus behavior from both BTC and fiat inputs so values persist when switching between fields
  5. Hardens calculator field input by sanitizing pasted and typed values for BTC/fiat and preventing classic-mode fiat from being rehydrated back to zero after clearing
  6. Switches fiat input keyboard to decimal type and uses space as grouping separator instead of comma

Preview

Screen.Recording.2026-04-03.at.17.45.25.mov

QA Notes

1. Currency settings symbols

  1. Go to Settings -> Local currency
  2. Scroll to "Other Currencies"
  3. Verify each currency shows its symbol in parentheses (e.g. "AED (د.إ)")
  4. Verify "Most Used" section still shows symbols as before

2. Calculator widget symbol truncation

  1. Add a calculator widget on the home screen
  2. Change local currency to CHF or XDR
  3. Verify the fiat icon badge shows a single character ("C" or "X"), not the full code
  4. Change to a 1-2 char symbol currency (USD, EUR, PLN) and verify it renders normally
Screen_recording_20260423_071500.webm

3. Calculator widget default value

  1. Remove existing calculator widget (if any)
  2. Add a new calculator widget
  3. Verify BTC field shows "10 000" and fiat field shows the converted amount
  4. Verify both fields are editable without clearing on focus
Screen_recording_20260423_073524.webm

4. Calculator input behavior

  1. Tap fiat field, type a value (e.g. "12.34") — verify decimal input works
  2. Tap BTC field — verify fiat value is preserved (not cleared)
  3. Tap fiat field again — verify BTC value is preserved
  4. Delete all in fiat field — verify you can type a new value including "."
  5. Verify fiat uses space grouping (e.g. "1 234.56" not "1,234.56")
Screen_recording_20260423_080014.webm

5. Calculator paste and clear edge cases

  1. In MODERN denomination, paste malformed BTC input containing punctuation (for example 1000087188..........,,,,,)
  2. Verify BTC shows only the sanitized sat value and does not display pasted punctuation
  3. In CLASSIC denomination, clear fiat completely and verify it stays empty instead of snapping back to 0
  4. Paste 8 into the empty fiat field in CLASSIC denomination and verify it behaves consistently
Screen_recording_20260423_081652.webm

@piotr-iohkpiotr-iohk added this to the 2.2.0 milestone Apr 2, 2026
@piotr-iohkpiotr-iohk self-assigned this Apr 3, 2026
@piotr-iohk
piotr-iohk marked this pull request as ready for review April 3, 2026 15:57
…onents/CalculatorCard.kt
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
@piotr-iohkpiotr-iohk removed this from the 2.2.0 milestone Apr 7, 2026
@piotr-iohk
piotr-iohk marked this pull request as draft April 7, 2026 17:19
@ovitrifovitrif added this to the 2.3.0 milestone Apr 7, 2026
@jvsena42jvsena42 assigned jvsena42 and unassigned piotr-iohk and jvsena42Apr 22, 2026
@jvsena42
jvsena42 marked this pull request as ready for review April 23, 2026 11:18

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

Found 3 issues. See inline comments.

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

@ovitrif

ovitrif commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

@ovitrif

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

Addressing in:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, but I found some issues in fiat input.

issuesFiat.mp4
  1. Delete key deletes all decimals
  2. Delete key when value is 0 adds a decimal first
  3. Can't add decimal if it shows only one
  4. Needs lots of taps on delete key when decimals are hidden

Issue seems to be that, while it doesn't show the 2nd decimal in cases like 1.9, the value is there: 1.90.

1 & 23 & 4
issuesFiat.mp4
issuesFiat2.mp4

Comment on lines +74 to +95
internal fun sanitizeDecimalInput(
raw: String,
locale: Locale = Locale.getDefault(),
maxDecimalPlaces: Int? = null,
): String {
val localDecimal = DecimalFormatSymbols.getInstance(locale).decimalSeparator
val normalized = if (localDecimal == ',') raw.replace(',', '.') else raw
val filtered = normalized.filter { it.isDigit() || it == '.' }
val dotIndex = filtered.indexOf('.')
val singleDot = if (dotIndex == -1) {
filtered
} else {
filtered.substring(0, dotIndex + 1) +
filtered.substring(dotIndex + 1).replace(".", "")
}
if (maxDecimalPlaces == null) return singleDot
val cappedDot = singleDot.indexOf('.')
if (cappedDot == -1) return singleDot
val fraction = singleDot.substring(cappedDot + 1)
if (fraction.length <= maxDecimalPlaces) return singleDot
return singleDot.substring(0, cappedDot + 1) + fraction.take(maxDecimalPlaces)
}

@ovitrifovitrifMay 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: would've been nice to add unit tests, even if it's low complexity, it's still logic.

@ovitrif

Copy link
Copy Markdown
Collaborator

I will add the fixes in my PR which also moves logic to viewmodel:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Merging, more fixes and polishing to be done by PR(s) addressing:

@ovitrif
ovitrif disabled auto-merge May 7, 2026 16:36
@ovitrif
ovitrif merged commit 41ff9c9 into masterMay 7, 2026
18 of 20 checks passed
@ovitrif
ovitrif deleted the fix/currency-widget-consistency-881 branch May 7, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: currency settings and calculator widget inconsistent with iOS

3 participants

@piotr-iohk@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: align currency and calc widget with ios - #884

Merged
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881
May 7, 2026
Merged

fix: align currency and calc widget with ios#884
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881

Conversation

@piotr-iohk

@piotr-iohkpiotr-iohk commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#881

Description

This PR:

  1. Shows currency symbols in the "Other Currencies" section of the local currency settings (previously only currency codes were displayed)
  2. Truncates 3+ character fiat symbols in the calculator widget icon badge to prevent layout overflow, matching iOS behavior from:
  3. Pre-fills new calculator widgets with a default BTC value of 10 000 and auto-derives the fiat equivalent on first load
  4. Removes auto-clear-on-focus behavior from both BTC and fiat inputs so values persist when switching between fields
  5. Hardens calculator field input by sanitizing pasted and typed values for BTC/fiat and preventing classic-mode fiat from being rehydrated back to zero after clearing
  6. Switches fiat input keyboard to decimal type and uses space as grouping separator instead of comma

Preview

Screen.Recording.2026-04-03.at.17.45.25.mov

QA Notes

1. Currency settings symbols

  1. Go to Settings -> Local currency
  2. Scroll to "Other Currencies"
  3. Verify each currency shows its symbol in parentheses (e.g. "AED (د.إ)")
  4. Verify "Most Used" section still shows symbols as before

2. Calculator widget symbol truncation

  1. Add a calculator widget on the home screen
  2. Change local currency to CHF or XDR
  3. Verify the fiat icon badge shows a single character ("C" or "X"), not the full code
  4. Change to a 1-2 char symbol currency (USD, EUR, PLN) and verify it renders normally
Screen_recording_20260423_071500.webm

3. Calculator widget default value

  1. Remove existing calculator widget (if any)
  2. Add a new calculator widget
  3. Verify BTC field shows "10 000" and fiat field shows the converted amount
  4. Verify both fields are editable without clearing on focus
Screen_recording_20260423_073524.webm

4. Calculator input behavior

  1. Tap fiat field, type a value (e.g. "12.34") — verify decimal input works
  2. Tap BTC field — verify fiat value is preserved (not cleared)
  3. Tap fiat field again — verify BTC value is preserved
  4. Delete all in fiat field — verify you can type a new value including "."
  5. Verify fiat uses space grouping (e.g. "1 234.56" not "1,234.56")
Screen_recording_20260423_080014.webm

5. Calculator paste and clear edge cases

  1. In MODERN denomination, paste malformed BTC input containing punctuation (for example 1000087188..........,,,,,)
  2. Verify BTC shows only the sanitized sat value and does not display pasted punctuation
  3. In CLASSIC denomination, clear fiat completely and verify it stays empty instead of snapping back to 0
  4. Paste 8 into the empty fiat field in CLASSIC denomination and verify it behaves consistently
Screen_recording_20260423_081652.webm

@piotr-iohkpiotr-iohk added this to the 2.2.0 milestone Apr 2, 2026
@piotr-iohkpiotr-iohk self-assigned this Apr 3, 2026
@piotr-iohk
piotr-iohk marked this pull request as ready for review April 3, 2026 15:57
…onents/CalculatorCard.kt
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
@piotr-iohkpiotr-iohk removed this from the 2.2.0 milestone Apr 7, 2026
@piotr-iohk
piotr-iohk marked this pull request as draft April 7, 2026 17:19
@ovitrifovitrif added this to the 2.3.0 milestone Apr 7, 2026
@jvsena42jvsena42 assigned jvsena42 and unassigned piotr-iohk and jvsena42Apr 22, 2026
@jvsena42
jvsena42 marked this pull request as ready for review April 23, 2026 11:18

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

Found 3 issues. See inline comments.

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

@ovitrif

ovitrif commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

@ovitrif

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

Addressing in:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, but I found some issues in fiat input.

issuesFiat.mp4
  1. Delete key deletes all decimals
  2. Delete key when value is 0 adds a decimal first
  3. Can't add decimal if it shows only one
  4. Needs lots of taps on delete key when decimals are hidden

Issue seems to be that, while it doesn't show the 2nd decimal in cases like 1.9, the value is there: 1.90.

1 & 23 & 4
issuesFiat.mp4
issuesFiat2.mp4

Comment on lines +74 to +95
internal fun sanitizeDecimalInput(
raw: String,
locale: Locale = Locale.getDefault(),
maxDecimalPlaces: Int? = null,
): String {
val localDecimal = DecimalFormatSymbols.getInstance(locale).decimalSeparator
val normalized = if (localDecimal == ',') raw.replace(',', '.') else raw
val filtered = normalized.filter { it.isDigit() || it == '.' }
val dotIndex = filtered.indexOf('.')
val singleDot = if (dotIndex == -1) {
filtered
} else {
filtered.substring(0, dotIndex + 1) +
filtered.substring(dotIndex + 1).replace(".", "")
}
if (maxDecimalPlaces == null) return singleDot
val cappedDot = singleDot.indexOf('.')
if (cappedDot == -1) return singleDot
val fraction = singleDot.substring(cappedDot + 1)
if (fraction.length <= maxDecimalPlaces) return singleDot
return singleDot.substring(0, cappedDot + 1) + fraction.take(maxDecimalPlaces)
}

@ovitrifovitrifMay 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: would've been nice to add unit tests, even if it's low complexity, it's still logic.

@ovitrif

Copy link
Copy Markdown
Collaborator

I will add the fixes in my PR which also moves logic to viewmodel:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Merging, more fixes and polishing to be done by PR(s) addressing:

@ovitrif
ovitrif disabled auto-merge May 7, 2026 16:36
@ovitrif
ovitrif merged commit 41ff9c9 into masterMay 7, 2026
18 of 20 checks passed
@ovitrif
ovitrif deleted the fix/currency-widget-consistency-881 branch May 7, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: currency settings and calculator widget inconsistent with iOS

3 participants

@piotr-iohk@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: align currency and calc widget with ios - #884

Merged
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881
May 7, 2026
Merged

fix: align currency and calc widget with ios#884
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881

Conversation

@piotr-iohk

@piotr-iohkpiotr-iohk commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#881

Description

This PR:

  1. Shows currency symbols in the "Other Currencies" section of the local currency settings (previously only currency codes were displayed)
  2. Truncates 3+ character fiat symbols in the calculator widget icon badge to prevent layout overflow, matching iOS behavior from:
  3. Pre-fills new calculator widgets with a default BTC value of 10 000 and auto-derives the fiat equivalent on first load
  4. Removes auto-clear-on-focus behavior from both BTC and fiat inputs so values persist when switching between fields
  5. Hardens calculator field input by sanitizing pasted and typed values for BTC/fiat and preventing classic-mode fiat from being rehydrated back to zero after clearing
  6. Switches fiat input keyboard to decimal type and uses space as grouping separator instead of comma

Preview

Screen.Recording.2026-04-03.at.17.45.25.mov

QA Notes

1. Currency settings symbols

  1. Go to Settings -> Local currency
  2. Scroll to "Other Currencies"
  3. Verify each currency shows its symbol in parentheses (e.g. "AED (د.إ)")
  4. Verify "Most Used" section still shows symbols as before

2. Calculator widget symbol truncation

  1. Add a calculator widget on the home screen
  2. Change local currency to CHF or XDR
  3. Verify the fiat icon badge shows a single character ("C" or "X"), not the full code
  4. Change to a 1-2 char symbol currency (USD, EUR, PLN) and verify it renders normally
Screen_recording_20260423_071500.webm

3. Calculator widget default value

  1. Remove existing calculator widget (if any)
  2. Add a new calculator widget
  3. Verify BTC field shows "10 000" and fiat field shows the converted amount
  4. Verify both fields are editable without clearing on focus
Screen_recording_20260423_073524.webm

4. Calculator input behavior

  1. Tap fiat field, type a value (e.g. "12.34") — verify decimal input works
  2. Tap BTC field — verify fiat value is preserved (not cleared)
  3. Tap fiat field again — verify BTC value is preserved
  4. Delete all in fiat field — verify you can type a new value including "."
  5. Verify fiat uses space grouping (e.g. "1 234.56" not "1,234.56")
Screen_recording_20260423_080014.webm

5. Calculator paste and clear edge cases

  1. In MODERN denomination, paste malformed BTC input containing punctuation (for example 1000087188..........,,,,,)
  2. Verify BTC shows only the sanitized sat value and does not display pasted punctuation
  3. In CLASSIC denomination, clear fiat completely and verify it stays empty instead of snapping back to 0
  4. Paste 8 into the empty fiat field in CLASSIC denomination and verify it behaves consistently
Screen_recording_20260423_081652.webm

@piotr-iohkpiotr-iohk added this to the 2.2.0 milestone Apr 2, 2026
@piotr-iohkpiotr-iohk self-assigned this Apr 3, 2026
@piotr-iohk
piotr-iohk marked this pull request as ready for review April 3, 2026 15:57
…onents/CalculatorCard.kt
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
@piotr-iohkpiotr-iohk removed this from the 2.2.0 milestone Apr 7, 2026
@piotr-iohk
piotr-iohk marked this pull request as draft April 7, 2026 17:19
@ovitrifovitrif added this to the 2.3.0 milestone Apr 7, 2026
@jvsena42jvsena42 assigned jvsena42 and unassigned piotr-iohk and jvsena42Apr 22, 2026
@jvsena42
jvsena42 marked this pull request as ready for review April 23, 2026 11:18

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

Found 3 issues. See inline comments.

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

@ovitrif

ovitrif commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

@ovitrif

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

Addressing in:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, but I found some issues in fiat input.

issuesFiat.mp4
  1. Delete key deletes all decimals
  2. Delete key when value is 0 adds a decimal first
  3. Can't add decimal if it shows only one
  4. Needs lots of taps on delete key when decimals are hidden

Issue seems to be that, while it doesn't show the 2nd decimal in cases like 1.9, the value is there: 1.90.

1 & 23 & 4
issuesFiat.mp4
issuesFiat2.mp4

Comment on lines +74 to +95
internal fun sanitizeDecimalInput(
raw: String,
locale: Locale = Locale.getDefault(),
maxDecimalPlaces: Int? = null,
): String {
val localDecimal = DecimalFormatSymbols.getInstance(locale).decimalSeparator
val normalized = if (localDecimal == ',') raw.replace(',', '.') else raw
val filtered = normalized.filter { it.isDigit() || it == '.' }
val dotIndex = filtered.indexOf('.')
val singleDot = if (dotIndex == -1) {
filtered
} else {
filtered.substring(0, dotIndex + 1) +
filtered.substring(dotIndex + 1).replace(".", "")
}
if (maxDecimalPlaces == null) return singleDot
val cappedDot = singleDot.indexOf('.')
if (cappedDot == -1) return singleDot
val fraction = singleDot.substring(cappedDot + 1)
if (fraction.length <= maxDecimalPlaces) return singleDot
return singleDot.substring(0, cappedDot + 1) + fraction.take(maxDecimalPlaces)
}

@ovitrifovitrifMay 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: would've been nice to add unit tests, even if it's low complexity, it's still logic.

@ovitrif

Copy link
Copy Markdown
Collaborator

I will add the fixes in my PR which also moves logic to viewmodel:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Merging, more fixes and polishing to be done by PR(s) addressing:

@ovitrif
ovitrif disabled auto-merge May 7, 2026 16:36
@ovitrif
ovitrif merged commit 41ff9c9 into masterMay 7, 2026
18 of 20 checks passed
@ovitrif
ovitrif deleted the fix/currency-widget-consistency-881 branch May 7, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: currency settings and calculator widget inconsistent with iOS

3 participants

@piotr-iohk@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix: align currency and calc widget with ios - #884

Merged
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881
May 7, 2026
Merged

fix: align currency and calc widget with ios#884
ovitrif merged 29 commits into
masterfrom
fix/currency-widget-consistency-881

Conversation

@piotr-iohk

@piotr-iohkpiotr-iohk commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#881

Description

This PR:

  1. Shows currency symbols in the "Other Currencies" section of the local currency settings (previously only currency codes were displayed)
  2. Truncates 3+ character fiat symbols in the calculator widget icon badge to prevent layout overflow, matching iOS behavior from:
  3. Pre-fills new calculator widgets with a default BTC value of 10 000 and auto-derives the fiat equivalent on first load
  4. Removes auto-clear-on-focus behavior from both BTC and fiat inputs so values persist when switching between fields
  5. Hardens calculator field input by sanitizing pasted and typed values for BTC/fiat and preventing classic-mode fiat from being rehydrated back to zero after clearing
  6. Switches fiat input keyboard to decimal type and uses space as grouping separator instead of comma

Preview

Screen.Recording.2026-04-03.at.17.45.25.mov

QA Notes

1. Currency settings symbols

  1. Go to Settings -> Local currency
  2. Scroll to "Other Currencies"
  3. Verify each currency shows its symbol in parentheses (e.g. "AED (د.إ)")
  4. Verify "Most Used" section still shows symbols as before

2. Calculator widget symbol truncation

  1. Add a calculator widget on the home screen
  2. Change local currency to CHF or XDR
  3. Verify the fiat icon badge shows a single character ("C" or "X"), not the full code
  4. Change to a 1-2 char symbol currency (USD, EUR, PLN) and verify it renders normally
Screen_recording_20260423_071500.webm

3. Calculator widget default value

  1. Remove existing calculator widget (if any)
  2. Add a new calculator widget
  3. Verify BTC field shows "10 000" and fiat field shows the converted amount
  4. Verify both fields are editable without clearing on focus
Screen_recording_20260423_073524.webm

4. Calculator input behavior

  1. Tap fiat field, type a value (e.g. "12.34") — verify decimal input works
  2. Tap BTC field — verify fiat value is preserved (not cleared)
  3. Tap fiat field again — verify BTC value is preserved
  4. Delete all in fiat field — verify you can type a new value including "."
  5. Verify fiat uses space grouping (e.g. "1 234.56" not "1,234.56")
Screen_recording_20260423_080014.webm

5. Calculator paste and clear edge cases

  1. In MODERN denomination, paste malformed BTC input containing punctuation (for example 1000087188..........,,,,,)
  2. Verify BTC shows only the sanitized sat value and does not display pasted punctuation
  3. In CLASSIC denomination, clear fiat completely and verify it stays empty instead of snapping back to 0
  4. Paste 8 into the empty fiat field in CLASSIC denomination and verify it behaves consistently
Screen_recording_20260423_081652.webm

@piotr-iohkpiotr-iohk added this to the 2.2.0 milestone Apr 2, 2026
@piotr-iohkpiotr-iohk self-assigned this Apr 3, 2026
@piotr-iohk
piotr-iohk marked this pull request as ready for review April 3, 2026 15:57
…onents/CalculatorCard.kt
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
@piotr-iohkpiotr-iohk removed this from the 2.2.0 milestone Apr 7, 2026
@piotr-iohk
piotr-iohk marked this pull request as draft April 7, 2026 17:19
@ovitrifovitrif added this to the 2.3.0 milestone Apr 7, 2026
@jvsena42jvsena42 assigned jvsena42 and unassigned piotr-iohk and jvsena42Apr 22, 2026
@jvsena42
jvsena42 marked this pull request as ready for review April 23, 2026 11:18

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

Found 3 issues. See inline comments.

@claudeclaudeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review

@ovitrif

ovitrif commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

@ovitrif

Copy link
Copy Markdown
Collaborator

Most of the logic added to the @Composable functions should live inside the viewmodel. I'm working on a refactor.

Addressing in:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, but I found some issues in fiat input.

issuesFiat.mp4
  1. Delete key deletes all decimals
  2. Delete key when value is 0 adds a decimal first
  3. Can't add decimal if it shows only one
  4. Needs lots of taps on delete key when decimals are hidden

Issue seems to be that, while it doesn't show the 2nd decimal in cases like 1.9, the value is there: 1.90.

1 & 23 & 4
issuesFiat.mp4
issuesFiat2.mp4

Comment on lines +74 to +95
internal fun sanitizeDecimalInput(
raw: String,
locale: Locale = Locale.getDefault(),
maxDecimalPlaces: Int? = null,
): String {
val localDecimal = DecimalFormatSymbols.getInstance(locale).decimalSeparator
val normalized = if (localDecimal == ',') raw.replace(',', '.') else raw
val filtered = normalized.filter { it.isDigit() || it == '.' }
val dotIndex = filtered.indexOf('.')
val singleDot = if (dotIndex == -1) {
filtered
} else {
filtered.substring(0, dotIndex + 1) +
filtered.substring(dotIndex + 1).replace(".", "")
}
if (maxDecimalPlaces == null) return singleDot
val cappedDot = singleDot.indexOf('.')
if (cappedDot == -1) return singleDot
val fraction = singleDot.substring(cappedDot + 1)
if (fraction.length <= maxDecimalPlaces) return singleDot
return singleDot.substring(0, cappedDot + 1) + fraction.take(maxDecimalPlaces)
}

@ovitrifovitrifMay 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: would've been nice to add unit tests, even if it's low complexity, it's still logic.

@ovitrif

Copy link
Copy Markdown
Collaborator

I will add the fixes in my PR which also moves logic to viewmodel:

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Merging, more fixes and polishing to be done by PR(s) addressing:

@ovitrif
ovitrif disabled auto-merge May 7, 2026 16:36
@ovitrif
ovitrif merged commit 41ff9c9 into masterMay 7, 2026
18 of 20 checks passed
@ovitrif
ovitrif deleted the fix/currency-widget-consistency-881 branch May 7, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: currency settings and calculator widget inconsistent with iOS

3 participants

@piotr-iohk@ovitrif@jvsena42