Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2e4cf91
fix: crash when locale has incomplete string arrays indexed by enum o…
HashEngineering Jul 21, 2026
6cba285
fix: crash from uncaught SocketTimeoutException in Maya fiat rate fetch
HashEngineering Jul 28, 2026
d950630
fix: crash opening single-tx CoinJoin/CrowdNode groups from tx list
HashEngineering Jul 28, 2026
add36c3
chore: enable parallel Gradle sync, add explore test databases
HashEngineering Jul 28, 2026
f0056c4
fix: review fixes for Maya rate refresh and gradle.properties
HashEngineering Jul 29, 2026
bf0e042
fix: surface SwapKit below-minimum quotes as an inline amount error
HashEngineering Aug 5, 2026
e7efda2
fix: keep the sell amount's currency in step with the picker
HashEngineering Aug 7, 2026
3b38d1c
fix: sweep the wallet for a fiat- or crypto-anchored Maya MAX swap
HashEngineering Aug 7, 2026
9eaa900
fix: log Imgur response body on profile picture upload failure
HashEngineering Aug 7, 2026
5583a65
fix: black 'Enter PIN' text on lock screen after dark mode sweep
HashEngineering Aug 7, 2026
70cd6d1
fix(anr): stop touching the dashj wallet on the main thread at 1 Hz d…
HashEngineering Aug 10, 2026
747b701
chore: update dashj to 22.0.5-SNAPSHOT
HashEngineering Aug 11, 2026
b06c064
fix: avoid racy background-thread read of _isBlockchainSynced.value
HashEngineering Aug 12, 2026
71207e7
fix: close Imgur responses and bound the error body read
HashEngineering Aug 12, 2026
ce55219
fix: simplify Maya convert-crypto enter-amount screen per design feed…
HashEngineering Aug 14, 2026
fae563e
fix: make address middle-ellipsis truncation font-scale safe
HashEngineering Aug 14, 2026
f73f214
fix: match convert-crypto direction card to Figma layout
HashEngineering Aug 14, 2026
6be2f68
fix: add Galaxy S22 @ 1.25x font-scale preview
HashEngineering Aug 14, 2026
30e834b
fix: align convert-crypto currency picker with Figma design
HashEngineering Aug 14, 2026
16b6003
fix: middle-ellipsis the address rows on the Maya address-input screen
HashEngineering Aug 14, 2026
1128c43
fix: use device spec for the Galaxy S22 preview's system UI frame
HashEngineering Aug 14, 2026
38086cc
fix: match DEXReceiveScreen to Figma layout, add Galaxy S22 preview
HashEngineering Aug 14, 2026
9b61684
Merge branch 'master' into fix/dash-dex-ui-improvements-1
HashEngineering Aug 23, 2026
e5cd869
fix: address review findings in MenuItem.kt
HashEngineering Aug 23, 2026
3dc25d4
fix: test one-character candidates in middleEllipsizeToFit
HashEngineering Aug 23, 2026
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 @@ -184,11 +184,19 @@ fun EnterAmount(
// Wrap the picker to its content instead of letting its options' fillMaxWidth grab the
// whole row: width = widest option label, height = the stacked options' natural height
// (so it sits compact on the right rather than stretching across the amount area).
// Figma (node 38680:47341) shows these as plain stacked labels with no pill/background
// behind them, unlike the segmented-toggle style this component normally renders.
SegmentedPicker(
options = pickerIndices.map { SegmentedOption(currencyCodes[it]) },
showSelection = false,
style = SegmentedPickerStyle(
displayMode = PickerDisplayMode.Vertical,
backgroundColor = Color.Transparent,
cornerRadius = 0f,
shadowElevation = 0,
textStyle = MyTheme.Typography.LabelSmallMedium,
optionPaddingHorizontal = 6f,
optionPaddingVertical = 4f
),
onOptionSelected = { option, index ->
onCurrencyPickerSelect(option, pickerIndices[index])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.dash.wallet.common.ui.components

import android.content.res.Configuration
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
Expand All @@ -32,12 +33,15 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import android.content.res.Configuration
import androidx.compose.ui.text.TextMeasurer
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.rememberTextMeasurer
Comment thread
coderabbitai[bot] marked this conversation as resolved.
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
Expand All @@ -49,6 +53,10 @@ fun MenuItem(
helpTextAbove: String? = null,
subtitle: String? = null,
subtitleMaxLines: Int = Int.MAX_VALUE,
// Truncates `subtitle` from the middle to fit the available width (e.g. for addresses,
// where both the start and end need to stay checkable) instead of the standard end-ellipsis.
// Width-measured so it stays correct at any font scale, unlike a fixed character count.
subtitleMiddleEllipsis: Boolean = false,
subtitle2: String? = null,
icon: Int? = null,
// Custom icon slot (e.g. a Coil AsyncImage for coin logos); used when `icon` is null
Expand Down Expand Up @@ -168,14 +176,23 @@ fun MenuItem(

// Subtitle
subtitle?.let {
Text(
text = it,
style = MyTheme.Typography.BodyMedium,
color = colors.textSecondary,
maxLines = subtitleMaxLines,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth()
)
if (subtitleMiddleEllipsis) {
MiddleEllipsisText(
text = it,
style = MyTheme.Typography.BodyMedium,
color = colors.textSecondary,
modifier = Modifier.fillMaxWidth()
)
} else {
Text(
text = it,
style = MyTheme.Typography.BodyMedium,
color = colors.textSecondary,
maxLines = subtitleMaxLines,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth()
)
}
}

// Second subtitle
Expand Down Expand Up @@ -271,6 +288,44 @@ fun MenuItem(
}
}

/**
* Single-line text that keeps the start and end of [text] visible, truncating the middle
* with "…" only as much as needed to fit the measured width. Unlike a fixed character-count
* cut, this stays correct across screen widths, locales and font scales.
*/
@Composable
private fun MiddleEllipsisText(
text: String,
style: TextStyle,
color: Color,
modifier: Modifier = Modifier
) {
val measurer = rememberTextMeasurer()
val density = LocalDensity.current
BoxWithConstraints(modifier = modifier) {
val maxWidthPx = with(density) { maxWidth.toPx() }
val display = remember(text, maxWidthPx, style, density.fontScale) {
middleEllipsizeToFit(text, maxWidthPx, style, measurer)
}
Text(text = display, style = style, color = color, maxLines = 1, overflow = TextOverflow.Clip)
}
}

private fun middleEllipsizeToFit(text: String, maxWidthPx: Float, style: TextStyle, measurer: TextMeasurer): String {
fun widthOf(s: String) = measurer.measure(text = s, style = style, softWrap = false).size.width

if (maxWidthPx <= 0f || widthOf(text) <= maxWidthPx) return text

var head = (text.length + 1) / 2
var tail = text.length - head
while (head + tail > 0) {
val candidate = "${text.take(head)}…${text.takeLast(tail)}"
if (widthOf(candidate) <= maxWidthPx) return candidate
if (head >= tail) head-- else tail--
}
return "…"
}

@Preview(name = "MenuItem Light", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "MenuItem Dark", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import org.dash.wallet.common.R
Expand All @@ -67,7 +68,12 @@ data class SegmentedPickerStyle(
val thumbColor: Color? = null,
val cornerRadius: Float = 12f,
val textStyle: TextStyle = MyTheme.CaptionMedium,
val shadowElevation: Int = 2
val shadowElevation: Int = 2,
// Extra inset drawn around each option's text/icon, on top of the option's own weighted
// slot. Zero by default so existing fixed-height horizontal/vertical toggles are unaffected;
// set this for pickers whose options should have visible breathing room between them.
val optionPaddingHorizontal: Float = 0f,
val optionPaddingVertical: Float = 0f
)

@Composable
Expand Down Expand Up @@ -205,7 +211,9 @@ fun SegmentedPicker(
internalSelectedIndex = index
onOptionSelected(option, index)
},
modifier = Modifier.weight(1f)
modifier = Modifier.weight(1f),
paddingHorizontal = style.optionPaddingHorizontal.dp,
paddingVertical = style.optionPaddingVertical.dp
)
}
}
Expand All @@ -225,7 +233,9 @@ fun SegmentedPicker(
onOptionSelected(option, index)
},
modifier = Modifier.weight(1f),
isHorizontal = false
isHorizontal = false,
paddingHorizontal = style.optionPaddingHorizontal.dp,
paddingVertical = style.optionPaddingVertical.dp
)
}
}
Expand All @@ -240,7 +250,9 @@ private fun OptionContent(
textStyle: TextStyle,
onSelect: () -> Unit,
modifier: Modifier = Modifier,
isHorizontal: Boolean = true
isHorizontal: Boolean = true,
paddingHorizontal: Dp = 0.dp,
paddingVertical: Dp = 0.dp
) {
Box(
modifier = modifier
Expand All @@ -254,9 +266,9 @@ private fun OptionContent(
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = Modifier.then(
if (isHorizontal) Modifier.fillMaxHeight() else Modifier.fillMaxWidth()
)
modifier = Modifier
.then(if (isHorizontal) Modifier.fillMaxHeight() else Modifier.fillMaxWidth())
.padding(horizontal = paddingHorizontal, vertical = paddingVertical)
) {
val colors = LocalDashColors.current
option.icon?.let {
Expand Down
Loading
Loading