mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 03:45:21 +00:00
UI geohash notifications (#325)
* location name in notifications * remove tests * panic nostr * mentions with hashes, otherwise none * fix timestamps * parse geohashes in messages * works * fix country name * mention notifications work
This commit is contained in:
@@ -5,6 +5,7 @@ import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.bitchat.android.model.BitchatMessage
|
||||
import com.bitchat.android.mesh.BluetoothMeshService
|
||||
@@ -80,11 +81,11 @@ fun formatMessageAsAnnotatedString(
|
||||
builder.append(baseName)
|
||||
val nicknameEnd = builder.length
|
||||
|
||||
// Add click annotation for nickname (store full sender name with hash)
|
||||
// Add click annotation for nickname (store canonical sender name with hash if available)
|
||||
if (!isSelf) {
|
||||
builder.addStringAnnotation(
|
||||
tag = "nickname_click",
|
||||
annotation = message.sender, // Store full sender name with hash
|
||||
annotation = (message.originalSender ?: message.sender),
|
||||
start = nicknameStart,
|
||||
end = nicknameEnd
|
||||
)
|
||||
@@ -257,6 +258,31 @@ private fun appendIOSFormattedContent(
|
||||
for (match in mentionMatches) {
|
||||
allMatches.add(match.range to "mention")
|
||||
}
|
||||
|
||||
// Add standalone geohash matches (e.g., "#9q") that are not part of another word
|
||||
// We use MessageSpecialParser to find exact ranges; then merge with existing ranges avoiding overlaps
|
||||
val geoMatches = MessageSpecialParser.findStandaloneGeohashes(content)
|
||||
for (gm in geoMatches) {
|
||||
val range = gm.start until gm.endExclusive
|
||||
if (!overlapsMention(range)) {
|
||||
allMatches.add(range to "geohash")
|
||||
}
|
||||
}
|
||||
|
||||
// Remove generic hashtag matches that overlap with detected geohash ranges to avoid duplicate rendering
|
||||
fun rangesOverlap(a: IntRange, b: IntRange): Boolean {
|
||||
return a.first < b.last && a.last > b.first
|
||||
}
|
||||
val geoRanges = allMatches.filter { it.second == "geohash" }.map { it.first }
|
||||
if (geoRanges.isNotEmpty()) {
|
||||
val iterator = allMatches.listIterator()
|
||||
while (iterator.hasNext()) {
|
||||
val (range, type) = iterator.next()
|
||||
if (type == "hashtag" && geoRanges.any { rangesOverlap(range, it) }) {
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allMatches.sortBy { it.first.first }
|
||||
|
||||
@@ -327,7 +353,7 @@ private fun appendIOSFormattedContent(
|
||||
}
|
||||
}
|
||||
"hashtag" -> {
|
||||
// iOS-style: render hashtags like normal content (no special styling)
|
||||
// Render general hashtags like normal content
|
||||
builder.pushStyle(SpanStyle(
|
||||
color = baseColor,
|
||||
fontSize = BASE_FONT_SIZE.sp,
|
||||
@@ -342,6 +368,37 @@ private fun appendIOSFormattedContent(
|
||||
}
|
||||
builder.pop()
|
||||
}
|
||||
else -> {
|
||||
if (type == "geohash") {
|
||||
// Style geohash in blue, underlined, and add click annotation
|
||||
builder.pushStyle(SpanStyle(
|
||||
color = Color(0xFF007AFF),
|
||||
fontSize = BASE_FONT_SIZE.sp,
|
||||
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.SemiBold,
|
||||
textDecoration = TextDecoration.Underline
|
||||
))
|
||||
val start = builder.length
|
||||
builder.append(matchText)
|
||||
val end = builder.length
|
||||
val geohash = matchText.removePrefix("#").lowercase()
|
||||
builder.addStringAnnotation(
|
||||
tag = "geohash_click",
|
||||
annotation = geohash,
|
||||
start = start,
|
||||
end = end
|
||||
)
|
||||
builder.pop()
|
||||
} else {
|
||||
// Fallback: treat as normal text
|
||||
builder.pushStyle(SpanStyle(
|
||||
color = baseColor,
|
||||
fontSize = BASE_FONT_SIZE.sp,
|
||||
fontWeight = if (isSelf) FontWeight.Bold else FontWeight.Normal
|
||||
))
|
||||
builder.append(matchText)
|
||||
builder.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastEnd = range.last + 1
|
||||
|
||||
Reference in New Issue
Block a user