Skip to content

Commit

Permalink
Add cross-platform JSON serialization support
Browse files Browse the repository at this point in the history
  • Loading branch information
bubelov committed May 22, 2024
1 parent 55696e6 commit f92311a
Show file tree
Hide file tree
Showing 16 changed files with 152 additions and 139 deletions.
7 changes: 1 addition & 6 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ kotlin {
implementation(libs.androidx.navigation.fragment)
implementation(libs.androidx.navigation.ui)
implementation(libs.androidx.preference)
//implementation(libs.androidx.sqlite)
implementation(libs.androidx.work)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.room)
Expand All @@ -42,6 +41,7 @@ kotlin {
implementation(libs.coil.svg)
}
commonMain.dependencies {
implementation(libs.kotlinx.serialization)
implementation(libs.androidx.sqlite)
}
}
Expand Down Expand Up @@ -125,11 +125,6 @@ android {
buildFeatures {
viewBinding = true
}

dependencies {
testImplementation(libs.junit)
testImplementation(libs.json)
}
}

tasks.register("bundleData") {
Expand Down
2 changes: 1 addition & 1 deletion app/src/androidMain/kotlin/area/AreaFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class AreaFragment : Fragment() {
val elements =
state.items.filterIsInstance<AreaAdapter.Item.Element>().size

binding.toolbar.title = state.area.tags.name(res = resources)
binding.toolbar.title = state.area.tags.name()
binding.toolbar.subtitle = resources.getQuantityString(
R.plurals.d_places,
elements,
Expand Down
12 changes: 9 additions & 3 deletions app/src/androidMain/kotlin/area/AreaJson.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package area

import json.toJsonArray
import org.json.JSONObject
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import java.io.InputStream
import java.time.ZonedDateTime

data class AreaJson(
val id: Long,
val tags: JSONObject?,
val tags: JsonObject?,
val updatedAt: String,
val deletedAt: String?,
)
Expand All @@ -24,7 +26,11 @@ fun InputStream.toAreasJson(): List<AreaJson> {
return toJsonArray().map {
AreaJson(
id = it.getLong("id"),
tags = it.optJSONObject("tags") ?: JSONObject(),
tags = if (it.has("tags")) {
Json.parseToJsonElement(it.getString("tags")).jsonObject
} else {
null
},
updatedAt = it.getString("updated_at"),
deletedAt = it.optString("deleted_at").ifBlank { null },
)
Expand Down
20 changes: 13 additions & 7 deletions app/src/androidMain/kotlin/area/AreaModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonPrimitive
import map.boundingBox
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.btcmap.R
Expand Down Expand Up @@ -94,20 +96,24 @@ class AreaModel(
)

val contact = AreaAdapter.Item.Contact(
website = area.tags.optString("contact:website").toHttpUrlOrNull(),
twitter = area.tags.optString("contact:twitter").toHttpUrlOrNull(),
telegram = area.tags.optString("contact:telegram").toHttpUrlOrNull(),
discord = area.tags.optString("contact:discord").toHttpUrlOrNull(),
youtube = area.tags.optString("contact:youtube").toHttpUrlOrNull(),
website = area.tags["contact:website"]?.jsonPrimitive?.contentOrNull?.toHttpUrlOrNull(),
twitter = area.tags["contact:twitter"]?.jsonPrimitive?.contentOrNull?.toHttpUrlOrNull(),
telegram = area.tags["contact:telegram"]?.jsonPrimitive?.contentOrNull?.toHttpUrlOrNull(),
discord = area.tags["contact:discord"]?.jsonPrimitive?.contentOrNull?.toHttpUrlOrNull(),
youtube = area.tags["contact:youtube"]?.jsonPrimitive?.contentOrNull?.toHttpUrlOrNull(),
)

val issuesCount = elements.sumOf { it.issues }

val items = buildList {
add(map)

if (area.tags.has("description")) {
add(AreaAdapter.Item.Description(area.tags.getString("description")))
if (area.tags.containsKey("description")) {
add(
AreaAdapter.Item.Description(
area.tags["description"]?.jsonPrimitive?.content ?: ""
)
)
}

add(contact)
Expand Down
91 changes: 0 additions & 91 deletions app/src/androidMain/kotlin/area/AreaTags.kt

This file was deleted.

78 changes: 78 additions & 0 deletions app/src/androidMain/kotlin/area/AreaTagsExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package area

import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.double
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import org.locationtech.jts.geom.Coordinate
import org.locationtech.jts.geom.GeometryFactory
import org.locationtech.jts.geom.Polygon

fun AreaTags.polygons(): List<Polygon> {
val geoFactory = GeometryFactory()

val res = mutableListOf<Polygon>()

val geoJson = this["geo_json"]?.jsonObject!!

if (geoJson["type"]?.jsonPrimitive?.contentOrNull == "FeatureCollection") {
val features = geoJson["features"]?.jsonArray!!

features.forEach { feature ->
val geometry = feature.jsonObject["geometry"]?.jsonObject!!

if (geometry["type"]?.jsonPrimitive?.contentOrNull == "MultiPolygon") {
val coordinates = geometry["coordinates"]?.jsonArray!!

coordinates.map { polys -> polys.jsonArray.map { it.jsonArray } }.forEach { polys ->
res += geoFactory.createPolygon(polys.first().jsonArray.map { it.jsonArray }
.map {
Coordinate(
it[0].jsonPrimitive.double,
it[1].jsonPrimitive.double,
)
}.toTypedArray())
}
}

if (geometry["type"]?.jsonPrimitive?.contentOrNull == "Polygon") {
val coordinates =
geometry["coordinates"]?.jsonArray!![0].jsonArray.map { it.jsonArray }

res += geoFactory.createPolygon(coordinates.map {
Coordinate(
it[0].jsonPrimitive.double,
it[1].jsonPrimitive.double,
)
}.toTypedArray())
}
}
}

if (geoJson["type"]?.jsonPrimitive?.contentOrNull == "MultiPolygon") {
val coordinates = geoJson["coordinates"]?.jsonArray!!.map { it.jsonArray }

coordinates.forEach { polys ->
val firstPoly = polys.map { it.jsonArray }.first().map { it.jsonArray }

res += geoFactory.createPolygon(firstPoly.map {
Coordinate(
it[0].jsonPrimitive.double,
it[1].jsonPrimitive.double,
)
}.toTypedArray())
}
}

if (geoJson["type"]?.jsonPrimitive?.contentOrNull == "Polygon") {
val coordinates = geoJson["coordinates"]?.jsonArray!!.map { it.jsonArray }
.first()
.map { it.jsonArray }
.map { Coordinate(it[0].jsonPrimitive.double, it[1].jsonPrimitive.double) }

res += geoFactory.createPolygon(coordinates.toTypedArray())
}

return res
}
8 changes: 5 additions & 3 deletions app/src/androidMain/kotlin/area/AreasModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonPrimitive
import map.boundingBox
import org.btcmap.R
import org.osmdroid.util.GeoPoint
Expand All @@ -26,7 +28,7 @@ class AreasModel(
viewModelScope.launch {
val communities = areasRepo
.selectByType("community")
.filter { it.tags.optString("icon:square").isNotBlank() }
.filter { it.tags.containsKey("icon:square") }
.mapNotNull {
val polygons = runCatching {
it.tags.polygons()
Expand Down Expand Up @@ -57,8 +59,8 @@ class AreasModel(

AreasAdapter.Item(
id = it.first.id,
iconUrl = it.first.tags.optString("icon:square"),
name = it.first.tags.name(res = app.resources),
iconUrl = it.first.tags["icon:square"]?.jsonPrimitive?.contentOrNull ?: "",
name = it.first.tags.name(),
distance = distanceStringBuilder.toString(),
)
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/androidMain/kotlin/db/CursorExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.json.JSONObject
import java.time.LocalDate
import java.time.ZonedDateTime

fun SQLiteStatement.getJsonObject(columnIndex: Int): JSONObject {
fun SQLiteStatement.getJsonObjectOld(columnIndex: Int): JSONObject {
return JSONObject(getText(columnIndex))
}

Expand Down
20 changes: 10 additions & 10 deletions app/src/androidMain/kotlin/element/ElementQueries.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package element
import androidx.sqlite.use
import db.Database
import db.getJsonArray
import db.getJsonObject
import db.getJsonObjectOld
import db.getText
import db.getZonedDateTime
import db.getZonedDateTimeOrNull
Expand Down Expand Up @@ -72,8 +72,8 @@ class ElementQueries(private val db: Database) {
if (it.step()) {
Element(
id = it.getLong(0),
overpassData = it.getJsonObject(1),
tags = it.getJsonObject(2),
overpassData = it.getJsonObjectOld(1),
tags = it.getJsonObjectOld(2),
updatedAt = it.getText(3),
lat = it.getDouble(4),
lon = it.getDouble(5),
Expand Down Expand Up @@ -107,8 +107,8 @@ class ElementQueries(private val db: Database) {
add(
Element(
id = it.getLong(0),
overpassData = it.getJsonObject(1),
tags = it.getJsonObject(2),
overpassData = it.getJsonObjectOld(1),
tags = it.getJsonObjectOld(2),
updatedAt = it.getText(3),
lat = it.getDouble(4),
lon = it.getDouble(5),
Expand Down Expand Up @@ -142,8 +142,8 @@ class ElementQueries(private val db: Database) {
add(
Element(
id = it.getLong(0),
overpassData = it.getJsonObject(1),
tags = it.getJsonObject(2),
overpassData = it.getJsonObjectOld(1),
tags = it.getJsonObjectOld(2),
updatedAt = it.getText(3),
lat = it.getDouble(4),
lon = it.getDouble(5),
Expand Down Expand Up @@ -177,8 +177,8 @@ class ElementQueries(private val db: Database) {
add(
Element(
id = it.getLong(0),
overpassData = it.getJsonObject(1),
tags = it.getJsonObject(2),
overpassData = it.getJsonObjectOld(1),
tags = it.getJsonObjectOld(2),
updatedAt = it.getText(3),
lat = it.getDouble(4),
lon = it.getDouble(5),
Expand Down Expand Up @@ -318,7 +318,7 @@ class ElementQueries(private val db: Database) {
lat = it.getDouble(1),
lon = it.getDouble(2),
icon = it.getText(3),
osmTags = it.getJsonObject(4),
osmTags = it.getJsonObjectOld(4),
issues = it.getJsonArray(5),
osmType = it.getText(6),
osmId = it.getLong(7),
Expand Down
4 changes: 2 additions & 2 deletions app/src/androidMain/kotlin/event/EventQueries.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package event

import androidx.sqlite.use
import db.Database
import db.getJsonObject
import db.getJsonObjectOld
import db.getText
import db.getZonedDateTime
import java.time.ZonedDateTime
Expand Down Expand Up @@ -81,7 +81,7 @@ class EventQueries(private val db: Database) {
userId = it.getLong(1),
elementId = it.getLong(2),
type = it.getLong(3),
tags = it.getJsonObject(4),
tags = it.getJsonObjectOld(4),
createdAt = it.getZonedDateTime(5),
updatedAt = it.getZonedDateTime(6),
)
Expand Down
Loading

0 comments on commit f92311a

Please sign in to comment.