feat(geohash): add in-app Geohash Picker (#363)

* feat(geohash): add in-app Geohash Picker map with quadrant drill-down and Activity integration

- New GeohashPickerActivity hosting a WebView with Leaflet-based picker
- Adds map icon next to custom geohash input in LocationChannelsSheet
- Picker allows quadrant selection and subquadrant drill-down; returns selected geohash
- Register activity in AndroidManifest

perf(picker): improve map performance and correctness
- Use LayerGroup and clearLayers() on redraw to avoid stale overlays
- Use Leaflet canvas renderer for rectangles to reduce DOM and improve perf
- Make labels non-interactive and pointer-events: none to avoid gesture overhead
- Fix initial mega-label artifact by grouping and clearing labels with cells

chore: add asset geohash_picker.html with minimal geohash helpers (bounds/encode/adjacent)

* remove accidentally committed submodule.

* fix some issues

* better geohash labels on map

* design wip

* countries green

* wip

* geohashpicker: pan + zoom; start from current geohash channel

* better ui

* ui elements

* nice

* readability

---------

Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
This commit is contained in:
lollerfirst
2025-09-06 11:49:23 +02:00
committed by GitHub
co-authored by callebtc
parent cc45f477fb
commit a804782476
4 changed files with 549 additions and 0 deletions
@@ -10,6 +10,7 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Map
import androidx.compose.material.icons.filled.PinDrop
import androidx.compose.material3.*
import androidx.compose.ui.text.font.FontWeight
@@ -30,6 +31,8 @@ import com.bitchat.android.geohash.GeohashChannel
import com.bitchat.android.geohash.GeohashChannelLevel
import com.bitchat.android.geohash.LocationChannelManager
import java.util.*
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
/**
* Location Channels Sheet for selecting geohash-based location channels
@@ -71,6 +74,18 @@ fun LocationChannelsSheet(
// Scroll state for LazyColumn
val listState = rememberLazyListState()
val mapPickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == android.app.Activity.RESULT_OK) {
val gh = result.data?.getStringExtra(GeohashPickerActivity.EXTRA_RESULT_GEOHASH)
if (!gh.isNullOrBlank()) {
customGeohash = gh
customError = null
}
}
}
// iOS system colors (matches iOS exactly)
val colorScheme = MaterialTheme.colorScheme
val isDark = colorScheme.background.red + colorScheme.background.green + colorScheme.background.blue < 1.5f
@@ -312,6 +327,26 @@ fun LocationChannelsSheet(
)
val normalized = customGeohash.trim().lowercase().replace("#", "")
// Map picker button
IconButton(onClick = {
val initial = when {
normalized.isNotBlank() -> normalized
selectedChannel is ChannelID.Location -> (selectedChannel as ChannelID.Location).channel.geohash
else -> ""
}
val intent = Intent(context, GeohashPickerActivity::class.java).apply {
putExtra(GeohashPickerActivity.EXTRA_INITIAL_GEOHASH, initial)
}
mapPickerLauncher.launch(intent)
}) {
Icon(
imageVector = Icons.Filled.Map,
contentDescription = "Open map",
tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f)
)
}
val isValid = validateGeohash(normalized)
// iOS-style teleport button