@dr33m/react-native-readium 5.0.0-rc.22 → 5.0.0-rc.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42,6 +42,11 @@ abstract class BaseReaderFragment : Fragment() {
42
42
  // TTS
43
43
  private var ttsManager: TTSManager? = null
44
44
 
45
+ // True while the user has an active text selection.
46
+ // applyDecorations injects JS into the EPUB WebView; doing so while the user
47
+ // is dragging selection handles causes the selection to jump or reset.
48
+ private var isUserSelecting = false
49
+
45
50
  // Track active decoration listeners to avoid duplicates
46
51
  private val activeDecorationGroups = mutableSetOf<String>()
47
52
 
@@ -275,29 +280,33 @@ abstract class BaseReaderFragment : Fragment() {
275
280
 
276
281
  private fun applyTTSDecoration(locator: Locator) {
277
282
  if (!isNavigatorReady) return
283
+ if (isUserSelecting) return // skip DOM update while user drags selection handles
278
284
  val decorableNavigator = navigator as? DecorableNavigator ?: return
279
- // Call applyDecorations directlyit is a regular (non-suspend) function in
280
- // Readium 3.x. The test app (VisualReaderFragment) does the same: no launch {},
281
- // no channel routing. Wrapping in viewScope.launch defers the call to the next
282
- // dispatch cycle and was preventing the highlight from ever appearing.
283
- decorableNavigator.applyDecorations(
284
- listOf(
285
- Decoration(
286
- id = "tts",
287
- locator = locator,
288
- style = Decoration.Style.Highlight(
289
- tint = android.graphics.Color.argb(89, 0xF2, 0xCA, 0x50) // #f2ca50 @ 35%
285
+ // applyDecorations is suspend in Readium 3.x must be called from a coroutine.
286
+ // viewLifecycleOwner.lifecycleScope dispatches to Dispatchers.Main, matching
287
+ // the observeWhenStarted pattern used by the Readium test app.
288
+ viewLifecycleOwner.lifecycleScope.launch {
289
+ decorableNavigator.applyDecorations(
290
+ listOf(
291
+ Decoration(
292
+ id = "tts",
293
+ locator = locator,
294
+ style = Decoration.Style.Highlight(
295
+ tint = android.graphics.Color.argb(89, 0xF2, 0xCA, 0x50) // #f2ca50 @ 35%
296
+ )
290
297
  )
291
- )
292
- ),
293
- "tts"
294
- )
298
+ ),
299
+ "tts"
300
+ )
301
+ }
295
302
  }
296
303
 
297
304
  private fun clearTTSDecoration() {
298
305
  if (!isNavigatorReady) return
299
306
  val decorableNavigator = navigator as? DecorableNavigator ?: return
300
- decorableNavigator.applyDecorations(emptyList(), "tts")
307
+ viewLifecycleOwner.lifecycleScope.launch {
308
+ decorableNavigator.applyDecorations(emptyList(), "tts")
309
+ }
301
310
  }
302
311
 
303
312
  override fun onDestroyView() {
@@ -341,6 +350,10 @@ abstract class BaseReaderFragment : Fragment() {
341
350
  val currentLocator = currentSelection?.locator
342
351
  val currentText = currentLocator?.text?.highlight
343
352
 
353
+ // Keep the guard flag in sync so TTS decoration skips DOM updates
354
+ // while the user is dragging selection handles.
355
+ isUserSelecting = currentLocator != null
356
+
344
357
  // Check if selection has changed
345
358
  val hasChanged = when {
346
359
  previousSelection == null && currentLocator == null -> false
@@ -3,7 +3,9 @@ package com.reactnativereadium.reader
3
3
  import android.app.Application
4
4
  import kotlinx.coroutines.CoroutineScope
5
5
  import kotlinx.coroutines.Job
6
+ import kotlinx.coroutines.flow.distinctUntilChanged
6
7
  import kotlinx.coroutines.flow.launchIn
8
+ import kotlinx.coroutines.flow.map
7
9
  import kotlinx.coroutines.flow.onEach
8
10
  import kotlinx.coroutines.launch
9
11
  import org.readium.navigator.media.common.MediaNavigator
@@ -108,8 +110,14 @@ class TTSManager(
108
110
  }
109
111
  .launchIn(this)
110
112
 
111
- // Observe current locator
112
- ttsNavigator.currentLocator
113
+ // Observe utterance-level locator (sentence, not word).
114
+ // TtsNavigator.currentLocator returns tokenLocator ?: utteranceLocator — the
115
+ // word-level locator — which has incomplete CSS selectors and cannot be rendered
116
+ // by the EPUB decorator. utteranceLocator is the sentence-level locator and
117
+ // matches what the Readium test app (TtsViewModel.highlight) uses.
118
+ ttsNavigator.location
119
+ .map { it.utteranceLocator }
120
+ .distinctUntilChanged()
113
121
  .onEach { locator ->
114
122
  val text = locator.text.highlight ?: ""
115
123
  onUtterance(locator, text)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dr33m/react-native-readium",
3
- "version": "5.0.0-rc.22",
3
+ "version": "5.0.0-rc.24",
4
4
  "description": "A react-native wrapper for https://readium.org/",
5
5
  "main": "lib/src/index",
6
6
  "types": "lib/src/index.d.ts",