Location notes (#482)

* try 1

* works

* equalize UI with ios

* ui cleanup

* geohash chats: no building

* load notes in background

* insta

* simplify and tor icon change

* icons nice

* refactor

* unify location enabled / disabled

* cooler

* simplify, doesnt subscribe right away

* load when clicked

* plus minus location notes

* load when tor is available

* translations

* fix transalations

* implement review comments
This commit is contained in:
callebtc
2025-10-18 14:19:53 +02:00
committed by GitHub
parent e8862d5128
commit f99cb46b26
38 changed files with 1769 additions and 24 deletions
@@ -115,4 +115,36 @@ object Geohash {
lonMax = maxOf(lonInterval.first, lonInterval.second)
)
}
/**
* Returns the 8 neighboring geohash cells at the same precision as the input.
* Neighbors include N, NE, E, SE, S, SW, W, NW, even when crossing parent cell boundaries.
*/
fun neighborsSamePrecision(geohash: String): Set<String> {
if (geohash.isEmpty()) return emptySet()
val p = geohash.length
val b = decodeToBounds(geohash)
val dLat = b.latMax - b.latMin
val dLon = b.lonMax - b.lonMin
fun wrapLon(lon: Double): Double {
var x = lon
while (x > 180.0) x -= 360.0
while (x < -180.0) x += 360.0
return x
}
val neighbors = mutableSetOf<String>()
for (dy in -1..1) {
for (dx in -1..1) {
if (dx == 0 && dy == 0) continue // skip center
val centerLat = (b.latMin + b.latMax) / 2 + dy * dLat
val rawLonCenter = (b.lonMin + b.lonMax) / 2 + dx * dLon
val centerLon = wrapLon(rawLonCenter)
val enc = encode(centerLat.coerceIn(-90.0, 90.0), centerLon, p)
if (enc.isNotEmpty() && enc != geohash) neighbors.add(enc)
}
}
return neighbors
}
}
@@ -5,6 +5,7 @@ package com.bitchat.android.geohash
* Direct port from iOS implementation for 100% compatibility
*/
enum class GeohashChannelLevel(val precision: Int, val displayName: String) {
BUILDING(8, "Building"), // iOS: precision 8 for building-level (used for Location Notes)
BLOCK(7, "Block"),
NEIGHBORHOOD(6, "Neighborhood"),
CITY(5, "City"),
@@ -88,10 +88,17 @@ class LocationChannelManager private constructor(private val context: Context) {
/**
* Enable location channels (request permission if needed)
* UNIFIED: Only requests location if location services are enabled by user
*/
fun enableLocationChannels() {
Log.d(TAG, "enableLocationChannels() called")
// UNIFIED FIX: Check if location services are enabled by user
if (!isLocationServicesEnabled()) {
Log.w(TAG, "Location services disabled by user - not requesting location")
return
}
when (getCurrentPermissionStatus()) {
PermissionState.NOT_DETERMINED -> {
Log.d(TAG, "Permission not determined - user needs to grant in app settings")