Skip to content

Commit

Permalink
Show community meetup locations
Browse files Browse the repository at this point in the history
  • Loading branch information
bubelov committed Feb 17, 2024
1 parent 7156336 commit 0553688
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 40 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

- Show community meetup locations
- Add area issues screen
- Change default location to Curacao
- Zoom to current location
Expand Down
28 changes: 28 additions & 0 deletions app/src/main/kotlin/area/AreaQueries.kt
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,32 @@ class AreaQueries(private val db: SQLiteOpenHelper) {
}

}

suspend fun selectMeetups(): List<Meetup> {
return withContext(Dispatchers.IO) {
val cursor = db.readableDatabase.query(
"""
SELECT
json_extract(tags, '$.meetup_lat') AS lat,
json_extract(tags, '$.meetup_lon') AS lon,
id
FROM area
WHERE
lat IS NOT NULL AND lon IS NOT NULL
"""
)

val rows = mutableListOf<Meetup>()

while (cursor.moveToNext()) {
rows += Meetup(
lat = cursor.getDouble(0),
lon = cursor.getDouble(1),
areaId = cursor.getString(2),
)
}

rows
}
}
}
2 changes: 2 additions & 0 deletions app/src/main/kotlin/area/AreasRepo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class AreasRepo(

suspend fun selectByType(type: String) = queries.selectByType(type)

suspend fun selectMeetups() = queries.selectMeetups()

suspend fun sync(): Result<SyncReport> {
return runCatching {
val startMillis = System.currentTimeMillis()
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/kotlin/area/Meetup.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package area

data class Meetup(
val lat: Double,
val lon: Double,
val areaId: String,
)
74 changes: 47 additions & 27 deletions app/src/main/kotlin/map/MapFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -265,36 +265,56 @@ class MapFragment : Fragment() {
visibleElements.clear()

newElements.forEach {
val marker = Marker(binding.map)
marker.position = GeoPoint(it.lat, it.lon)

if (it.count == 1L) {
val icon = if (
it.boostExpires != null
&& it.boostExpires.isAfter(ZonedDateTime.now(ZoneOffset.UTC))
) {
markersRepo.getBoostedMarker(it.iconId.ifBlank { "question_mark" })
} else {
markersRepo.getMarker(it.iconId.ifBlank { "question_mark" })
when (it) {
is MapModel.MapItem.ElementsCluster -> {
val marker = Marker(binding.map)
marker.position = GeoPoint(it.cluster.lat, it.cluster.lon)

if (it.cluster.count == 1L) {
val icon = if (
it.cluster.boostExpires != null
&& it.cluster.boostExpires.isAfter(ZonedDateTime.now(ZoneOffset.UTC))
) {
markersRepo.getBoostedMarker(it.cluster.iconId.ifBlank { "question_mark" })
} else {
markersRepo.getMarker(it.cluster.iconId.ifBlank { "question_mark" })
}

marker.icon = icon
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
} else {
marker.icon = createClusterIcon(it.cluster).toDrawable(resources)
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
}

marker.setOnMarkerClickListener { _, _ ->
if (it.cluster.count == 1L) {
model.selectElement(it.cluster.id, false)
}

true
}

visibleElements += marker
binding.map.overlays += marker
}

marker.icon = icon
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
} else {
marker.icon = createClusterIcon(it).toDrawable(resources)
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
}

marker.setOnMarkerClickListener { _, _ ->
if (it.count == 1L) {
model.selectElement(it.id, false)
is MapModel.MapItem.Meetup -> {
val marker = Marker(binding.map)
marker.position = GeoPoint(it.meetup.lat, it.meetup.lon)
marker.icon = markersRepo.meetupMarker
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
marker.setOnMarkerClickListener { _, _ ->
findNavController().navigate(
resId = R.id.areaFragment,
args = bundleOf("area_id" to it.meetup.areaId),
)

true
}
visibleElements += marker
binding.map.overlays += marker
}

true
}

visibleElements += marker
binding.map.overlays += marker
}

binding.map.invalidate()
Expand Down
39 changes: 30 additions & 9 deletions app/src/main/kotlin/map/MapMarkersRepo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class MapMarkersRepo(
}
}

private val boostedIconPaint by lazy {
private val whiteIconPaint by lazy {
Paint().apply {
val pinSizePx = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
Expand All @@ -51,12 +51,19 @@ class MapMarkersRepo(

private val boostedCache = mutableMapOf<String?, BitmapDrawable>()

val meetupMarker by lazy {
createMarkerIcon("groups", BackgroundType.MEETUP).toDrawable(context.resources)
}

fun getMarker(iconId: String): BitmapDrawable {
var markerDrawable = cache[iconId]

if (markerDrawable == null) {
markerDrawable =
createMarkerIcon(iconId, false).toDrawable(context.resources)
createMarkerIcon(
iconId,
BackgroundType.PRIMARY_CONTAINER
).toDrawable(context.resources)
cache[iconId] = markerDrawable
}

Expand All @@ -68,27 +75,35 @@ class MapMarkersRepo(

if (markerDrawable == null) {
markerDrawable =
createMarkerIcon(iconId, true).toDrawable(context.resources)
createMarkerIcon(iconId, BackgroundType.BOOSTED).toDrawable(context.resources)
boostedCache[iconId] = markerDrawable
}

return markerDrawable
}

private fun createMarkerIcon(iconId: String, boosted: Boolean): Bitmap {
private fun createMarkerIcon(iconId: String, backgroundType: BackgroundType): Bitmap {
val pinSizePx = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 48f, context.resources.displayMetrics
).toInt()

val emptyPinDrawable = ContextCompat.getDrawable(context, R.drawable.marker)!!

if (boosted) {
DrawableCompat.setTint(emptyPinDrawable, Color.parseColor("#f7931a"))
} else {
DrawableCompat.setTint(
when (backgroundType) {
BackgroundType.PRIMARY_CONTAINER -> DrawableCompat.setTint(
emptyPinDrawable,
context.getPrimaryContainerColor()
)

BackgroundType.BOOSTED -> DrawableCompat.setTint(
emptyPinDrawable,
Color.parseColor("#f7931a")
)

BackgroundType.MEETUP -> DrawableCompat.setTint(
emptyPinDrawable,
Color.parseColor("#0e95af")
)
}

val emptyPinBitmap = emptyPinDrawable.toBitmap(width = pinSizePx, height = pinSizePx)
Expand All @@ -112,7 +127,7 @@ class MapMarkersRepo(
iconId,
markerIcon.width / 2f - textWidth / 2f,
markerIcon.height / 2f - (iconPaint.fontMetrics.ascent + iconPaint.fontMetrics.descent) / 2 - markerIcon.height.toFloat() * 0.09f,
if (boosted) boostedIconPaint else iconPaint
if (backgroundType == BackgroundType.BOOSTED || backgroundType == BackgroundType.MEETUP) whiteIconPaint else iconPaint
)
}
}
Expand All @@ -123,4 +138,10 @@ class MapMarkersRepo(
companion object {
private const val PIN_SIZE_DP = 48f
}

enum class BackgroundType {
PRIMARY_CONTAINER,
BOOSTED,
MEETUP,
}
}
15 changes: 11 additions & 4 deletions app/src/main/kotlin/map/MapModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package map

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import area.AreasRepo
import conf.ConfRepo
import element.Element
import element.ElementsCluster
import element.ElementsRepo
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
Expand All @@ -18,6 +18,7 @@ class MapModel(
private val locationRepo: UserLocationRepository,
private val sync: Sync,
private val elementsRepo: ElementsRepo,
private val areasRepo: AreasRepo,
) : ViewModel() {

val userLocation: StateFlow<GeoPoint?> = locationRepo.location
Expand Down Expand Up @@ -46,8 +47,8 @@ class MapModel(
private val _selectedElement: MutableStateFlow<Element?> = MutableStateFlow(null)
val selectedElement = _selectedElement.asStateFlow()

private val _visibleElements = MutableStateFlow<List<ElementsCluster>>(emptyList())
val visibleElements = _visibleElements.asStateFlow()
private val _items = MutableStateFlow<List<MapItem>>(emptyList())
val visibleElements = _items.asStateFlow()

val syncActive = sync.active

Expand All @@ -63,7 +64,8 @@ class MapModel(
box = viewport.boundingBox,
excludedCategories = excludedCategories.map { it },
)
_visibleElements.update { clusters }
val meetups = areasRepo.selectMeetups().map { MapItem.Meetup(it) }
_items.update { clusters.map { MapItem.ElementsCluster(it) } + meetups }
}
}.launchIn(viewModelScope)

Expand Down Expand Up @@ -121,4 +123,9 @@ class MapModel(
val point2 = destinationPoint(distance, -135.0)
return BoundingBox.fromGeoPoints(listOf(point1, point2))
}

sealed class MapItem {
data class ElementsCluster(val cluster: element.ElementsCluster) : MapItem()
data class Meetup(val meetup: area.Meetup) : MapItem()
}
}

0 comments on commit 0553688

Please sign in to comment.