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:
@@ -20,8 +20,8 @@ android {
|
|||||||
applicationId = "com.docmost.app"
|
applicationId = "com.docmost.app"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 7
|
versionCode = 8
|
||||||
versionName = "1.0.6"
|
versionName = "1.0.7"
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@@ -58,6 +58,13 @@ android {
|
|||||||
viewBinding = true
|
viewBinding = true
|
||||||
buildConfig = true
|
buildConfig = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applicationVariants.all {
|
||||||
|
outputs.all {
|
||||||
|
val output = this as com.android.build.gradle.internal.api.BaseVariantOutputImpl
|
||||||
|
output.outputFileName = "Docmost-app-v${versionName}-${buildType.name}.apk"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|||||||
@@ -531,12 +531,9 @@
|
|||||||
} else {
|
} else {
|
||||||
console.log('AndroidInterface not available yet');
|
console.log('AndroidInterface not available yet');
|
||||||
}
|
}
|
||||||
// Android controla la carga de contenido via setContent()
|
// _pendingSet is cleared by setContent() after 100ms
|
||||||
// No cargar pendingAndroidContent automáticamente
|
// Do NOT clear it here — doing so prematurely lets onChange
|
||||||
// Clear pending set flag on next tick after initialization
|
// fire during initial content load and sets userEdited=true
|
||||||
setTimeout(function() {
|
|
||||||
window._pendingSet = false;
|
|
||||||
}, 0);
|
|
||||||
// Configurar observer para detectar cambios en bloques vacíos
|
// Configurar observer para detectar cambios en bloques vacíos
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
setupBackspaceHandler();
|
setupBackspaceHandler();
|
||||||
@@ -617,7 +614,7 @@
|
|||||||
window.setContentLock = false;
|
window.setContentLock = false;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
window._pendingSet = false;
|
window._pendingSet = false;
|
||||||
}, 100);
|
}, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.getContent = function() {
|
window.getContent = function() {
|
||||||
|
|||||||
@@ -283,6 +283,7 @@ class PageEditorActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var isEditorRendered = false
|
private var isEditorRendered = false
|
||||||
|
private var isContentLoading = false
|
||||||
private var pendingContent: String? = null
|
private var pendingContent: String? = null
|
||||||
private var isTitleVisible = true
|
private var isTitleVisible = true
|
||||||
private var isAnimating = false
|
private var isAnimating = false
|
||||||
@@ -627,6 +628,7 @@ class PageEditorActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
fun onContentChanged(markdown: String) {
|
fun onContentChanged(markdown: String) {
|
||||||
|
if (isContentLoading) return
|
||||||
currentPageContent = markdown
|
currentPageContent = markdown
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,12 +642,15 @@ class PageEditorActivity : AppCompatActivity() {
|
|||||||
loadEditorContentInternal(content)
|
loadEditorContentInternal(content)
|
||||||
pendingContent = null
|
pendingContent = null
|
||||||
}
|
}
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
isContentLoading = false
|
||||||
|
}, 600)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
fun onAutoSave(markdown: String) {
|
fun onAutoSave(markdown: String) {
|
||||||
if (!canEdit) return
|
if (!canEdit || isEditorReadOnly) return
|
||||||
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
val title = binding.etTitle.text.toString().trim()
|
val title = binding.etTitle.text.toString().trim()
|
||||||
@@ -698,14 +703,14 @@ class PageEditorActivity : AppCompatActivity() {
|
|||||||
try {
|
try {
|
||||||
cachedApi.updatePage(
|
cachedApi.updatePage(
|
||||||
currentPageId, markdown,
|
currentPageId, markdown,
|
||||||
if (hasTitleChanges) title else null,
|
title,
|
||||||
if (hasEmojiChanges) currentEmoji else null
|
if (hasEmojiChanges) currentEmoji else null
|
||||||
)
|
)
|
||||||
|
|
||||||
val cachedPage = pageCacheManager.getCachedPage(currentPageId)
|
val cachedPage = pageCacheManager.getCachedPage(currentPageId)
|
||||||
if (cachedPage != null) {
|
if (cachedPage != null) {
|
||||||
pageCacheManager.cachePage(cachedPage.copy(
|
pageCacheManager.cachePage(cachedPage.copy(
|
||||||
title = if (hasTitleChanges) title else cachedPage.title,
|
title = title,
|
||||||
icon = if (hasEmojiChanges) currentEmoji else cachedPage.icon,
|
icon = if (hasEmojiChanges) currentEmoji else cachedPage.icon,
|
||||||
content = markdown
|
content = markdown
|
||||||
))
|
))
|
||||||
@@ -740,7 +745,7 @@ class PageEditorActivity : AppCompatActivity() {
|
|||||||
try {
|
try {
|
||||||
cachedApi.updatePage(
|
cachedApi.updatePage(
|
||||||
currentPageId, null,
|
currentPageId, null,
|
||||||
if (hasTitleChanges) title else null,
|
title,
|
||||||
if (hasEmojiChanges) currentEmoji else null
|
if (hasEmojiChanges) currentEmoji else null
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -768,7 +773,7 @@ class PageEditorActivity : AppCompatActivity() {
|
|||||||
cachedApi.updatePage(
|
cachedApi.updatePage(
|
||||||
pageId!!,
|
pageId!!,
|
||||||
if (hasBodyChanges) markdown else null,
|
if (hasBodyChanges) markdown else null,
|
||||||
if (hasTitleChanges) title else null,
|
title,
|
||||||
if (pageEmoji != originalEmoji) pageEmoji else null
|
if (pageEmoji != originalEmoji) pageEmoji else null
|
||||||
)
|
)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
@@ -1004,6 +1009,7 @@ class PageEditorActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun loadEditorContent(markdown: String) {
|
private fun loadEditorContent(markdown: String) {
|
||||||
if (BuildConfig.DEBUG) android.util.Log.d("PageEditor", "loadEditorContent called with ${markdown.length} chars")
|
if (BuildConfig.DEBUG) android.util.Log.d("PageEditor", "loadEditorContent called with ${markdown.length} chars")
|
||||||
|
isContentLoading = true
|
||||||
if (isEditorRendered) {
|
if (isEditorRendered) {
|
||||||
loadEditorContentInternal(markdown)
|
loadEditorContentInternal(markdown)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user