From 922d31b7dfda8d298e47dd73ee282fcd589db46a Mon Sep 17 00:00:00 2001 From: Nino Date: Mon, 27 Jul 2026 17:39:48 -0600 Subject: [PATCH] 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> 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 --- app/build.gradle.kts | 4 +- .../docmost/app/ui/VersionViewerActivity.kt | 25 ++++++++--- .../com/docmost/app/utils/ContentConverter.kt | 42 +++++++++++++++---- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 00cb46a..fb334d8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "com.docmost.app" minSdk = 26 targetSdk = 34 - versionCode = 5 - versionName = "1.0.4" + versionCode = 6 + versionName = "1.0.5" } signingConfigs { diff --git a/app/src/main/java/com/docmost/app/ui/VersionViewerActivity.kt b/app/src/main/java/com/docmost/app/ui/VersionViewerActivity.kt index e1234ce..3c77573 100644 --- a/app/src/main/java/com/docmost/app/ui/VersionViewerActivity.kt +++ b/app/src/main/java/com/docmost/app/ui/VersionViewerActivity.kt @@ -109,13 +109,26 @@ class VersionViewerActivity : AppCompatActivity() { CoroutineScope(Dispatchers.IO).launch { try { val history = api.getPageHistoryInfo(pageId, historyId) - val htmlContent = if (history.content != null) { - val gson = Gson() - val json = gson.toJson(history.content) - originalTipTapJson = json - ContentConverter.tipTapToHtml(json) + val htmlContent: String + if (history.content != null) { + val content = history.content + if (content is String && content.trimStart().startsWith("<")) { + 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 = "

Sin contenido

" + originalTipTapJson = "" + } } else { - "

Sin contenido

" + htmlContent = "

Sin contenido

" + originalTipTapJson = "" } withContext(Dispatchers.Main) { diff --git a/app/src/main/java/com/docmost/app/utils/ContentConverter.kt b/app/src/main/java/com/docmost/app/utils/ContentConverter.kt index 01abd69..dbe39ec 100644 --- a/app/src/main/java/com/docmost/app/utils/ContentConverter.kt +++ b/app/src/main/java/com/docmost/app/utils/ContentConverter.kt @@ -1,16 +1,16 @@ package com.docmost.app.utils import com.google.gson.Gson -import com.google.gson.JsonObject +import com.google.gson.reflect.TypeToken object ContentConverter { private val gson = Gson() fun tipTapJsonToHtml(tipTapJson: String): String { return try { - val doc = gson.fromJson(tipTapJson, JsonObject::class.java).asMap() - @Suppress("UNCHECKED_CAST") - nodeToHtml(doc as Map) + val type = object : TypeToken>() {}.type + val doc: Map = gson.fromJson(tipTapJson, type) + nodeToHtml(doc) } catch (e: Exception) { tipTapJson } @@ -18,14 +18,34 @@ object ContentConverter { fun tipTapToHtml(tipTapJson: String): String { return try { - val doc = gson.fromJson(tipTapJson, JsonObject::class.java).asMap() - @Suppress("UNCHECKED_CAST") - nodeToHtml(doc as Map) + val type = object : TypeToken>() {}.type + val doc: Map = gson.fromJson(tipTapJson, type) + nodeToHtml(doc) } catch (e: Exception) { tipTapJson } } + fun contentToHtml(content: Any?): String { + if (content == null) return "

Sin contenido

" + 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) + } catch (e: Exception) { + "

Error converting content

" + } + } + return "

Sin contenido

" + } + private fun nodeToHtml(node: Map): String { val type = node["type"] as? String @@ -74,7 +94,13 @@ object ContentConverter { sb.append("

") } "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("") content?.forEach { child -> if (child is Map<*, *>) {