Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Vitor Pamplona
2026-07-28 19:50:55 -04:00
4 changed files with 15 additions and 4 deletions
@@ -766,6 +766,7 @@ private fun geohashBounds(geohash: String): BoundingBox? {
/** A rough physical size for a geohash cell at this precision, for the chip subtitle. */
private fun GeohashChannelLevel.areaSize(): String =
when (this) {
GeohashChannelLevel.CONTINENT -> "~5000 km"
GeohashChannelLevel.REGION -> "~1250 km"
GeohashChannelLevel.PROVINCE -> "~39 km"
GeohashChannelLevel.CITY -> "~5 km"
@@ -377,6 +377,7 @@ private fun TeleportCard(onClick: () -> Unit) {
internal fun GeohashChannelLevel.label(): String =
when (this) {
GeohashChannelLevel.CONTINENT -> "Continent"
GeohashChannelLevel.REGION -> "Region"
GeohashChannelLevel.PROVINCE -> "Province"
GeohashChannelLevel.CITY -> "City"
@@ -21,8 +21,13 @@
package com.vitorpamplona.quartz.experimental.bitchat.geohash
/**
* The named geohash precision levels Bitchat exposes as location channels, each a
* fixed geohash character length. Coarser (fewer chars) = larger area.
* The named geohash precision levels exposed as location channels, each a fixed
* geohash character length. Coarser (fewer chars) = larger area.
*
* [REGION]…[BUILDING] (28 chars) mirror the levels Bitchat exposes, so those cells
* interoperate with Bitchat peers. [CONTINENT] (1 char) is an Amethyst extension: a
* single character splits the globe into 32 ~5000 km cells, coarser than any Bitchat
* channel, for a whole-continent room.
*
* Because a geohash is a prefix code, the channel for any level is just the first
* [chars] characters of a finer cell — so one precise fix yields every level via
@@ -31,6 +36,7 @@ package com.vitorpamplona.quartz.experimental.bitchat.geohash
enum class GeohashChannelLevel(
val chars: Int,
) {
CONTINENT(1),
REGION(2),
PROVINCE(4),
CITY(5),
@@ -47,7 +53,7 @@ enum class GeohashChannelLevel(
companion object {
/** Coarsest → finest, the order a location-channel picker should list them. */
val ordered = listOf(REGION, PROVINCE, CITY, NEIGHBORHOOD, BLOCK, BUILDING)
val ordered = listOf(CONTINENT, REGION, PROVINCE, CITY, NEIGHBORHOOD, BLOCK, BUILDING)
/** The named level whose precision matches [chars], if any. */
fun forChars(chars: Int): GeohashChannelLevel? = entries.firstOrNull { it.chars == chars }
@@ -28,6 +28,7 @@ import kotlin.test.assertNull
class GeohashChannelLevelTest {
@Test
fun charCountsMatchBitchat() {
assertEquals(1, GeohashChannelLevel.CONTINENT.chars)
assertEquals(2, GeohashChannelLevel.REGION.chars)
assertEquals(4, GeohashChannelLevel.PROVINCE.chars)
assertEquals(5, GeohashChannelLevel.CITY.chars)
@@ -39,6 +40,7 @@ class GeohashChannelLevelTest {
@Test
fun cellForTruncatesToLevel() {
val fix = "u4pruydq" // 8 chars
assertEquals("u", GeohashChannelLevel.CONTINENT.cellFor(fix))
assertEquals("u4", GeohashChannelLevel.REGION.cellFor(fix))
assertEquals("u4pr", GeohashChannelLevel.PROVINCE.cellFor(fix))
assertEquals("u4pru", GeohashChannelLevel.CITY.cellFor(fix))
@@ -55,11 +57,12 @@ class GeohashChannelLevelTest {
@Test
fun orderedIsCoarseToFine() {
assertEquals(listOf(2, 4, 5, 6, 7, 8), GeohashChannelLevel.ordered.map { it.chars })
assertEquals(listOf(1, 2, 4, 5, 6, 7, 8), GeohashChannelLevel.ordered.map { it.chars })
}
@Test
fun forCharsResolvesNamedLevels() {
assertEquals(GeohashChannelLevel.CONTINENT, GeohashChannelLevel.forChars(1))
assertEquals(GeohashChannelLevel.CITY, GeohashChannelLevel.forChars(5))
assertNull(GeohashChannelLevel.forChars(3))
}