v1.0.7: Fix false offline modifications causing 'untitled' pages

Root cause chain:
1. JS _pendingSet cleared prematurely in onReady (0ms), letting onChange
   fire during initial content load and set userEdited=true
2. onAutoSave didn't check isEditorReadOnly, firing even for read-only pages
3. Markdown round-trip (extractText → markdownToBlocks → blocksToMarkdown)
   produced different output, triggering false change detection
4. onSaveContent passed null for title when no title changes, which
   CachedApi converted to empty string, causing server to set title to 'untitled'

Fixes:
- JS: Remove premature _pendingSet clearing in onReady; increase timeout to 500ms
- Kotlin: onAutoSave checks isEditorReadOnly (no auto-save in read-only mode)
- Kotlin: Save operations always pass current title (never null) to prevent
  empty title being sent to server
- Kotlin: Add isContentLoading flag to suppress onContentChanged during initial
  content load, preventing false currentPageContent updates
- Added APK versioned naming for Obtanium compatibility
This commit is contained in:
2026-07-27 20:56:59 -06:00
parent 57f8858708
commit f265498ed3
3 changed files with 24 additions and 14 deletions

View File

@@ -531,12 +531,9 @@
} else {
console.log('AndroidInterface not available yet');
}
// Android controla la carga de contenido via setContent()
// No cargar pendingAndroidContent automáticamente
// Clear pending set flag on next tick after initialization
setTimeout(function() {
window._pendingSet = false;
}, 0);
// _pendingSet is cleared by setContent() after 100ms
// Do NOT clear it here — doing so prematurely lets onChange
// fire during initial content load and sets userEdited=true
// Configurar observer para detectar cambios en bloques vacíos
setTimeout(function() {
setupBackspaceHandler();
@@ -617,7 +614,7 @@
window.setContentLock = false;
setTimeout(function() {
window._pendingSet = false;
}, 100);
}, 500);
};
window.getContent = function() {

View File

@@ -283,6 +283,7 @@ class PageEditorActivity : AppCompatActivity() {
}
private var isEditorRendered = false
private var isContentLoading = false
private var pendingContent: String? = null
private var isTitleVisible = true
private var isAnimating = false
@@ -627,6 +628,7 @@ class PageEditorActivity : AppCompatActivity() {
@JavascriptInterface
fun onContentChanged(markdown: String) {
if (isContentLoading) return
currentPageContent = markdown
}
@@ -640,12 +642,15 @@ class PageEditorActivity : AppCompatActivity() {
loadEditorContentInternal(content)
pendingContent = null
}
Handler(Looper.getMainLooper()).postDelayed({
isContentLoading = false
}, 600)
}
}
@JavascriptInterface
fun onAutoSave(markdown: String) {
if (!canEdit) return
if (!canEdit || isEditorReadOnly) return
runOnUiThread {
val title = binding.etTitle.text.toString().trim()
@@ -698,14 +703,14 @@ class PageEditorActivity : AppCompatActivity() {
try {
cachedApi.updatePage(
currentPageId, markdown,
if (hasTitleChanges) title else null,
title,
if (hasEmojiChanges) currentEmoji else null
)
val cachedPage = pageCacheManager.getCachedPage(currentPageId)
if (cachedPage != null) {
pageCacheManager.cachePage(cachedPage.copy(
title = if (hasTitleChanges) title else cachedPage.title,
title = title,
icon = if (hasEmojiChanges) currentEmoji else cachedPage.icon,
content = markdown
))
@@ -740,7 +745,7 @@ class PageEditorActivity : AppCompatActivity() {
try {
cachedApi.updatePage(
currentPageId, null,
if (hasTitleChanges) title else null,
title,
if (hasEmojiChanges) currentEmoji else null
)
} catch (e: Exception) {
@@ -768,7 +773,7 @@ class PageEditorActivity : AppCompatActivity() {
cachedApi.updatePage(
pageId!!,
if (hasBodyChanges) markdown else null,
if (hasTitleChanges) title else null,
title,
if (pageEmoji != originalEmoji) pageEmoji else null
)
withContext(Dispatchers.Main) {
@@ -1004,6 +1009,7 @@ class PageEditorActivity : AppCompatActivity() {
private fun loadEditorContent(markdown: String) {
if (BuildConfig.DEBUG) android.util.Log.d("PageEditor", "loadEditorContent called with ${markdown.length} chars")
isContentLoading = true
if (isEditorRendered) {
loadEditorContentInternal(markdown)
} else {