v1.0.5: Fix history viewer - ContentConverter JsonElement type bug
- ContentConverter.tipTapToHtml() had same JsonObject.asMap() bug as tiptapToMarkdown - All as? String casts silently returned null, producing empty HTML - Now uses Gson TypeToken<Map<String, Any?>> for proper deserialization - Added contentToHtml() that handles String (HTML), Map (TipTap), and JSON string - Fixed heading level cast (Gson deserializes numbers as Double, not Int) - VersionViewerActivity handles all content types correctly
This commit is contained in:
@@ -20,8 +20,8 @@ android {
|
|||||||
applicationId = "com.docmost.app"
|
applicationId = "com.docmost.app"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 5
|
versionCode = 6
|
||||||
versionName = "1.0.4"
|
versionName = "1.0.5"
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
|
|||||||
@@ -109,13 +109,26 @@ class VersionViewerActivity : AppCompatActivity() {
|
|||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
try {
|
try {
|
||||||
val history = api.getPageHistoryInfo(pageId, historyId)
|
val history = api.getPageHistoryInfo(pageId, historyId)
|
||||||
val htmlContent = if (history.content != null) {
|
val htmlContent: String
|
||||||
val gson = Gson()
|
if (history.content != null) {
|
||||||
val json = gson.toJson(history.content)
|
val content = history.content
|
||||||
originalTipTapJson = json
|
if (content is String && content.trimStart().startsWith("<")) {
|
||||||
ContentConverter.tipTapToHtml(json)
|
htmlContent = content
|
||||||
|
originalTipTapJson = ""
|
||||||
|
} else if (content is Map<*, *>) {
|
||||||
|
val gson = Gson()
|
||||||
|
originalTipTapJson = gson.toJson(content)
|
||||||
|
htmlContent = ContentConverter.contentToHtml(content)
|
||||||
|
} else if (content is String) {
|
||||||
|
originalTipTapJson = content
|
||||||
|
htmlContent = ContentConverter.tipTapToHtml(content)
|
||||||
|
} else {
|
||||||
|
htmlContent = "<p>Sin contenido</p>"
|
||||||
|
originalTipTapJson = ""
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
"<p>Sin contenido</p>"
|
htmlContent = "<p>Sin contenido</p>"
|
||||||
|
originalTipTapJson = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package com.docmost.app.utils
|
package com.docmost.app.utils
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
object ContentConverter {
|
object ContentConverter {
|
||||||
private val gson = Gson()
|
private val gson = Gson()
|
||||||
|
|
||||||
fun tipTapJsonToHtml(tipTapJson: String): String {
|
fun tipTapJsonToHtml(tipTapJson: String): String {
|
||||||
return try {
|
return try {
|
||||||
val doc = gson.fromJson(tipTapJson, JsonObject::class.java).asMap()
|
val type = object : TypeToken<Map<String, Any?>>() {}.type
|
||||||
@Suppress("UNCHECKED_CAST")
|
val doc: Map<String, Any?> = gson.fromJson(tipTapJson, type)
|
||||||
nodeToHtml(doc as Map<String, Any?>)
|
nodeToHtml(doc)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
tipTapJson
|
tipTapJson
|
||||||
}
|
}
|
||||||
@@ -18,14 +18,34 @@ object ContentConverter {
|
|||||||
|
|
||||||
fun tipTapToHtml(tipTapJson: String): String {
|
fun tipTapToHtml(tipTapJson: String): String {
|
||||||
return try {
|
return try {
|
||||||
val doc = gson.fromJson(tipTapJson, JsonObject::class.java).asMap()
|
val type = object : TypeToken<Map<String, Any?>>() {}.type
|
||||||
@Suppress("UNCHECKED_CAST")
|
val doc: Map<String, Any?> = gson.fromJson(tipTapJson, type)
|
||||||
nodeToHtml(doc as Map<String, Any?>)
|
nodeToHtml(doc)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
tipTapJson
|
tipTapJson
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun contentToHtml(content: Any?): String {
|
||||||
|
if (content == null) return "<p>Sin contenido</p>"
|
||||||
|
if (content is String) {
|
||||||
|
return if (content.trimStart().startsWith("<")) {
|
||||||
|
content
|
||||||
|
} else {
|
||||||
|
tipTapToHtml(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (content is Map<*, *>) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return try {
|
||||||
|
nodeToHtml(content as Map<String, Any?>)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"<p>Error converting content</p>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "<p>Sin contenido</p>"
|
||||||
|
}
|
||||||
|
|
||||||
private fun nodeToHtml(node: Map<String, Any?>): String {
|
private fun nodeToHtml(node: Map<String, Any?>): String {
|
||||||
val type = node["type"] as? String
|
val type = node["type"] as? String
|
||||||
|
|
||||||
@@ -74,7 +94,13 @@ object ContentConverter {
|
|||||||
sb.append("</p>")
|
sb.append("</p>")
|
||||||
}
|
}
|
||||||
"heading" -> {
|
"heading" -> {
|
||||||
val level = (node["attrs"] as? Map<*, *>)?.get("level") as? Int ?: 1
|
val levelRaw = (node["attrs"] as? Map<*, *>)?.get("level")
|
||||||
|
val level = when (levelRaw) {
|
||||||
|
is Int -> levelRaw
|
||||||
|
is Double -> levelRaw.toInt()
|
||||||
|
is Number -> levelRaw.toInt()
|
||||||
|
else -> 1
|
||||||
|
}
|
||||||
sb.append("<h$level>")
|
sb.append("<h$level>")
|
||||||
content?.forEach { child ->
|
content?.forEach { child ->
|
||||||
if (child is Map<*, *>) {
|
if (child is Map<*, *>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user