diff --git a/app/src/main/java/com/bitchat/android/ui/ChatUIConstants.kt b/app/src/main/java/com/bitchat/android/ui/ChatUIConstants.kt index f00d650e..1a15a497 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatUIConstants.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatUIConstants.kt @@ -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) +}