mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-09-19 04:59:59 +00:00
fix: stop nickname truncation cutting a character in half
truncateNickname compared and cut with String.length and take, both of which count UTF-16 code units. A name whose 15th unit is the high surrogate of an emoji lost its low surrogate, leaving a lone U+D83D that renders as a tofu box wherever the name is shown - the peer list, the geohash people list, and every inline mention. Step back to the last grapheme boundary at or before the limit instead, so a truncated name is always whole. The limit itself is unchanged, so an ASCII name truncates exactly as before.
This commit is contained in:
parent
d55754d824
commit
7073f7dec0
@ -1,9 +1,19 @@
|
||||
package com.bitchat.android.ui
|
||||
|
||||
import java.text.BreakIterator
|
||||
|
||||
/**
|
||||
* UI constants/utilities for nickname rendering.
|
||||
*/
|
||||
fun truncateNickname(name: String, maxLen: Int = com.bitchat.android.util.AppConstants.UI.MAX_NICKNAME_LENGTH): String {
|
||||
return if (name.length <= maxLen) name else name.take(maxLen)
|
||||
}
|
||||
if (name.length <= maxLen) return name
|
||||
|
||||
// The limit counts UTF-16 code units, so cutting at it can land inside a
|
||||
// surrogate pair and leave a lone surrogate that renders as a tofu box, or
|
||||
// split a ZWJ sequence into its parts. Step back to the last grapheme
|
||||
// boundary at or before the limit so what is shown is always whole.
|
||||
val boundaries = BreakIterator.getCharacterInstance()
|
||||
boundaries.setText(name)
|
||||
val end = boundaries.preceding(maxLen + 1)
|
||||
return if (end == BreakIterator.DONE) "" else name.substring(0, end)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user