Skip to content

Commit a8fb889

Browse files
committed
Serialize EditorDependencies in parcelable
1 parent aa3b776 commit a8fb889

File tree

6 files changed

+132
-47
lines changed

6 files changed

+132
-47
lines changed

android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import androidx.webkit.WebViewAssetLoader.AssetsPathHandler
2727
import kotlinx.coroutines.CoroutineScope
2828
import kotlinx.coroutines.Dispatchers
2929
import kotlinx.coroutines.Job
30+
import kotlinx.coroutines.SupervisorJob
31+
import kotlinx.coroutines.cancel
3032
import kotlinx.coroutines.launch
3133
import kotlinx.coroutines.withContext
3234
import org.json.JSONException
@@ -66,8 +68,7 @@ class GutenbergView : WebView {
6668
private var networkRequestListener: NetworkRequestListener? = null
6769
private var loadingListener: EditorLoadingListener? = null
6870

69-
private val coroutineScope = CoroutineScope(Dispatchers.Main + Job())
70-
private var dependencyLoadingJob: Job? = null
71+
private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
7172

7273
/**
7374
* Stores the contextId from the most recent openMediaLibrary call
@@ -311,7 +312,7 @@ class GutenbergView : WebView {
311312
private fun prepareAndLoadEditor() {
312313
loadingListener?.onDependencyLoadingStarted()
313314

314-
dependencyLoadingJob = coroutineScope.launch {
315+
coroutineScope.launch {
315316
try {
316317
val editorService = EditorService.create(
317318
context = context,
@@ -758,7 +759,7 @@ class GutenbergView : WebView {
758759

759760
override fun onDetachedFromWindow() {
760761
super.onDetachedFromWindow()
761-
dependencyLoadingJob?.cancel()
762+
coroutineScope.cancel()
762763
clearConfig()
763764
this.stopLoading()
764765
FileCache.clearCache(context)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package org.wordpress.gutenberg.model
2+
3+
import android.content.Context
4+
import kotlinx.serialization.Serializable
5+
import kotlinx.serialization.encodeToString
6+
import kotlinx.serialization.json.Json
7+
import java.io.File
8+
import java.util.UUID
9+
10+
/**
11+
* Handles serialization of [EditorDependencies] to and from disk.
12+
*
13+
* Since [EditorDependencies] contains non-serializable types like [File],
14+
* this class provides methods to serialize dependencies to a temporary file
15+
* and deserialize them back. This is useful for passing large dependency
16+
* objects between activities without exceeding Intent size limits.
17+
*
18+
* ## Usage
19+
*
20+
* ```kotlin
21+
* // In the sending activity:
22+
* val filePath = EditorDependenciesSerializer.writeToDisk(context, dependencies)
23+
* intent.putExtra("dependencies_path", filePath)
24+
*
25+
* // In the receiving activity:
26+
* val filePath = intent.getStringExtra("dependencies_path")
27+
* val dependencies = EditorDependenciesSerializer.readFromDisk(filePath)
28+
* ```
29+
*/
30+
object EditorDependenciesSerializer {
31+
private val json = Json {
32+
ignoreUnknownKeys = true
33+
encodeDefaults = true
34+
}
35+
36+
/**
37+
* Serializable representation of [EditorDependencies].
38+
*
39+
* This class mirrors [EditorDependencies] but with serializable types:
40+
* - [File] references are stored as path strings
41+
* - [Date] objects are stored as Unix timestamps
42+
*/
43+
@Serializable
44+
private data class SerializedDependencies(
45+
val editorSettings: EditorSettings,
46+
val assetBundleRaw: EditorAssetBundle.RawAssetBundle,
47+
val assetBundleRootPath: String,
48+
val preloadList: EditorPreloadList?
49+
)
50+
51+
/**
52+
* Writes [EditorDependencies] to a temporary file in the app's cache directory.
53+
*
54+
* @param context The Android context.
55+
* @param dependencies The dependencies to serialize.
56+
* @return The absolute path to the created file.
57+
*/
58+
fun writeToDisk(context: Context, dependencies: EditorDependencies): String {
59+
val serialized = SerializedDependencies(
60+
editorSettings = dependencies.editorSettings,
61+
assetBundleRaw = EditorAssetBundle.RawAssetBundle(
62+
manifest = dependencies.assetBundle.manifest,
63+
downloadDate = dependencies.assetBundle.downloadDate
64+
),
65+
assetBundleRootPath = dependencies.assetBundle.bundleRoot.absolutePath,
66+
preloadList = dependencies.preloadList
67+
)
68+
69+
val fileName = "editor_dependencies_${UUID.randomUUID()}.json"
70+
val file = File(context.cacheDir, fileName)
71+
file.writeText(json.encodeToString(serialized))
72+
73+
return file.absolutePath
74+
}
75+
76+
/**
77+
* Reads [EditorDependencies] from a file and deletes the file.
78+
*
79+
* @param filePath The absolute path to the serialized dependencies file.
80+
* @return The deserialized dependencies, or `null` if the file doesn't exist or is invalid.
81+
*/
82+
fun readFromDisk(filePath: String?): EditorDependencies? {
83+
if (filePath == null) return null
84+
85+
val file = File(filePath)
86+
if (!file.exists()) return null
87+
88+
return try {
89+
val data = file.readText()
90+
val serialized = json.decodeFromString<SerializedDependencies>(data)
91+
92+
val dependencies = EditorDependencies(
93+
editorSettings = serialized.editorSettings,
94+
assetBundle = serialized.assetBundleRaw.toEditorAssetBundle(
95+
File(serialized.assetBundleRootPath)
96+
),
97+
preloadList = serialized.preloadList
98+
)
99+
100+
// Clean up the temp file
101+
file.delete()
102+
103+
dependencies
104+
} catch (e: Exception) {
105+
file.delete()
106+
null
107+
}
108+
}
109+
}

android/Gutenberg/src/main/java/org/wordpress/gutenberg/views/EditorProgressView.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.view.Gravity
66
import android.widget.LinearLayout
77
import android.widget.ProgressBar
88
import android.widget.TextView
9+
import androidx.core.widget.TextViewCompat
910
import org.wordpress.gutenberg.model.EditorProgress
1011

1112
/**
@@ -62,7 +63,7 @@ class EditorProgressView @JvmOverloads constructor(
6263
marginEnd = dpToPx(16)
6364
}
6465
gravity = Gravity.CENTER
65-
setTextAppearance(android.R.style.TextAppearance_Material_Body1)
66+
TextViewCompat.setTextAppearance(this, android.R.style.TextAppearance_Material_Body1)
6667
}
6768

6869
addView(progressBar)

android/app/src/main/java/com/example/gutenbergkit/EditorActivity.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,15 @@ import org.wordpress.gutenberg.model.EditorConfiguration
5252
import org.wordpress.gutenberg.GutenbergView
5353
import org.wordpress.gutenberg.EditorLoadingListener
5454
import org.wordpress.gutenberg.model.EditorDependencies
55+
import org.wordpress.gutenberg.model.EditorDependenciesSerializer
5556
import org.wordpress.gutenberg.model.EditorProgress
5657

5758
class EditorActivity : ComponentActivity() {
59+
60+
companion object {
61+
const val EXTRA_DEPENDENCIES_PATH = "dependencies_path"
62+
}
63+
5864
private var gutenbergView: GutenbergView? = null
5965
private lateinit var filePickerLauncher: ActivityResultLauncher<Intent>
6066
override fun onCreate(savedInstanceState: Bundle?) {
@@ -89,8 +95,9 @@ class EditorActivity : ComponentActivity() {
8995
intent.getParcelableExtra<EditorConfiguration>(MainActivity.EXTRA_CONFIGURATION)
9096
} ?: EditorConfiguration.bundled()
9197

92-
// Get dependencies from the holder (set by SitePreparationActivity)
93-
val dependencies = EditorDependenciesHolder.getAndClear()
98+
// Read dependencies from disk if a file path was provided
99+
val dependenciesPath = intent.getStringExtra(EXTRA_DEPENDENCIES_PATH)
100+
val dependencies = EditorDependenciesSerializer.readFromDisk(dependenciesPath)
94101

95102
setContent {
96103
AppTheme {

android/app/src/main/java/com/example/gutenbergkit/EditorDependenciesHolder.kt

Lines changed: 0 additions & 37 deletions
This file was deleted.

android/app/src/main/java/com/example/gutenbergkit/SitePreparationActivity.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import androidx.compose.ui.unit.dp
5454
import androidx.lifecycle.ViewModelProvider
5555
import com.example.gutenbergkit.ui.theme.AppTheme
5656
import org.wordpress.gutenberg.model.EditorConfiguration
57+
import org.wordpress.gutenberg.model.EditorDependenciesSerializer
5758

5859
class SitePreparationActivity : ComponentActivity() {
5960

@@ -146,11 +147,14 @@ class SitePreparationActivity : ComponentActivity() {
146147
configuration: EditorConfiguration,
147148
dependencies: org.wordpress.gutenberg.model.EditorDependencies?
148149
) {
149-
// Store dependencies in the holder for EditorActivity to retrieve
150-
EditorDependenciesHolder.set(dependencies)
151-
152150
val intent = Intent(this, EditorActivity::class.java).apply {
153151
putExtra(MainActivity.EXTRA_CONFIGURATION, configuration)
152+
153+
// Serialize dependencies to disk and pass the file path
154+
if (dependencies != null) {
155+
val filePath = EditorDependenciesSerializer.writeToDisk(this@SitePreparationActivity, dependencies)
156+
putExtra(EditorActivity.EXTRA_DEPENDENCIES_PATH, filePath)
157+
}
154158
}
155159
startActivity(intent)
156160
}

0 commit comments

Comments
 (0)