react-native-readium 4.0.2 → 5.0.0-rc.0

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.
Files changed (118) hide show
  1. package/README.md +93 -9
  2. package/android/build.gradle +32 -29
  3. package/android/gradle.properties +3 -3
  4. package/android/src/main/java/com/reactnativereadium/ReadiumView.kt +88 -28
  5. package/android/src/main/java/com/reactnativereadium/ReadiumViewManager.kt +20 -19
  6. package/android/src/main/java/com/reactnativereadium/reader/BaseReaderFragment.kt +27 -6
  7. package/android/src/main/java/com/reactnativereadium/reader/EpubReaderFragment.kt +53 -69
  8. package/android/src/main/java/com/reactnativereadium/reader/PositionLabelManager.kt +132 -0
  9. package/android/src/main/java/com/reactnativereadium/reader/ReaderService.kt +64 -65
  10. package/android/src/main/java/com/reactnativereadium/reader/ReaderViewModel.kt +6 -85
  11. package/android/src/main/java/com/reactnativereadium/reader/VisualReaderFragment.kt +32 -2
  12. package/android/src/main/java/com/reactnativereadium/utils/FragmentFactory.kt +2 -3
  13. package/android/src/main/java/com/reactnativereadium/utils/JsonExtensions.kt +61 -0
  14. package/android/src/main/java/com/reactnativereadium/utils/MetadataNormalizer.kt +183 -0
  15. package/android/src/main/java/com/reactnativereadium/utils/NormalizedMetadata.kt +179 -0
  16. package/android/src/main/java/com/reactnativereadium/utils/extensions/InputStream.kt +0 -9
  17. package/ios/App/AppModule.swift +3 -9
  18. package/ios/Common/Toolkit/Extensions/Locator.swift +1 -1
  19. package/ios/Data/Bookmark.swift +1 -1
  20. package/ios/Reader/Common/ReaderViewController.swift +118 -21
  21. package/ios/Reader/EPUB/AssociatedColors.swift +1 -1
  22. package/ios/Reader/EPUB/EPUBHTTPServer.swift +13 -0
  23. package/ios/Reader/EPUB/EPUBModule.swift +1 -1
  24. package/ios/Reader/EPUB/EPUBViewController.swift +3 -4
  25. package/ios/Reader/ReaderFormatModule.swift +1 -1
  26. package/ios/Reader/ReaderModule.swift +1 -1
  27. package/ios/Reader/ReaderService.swift +70 -35
  28. package/ios/ReadiumView.swift +62 -25
  29. package/ios/ReadiumViewManager.m +1 -1
  30. package/lib/src/ReadiumViewNativeComponent.d.ts +19 -0
  31. package/lib/src/ReadiumViewNativeComponent.js +10 -0
  32. package/lib/src/components/BaseReadiumView.d.ts +1 -2
  33. package/lib/src/components/BaseReadiumView.js +3 -7
  34. package/lib/src/components/ReadiumView.js +15 -15
  35. package/lib/src/components/ReadiumView.web.js +100 -21
  36. package/lib/src/interfaces/BaseReadiumViewProps.d.ts +2 -1
  37. package/lib/src/interfaces/Preferences.d.ts +3 -2
  38. package/lib/src/interfaces/PublicationMetadata.d.ts +114 -0
  39. package/lib/src/interfaces/PublicationMetadata.js +1 -0
  40. package/lib/src/interfaces/PublicationReady.d.ts +15 -0
  41. package/lib/src/interfaces/PublicationReady.js +1 -0
  42. package/lib/src/interfaces/index.d.ts +2 -0
  43. package/lib/src/interfaces/index.js +2 -0
  44. package/lib/src/utils/index.d.ts +0 -1
  45. package/lib/src/utils/index.js +0 -1
  46. package/lib/web/hooks/index.d.ts +3 -2
  47. package/lib/web/hooks/index.js +3 -2
  48. package/lib/web/hooks/useLocationObserver.d.ts +2 -1
  49. package/lib/web/hooks/useLocationObserver.js +18 -11
  50. package/lib/web/hooks/useNavigator.d.ts +12 -0
  51. package/lib/web/hooks/useNavigator.js +87 -0
  52. package/lib/web/hooks/usePositionLabel.d.ts +9 -0
  53. package/lib/web/hooks/usePositionLabel.js +33 -0
  54. package/lib/web/hooks/usePreferencesObserver.d.ts +2 -0
  55. package/lib/web/hooks/usePreferencesObserver.js +54 -0
  56. package/lib/web/utils/manifestFetcher.d.ts +8 -0
  57. package/lib/web/utils/manifestFetcher.js +28 -0
  58. package/lib/web/utils/manifestNormalizer.d.ts +8 -0
  59. package/lib/web/utils/manifestNormalizer.js +70 -0
  60. package/lib/web/utils/metadataNormalizer.d.ts +53 -0
  61. package/lib/web/utils/metadataNormalizer.js +220 -0
  62. package/lib/web/utils/navigatorListeners.d.ts +6 -0
  63. package/lib/web/utils/navigatorListeners.js +50 -0
  64. package/lib/web/utils/publicationUtils.d.ts +15 -0
  65. package/lib/web/utils/publicationUtils.js +39 -0
  66. package/package.json +24 -14
  67. package/react-native-readium.podspec +7 -5
  68. package/src/ReadiumViewNativeComponent.ts +35 -0
  69. package/src/components/BaseReadiumView.tsx +3 -10
  70. package/src/components/ReadiumView.tsx +15 -15
  71. package/src/components/ReadiumView.web.tsx +120 -27
  72. package/src/interfaces/BaseReadiumViewProps.ts +2 -1
  73. package/src/interfaces/Preferences.ts +3 -2
  74. package/src/interfaces/PublicationMetadata.ts +141 -0
  75. package/src/interfaces/PublicationReady.ts +18 -0
  76. package/src/interfaces/index.ts +2 -0
  77. package/src/utils/index.ts +0 -1
  78. package/web/hooks/index.ts +3 -2
  79. package/web/hooks/useLocationObserver.ts +24 -11
  80. package/web/hooks/useNavigator.ts +146 -0
  81. package/web/hooks/usePositionLabel.ts +51 -0
  82. package/web/hooks/usePreferencesObserver.ts +69 -0
  83. package/web/utils/manifestFetcher.ts +38 -0
  84. package/web/utils/manifestNormalizer.ts +74 -0
  85. package/web/utils/metadataNormalizer.ts +238 -0
  86. package/web/utils/navigatorListeners.ts +60 -0
  87. package/web/utils/publicationUtils.ts +47 -0
  88. package/android/src/main/java/com/reactnativereadium/search/SearchFragment.kt +0 -100
  89. package/android/src/main/java/com/reactnativereadium/search/SearchPagingSource.kt +0 -44
  90. package/android/src/main/java/com/reactnativereadium/search/SearchResultAdapter.kt +0 -68
  91. package/android/src/main/java/com/reactnativereadium/utils/R2DispatcherActivity.kt +0 -45
  92. package/android/src/main/java/com/reactnativereadium/utils/SectionDecoration.kt +0 -98
  93. package/android/src/main/java/com/reactnativereadium/utils/SingleClickListener.kt +0 -32
  94. package/android/src/main/java/com/reactnativereadium/utils/extensions/Bitmap.kt +0 -23
  95. package/android/src/main/java/com/reactnativereadium/utils/extensions/Context.kt +0 -16
  96. package/android/src/main/java/com/reactnativereadium/utils/extensions/File.kt +0 -22
  97. package/android/src/main/java/com/reactnativereadium/utils/extensions/Link.kt +0 -6
  98. package/android/src/main/java/com/reactnativereadium/utils/extensions/Metadata.kt +0 -6
  99. package/android/src/main/java/com/reactnativereadium/utils/extensions/URL.kt +0 -29
  100. package/android/src/main/java/com/reactnativereadium/utils/extensions/Uri.kt +0 -17
  101. package/android/src/main/res/layout/fragment_search.xml +0 -39
  102. package/android/src/main/res/layout/item_recycle_search.xml +0 -14
  103. package/ios/Common/EPUBPreferences.swift +0 -8
  104. package/ios/Common/Paths.swift +0 -52
  105. package/ios/Common/Publication.swift +0 -15
  106. package/ios/Common/Toolkit/Extensions/HTTPClient.swift +0 -65
  107. package/ios/Common/Toolkit/Extensions/UIImage.swift +0 -12
  108. package/ios/Common/Toolkit/Extensions/UIViewController.swift +0 -19
  109. package/ios/Common/Toolkit/ScreenOrientation.swift +0 -13
  110. package/lib/src/utils/createFragment.d.ts +0 -1
  111. package/lib/src/utils/createFragment.js +0 -10
  112. package/lib/web/hooks/useReaderRef.d.ts +0 -3
  113. package/lib/web/hooks/useReaderRef.js +0 -85
  114. package/lib/web/hooks/useSettingsObserver.d.ts +0 -2
  115. package/lib/web/hooks/useSettingsObserver.js +0 -44
  116. package/src/utils/createFragment.ts +0 -15
  117. package/web/hooks/useReaderRef.ts +0 -109
  118. package/web/hooks/useSettingsObserver.ts +0 -61
@@ -0,0 +1,47 @@
1
+ import {
2
+ Locator,
3
+ LocatorLocations,
4
+ Manifest,
5
+ Publication,
6
+ } from '@readium/shared';
7
+
8
+ /**
9
+ * Normalizes a publication URL to ensure it ends with /
10
+ * If URL ends with manifest.json, extracts the base directory
11
+ */
12
+ export function normalizePublicationURL(url: string): string {
13
+ if (url.endsWith('manifest.json')) {
14
+ return url.substring(0, url.lastIndexOf('/') + 1);
15
+ }
16
+ return url.endsWith('/') ? url : `${url}/`;
17
+ }
18
+
19
+ /**
20
+ * Creates positions array from publication reading order
21
+ * NOTE: The published npm packages (v2.2.5) require positions to be passed explicitly
22
+ */
23
+ export function createPositions(publication: Publication): Locator[] {
24
+ return publication.readingOrder.items.map((link: any, idx: number) => {
25
+ const position = idx + 1;
26
+ return new Locator({
27
+ href: link.href,
28
+ type: link.type,
29
+ title: link.title,
30
+ locations: new LocatorLocations({
31
+ position: position,
32
+ progression: 0,
33
+ totalProgression: idx / publication.readingOrder.items.length,
34
+ }),
35
+ });
36
+ });
37
+ }
38
+
39
+ /**
40
+ * Extracts table of contents items from manifest
41
+ */
42
+ export function extractTableOfContents(manifest: Manifest): any[] {
43
+ return Array.isArray(manifest.toc)
44
+ ? manifest.toc
45
+ : // @ts-ignore
46
+ manifest.toc.items || [];
47
+ }
@@ -1,100 +0,0 @@
1
- /*
2
- * Copyright 2021 Readium Foundation. All rights reserved.
3
- * Use of this source code is governed by the BSD-style license
4
- * available in the top-level LICENSE file of the project.
5
- */
6
-
7
- package com.reactnativereadium.search
8
-
9
- import android.os.Bundle
10
- import android.view.LayoutInflater
11
- import android.view.View
12
- import android.view.ViewGroup
13
- import androidx.core.view.isVisible
14
- import androidx.fragment.app.Fragment
15
- import androidx.fragment.app.activityViewModels
16
- import androidx.fragment.app.setFragmentResult
17
- import androidx.lifecycle.lifecycleScope
18
- import androidx.recyclerview.widget.DividerItemDecoration
19
- import androidx.recyclerview.widget.LinearLayoutManager
20
- import kotlinx.coroutines.flow.launchIn
21
- import kotlinx.coroutines.flow.onEach
22
- import org.readium.r2.shared.publication.Locator
23
- import com.reactnativereadium.R
24
- import com.reactnativereadium.databinding.FragmentSearchBinding
25
- import com.reactnativereadium.reader.ReaderViewModel
26
- import com.reactnativereadium.utils.SectionDecoration
27
-
28
- class SearchFragment : Fragment(R.layout.fragment_search) {
29
-
30
- private val viewModel: ReaderViewModel by activityViewModels()
31
-
32
- private var _binding: FragmentSearchBinding? = null
33
- private val binding get() = _binding!!
34
-
35
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
36
- super.onViewCreated(view, savedInstanceState)
37
-
38
- val viewScope = viewLifecycleOwner.lifecycleScope
39
-
40
- val searchAdapter = SearchResultAdapter(object : SearchResultAdapter.Listener {
41
- override fun onItemClicked(v: View, locator: Locator) {
42
- val result = Bundle().apply {
43
- putParcelable(SearchFragment::class.java.name, locator)
44
- }
45
- setFragmentResult(SearchFragment::class.java.name, result)
46
- }
47
- })
48
-
49
- viewModel.searchResult
50
- .onEach { searchAdapter.submitData(it) }
51
- .launchIn(viewScope)
52
-
53
- viewModel.searchLocators
54
- .onEach { binding.noResultLabel.isVisible = it.isEmpty() }
55
- .launchIn(viewScope)
56
-
57
- viewModel.channel
58
- .receive(viewLifecycleOwner) { event ->
59
- when (event) {
60
- ReaderViewModel.Event.StartNewSearch ->
61
- binding.searchRecyclerView.scrollToPosition(0)
62
- else -> {}
63
- }
64
- }
65
-
66
- binding.searchRecyclerView.apply {
67
- adapter = searchAdapter
68
- layoutManager = LinearLayoutManager(activity)
69
- addItemDecoration(SectionDecoration(context, object : SectionDecoration.Listener {
70
- override fun isStartOfSection(itemPos: Int): Boolean =
71
- viewModel.searchLocators.value.run {
72
- when {
73
- itemPos == 0 -> true
74
- itemPos < 0 -> false
75
- itemPos >= size -> false
76
- else -> getOrNull(itemPos)?.title != getOrNull(itemPos-1)?.title
77
- }
78
- }
79
-
80
- override fun sectionTitle(itemPos: Int): String =
81
- viewModel.searchLocators.value.getOrNull(itemPos)?.title ?: ""
82
- }))
83
- addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
84
- }
85
- }
86
-
87
- override fun onCreateView(
88
- inflater: LayoutInflater,
89
- container: ViewGroup?,
90
- savedInstanceState: Bundle?
91
- ): View {
92
- _binding = FragmentSearchBinding.inflate(inflater, container, false)
93
- return binding.root
94
- }
95
-
96
- override fun onDestroyView() {
97
- super.onDestroyView()
98
- _binding = null
99
- }
100
- }
@@ -1,44 +0,0 @@
1
- /*
2
- * Copyright 2021 Readium Foundation. All rights reserved.
3
- * Use of this source code is governed by the BSD-style license
4
- * available in the top-level LICENSE file of the project.
5
- */
6
-
7
- package com.reactnativereadium.search
8
-
9
- import androidx.paging.PagingSource
10
- import androidx.paging.PagingState
11
- import org.readium.r2.shared.Search
12
- import org.readium.r2.shared.publication.Locator
13
- import org.readium.r2.shared.publication.LocatorCollection
14
- import org.readium.r2.shared.publication.services.search.SearchIterator
15
- import org.readium.r2.shared.publication.services.search.SearchTry
16
-
17
- @OptIn(Search::class)
18
- class SearchPagingSource(
19
- private val listener: Listener?
20
- ) : PagingSource<Unit, Locator>() {
21
-
22
- interface Listener {
23
- suspend fun next(): SearchTry<LocatorCollection?>
24
- }
25
-
26
- override val keyReuseSupported: Boolean get() = true
27
-
28
- override fun getRefreshKey(state: PagingState<Unit, Locator>): Unit? = null
29
-
30
- override suspend fun load(params: LoadParams<Unit>): LoadResult<Unit, Locator> {
31
- listener ?: return LoadResult.Page(data = emptyList(), prevKey = null, nextKey = null)
32
-
33
- return try {
34
- val page = listener.next().getOrThrow()
35
- LoadResult.Page(
36
- data = page?.locators ?: emptyList(),
37
- prevKey = null,
38
- nextKey = if (page == null) null else Unit
39
- )
40
- } catch (e: Exception) {
41
- LoadResult.Error(e)
42
- }
43
- }
44
- }
@@ -1,68 +0,0 @@
1
- /*
2
- * Copyright 2021 Readium Foundation. All rights reserved.
3
- * Use of this source code is governed by the BSD-style license
4
- * available in the top-level LICENSE file of the project.
5
- */
6
-
7
- package com.reactnativereadium.search
8
-
9
- import android.os.Build
10
- import android.text.Html
11
- import android.view.LayoutInflater
12
- import android.view.View
13
- import android.view.ViewGroup
14
- import androidx.paging.PagingDataAdapter
15
- import androidx.recyclerview.widget.DiffUtil
16
- import androidx.recyclerview.widget.RecyclerView
17
- import org.readium.r2.shared.publication.Locator
18
- import com.reactnativereadium.databinding.ItemRecycleSearchBinding
19
- import com.reactnativereadium.utils.singleClick
20
-
21
- /**
22
- * This class is an adapter for Search results' recycler view.
23
- */
24
- class SearchResultAdapter(private var listener: Listener) :
25
- PagingDataAdapter<Locator, SearchResultAdapter.ViewHolder>(ItemCallback()) {
26
-
27
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
28
- return ViewHolder(
29
- ItemRecycleSearchBinding.inflate(
30
- LayoutInflater.from(parent.context), parent, false
31
- )
32
- )
33
- }
34
-
35
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
36
- val locator = getItem(position) ?: return
37
- val html =
38
- "${locator.text.before}<span style=\"background:yellow;\"><b>${locator.text.highlight}</b></span>${locator.text.after}"
39
- holder.textView.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
40
- Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT)
41
- } else {
42
- @Suppress("DEPRECATION")
43
- Html.fromHtml(html)
44
- }
45
-
46
- holder.itemView.singleClick { v ->
47
- listener.onItemClicked(v, locator)
48
- }
49
- }
50
-
51
- inner class ViewHolder(val binding: ItemRecycleSearchBinding) :
52
- RecyclerView.ViewHolder(binding.root) {
53
- val textView = binding.text
54
- }
55
-
56
- interface Listener {
57
- fun onItemClicked(v: View, locator: Locator)
58
- }
59
-
60
- private class ItemCallback : DiffUtil.ItemCallback<Locator>() {
61
-
62
- override fun areItemsTheSame(oldItem: Locator, newItem: Locator): Boolean =
63
- oldItem == newItem
64
-
65
- override fun areContentsTheSame(oldItem: Locator, newItem: Locator): Boolean =
66
- oldItem == newItem
67
- }
68
- }
@@ -1,45 +0,0 @@
1
- package com.reactnativereadium.utils
2
-
3
- import android.app.Activity
4
- import android.content.Intent
5
- import android.net.Uri
6
- import android.os.Bundle
7
- //import com.reactnativereadium.MainActivity
8
- import timber.log.Timber
9
-
10
- class R2DispatcherActivity : Activity() {
11
-
12
- override fun onCreate(savedInstanceState: Bundle?) {
13
- super.onCreate(savedInstanceState)
14
- dispatchIntent(intent)
15
- finish()
16
- }
17
-
18
- private fun dispatchIntent(intent: Intent) {
19
- val uri = uriFromIntent(intent)
20
- ?: run {
21
- Timber.d("Got an empty intent.")
22
- return
23
- }
24
- // FIXME: MainActivity
25
- // val newIntent = Intent(this, MainActivity::class.java).apply {
26
- // addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
27
- // data = uri
28
- // }
29
- // startActivity(newIntent)
30
- }
31
-
32
- private fun uriFromIntent(intent: Intent): Uri? =
33
- when (intent.action) {
34
- Intent.ACTION_SEND -> {
35
- if ("text/plain" == intent.type) {
36
- intent.getStringExtra(Intent.EXTRA_TEXT).let { Uri.parse(it) }
37
- } else {
38
- intent.getParcelableExtra(Intent.EXTRA_STREAM)
39
- }
40
- }
41
- else -> {
42
- intent.data
43
- }
44
- }
45
- }
@@ -1,98 +0,0 @@
1
- package com.reactnativereadium.utils
2
-
3
- import android.content.Context
4
- import android.graphics.Canvas
5
- import android.graphics.Rect
6
- import android.view.LayoutInflater
7
- import android.view.View
8
- import android.view.ViewGroup
9
- import android.widget.TextView
10
- import androidx.core.view.children
11
- import androidx.recyclerview.widget.RecyclerView
12
- import androidx.recyclerview.widget.RecyclerView.NO_POSITION
13
- /* import com.reactnativereadium.databinding.SectionHeaderBinding */
14
-
15
- class SectionDecoration(
16
- private val context: Context,
17
- private val listener: Listener
18
- ) : RecyclerView.ItemDecoration() {
19
-
20
- interface Listener {
21
- fun isStartOfSection(itemPos: Int): Boolean
22
- fun sectionTitle(itemPos: Int): String
23
- }
24
-
25
- private lateinit var headerView: View
26
- private lateinit var sectionTitleView: TextView
27
-
28
- override fun getItemOffsets(
29
- outRect: Rect,
30
- view: View,
31
- parent: RecyclerView,
32
- state: RecyclerView.State
33
- ) {
34
- super.getItemOffsets(outRect, view, parent, state)
35
- val pos = parent.getChildAdapterPosition(view)
36
- initHeaderViewIfNeeded(parent)
37
- if (listener.sectionTitle(pos) != "" && listener.isStartOfSection(pos)) {
38
- sectionTitleView.text = listener.sectionTitle(pos)
39
- fixLayoutSize(headerView, parent)
40
- outRect.top = headerView.height
41
- }
42
- }
43
-
44
- override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
45
- super.onDrawOver(c, parent, state)
46
- initHeaderViewIfNeeded(parent)
47
-
48
- val children = parent.children.toList()
49
- children.forEach { child ->
50
- val pos = parent.getChildAdapterPosition(child)
51
- if (pos != NO_POSITION && listener.sectionTitle(pos) != "" &&
52
- (listener.isStartOfSection(pos) || isTopChild(child, children))) {
53
- sectionTitleView.text = listener.sectionTitle(pos)
54
- fixLayoutSize(headerView, parent)
55
- drawHeader(c, child, headerView)
56
- }
57
- }
58
- }
59
-
60
- private fun initHeaderViewIfNeeded(parent: RecyclerView) {
61
- if (::headerView.isInitialized) return
62
- /* FIXME: databinding.SectionHeaderBinding */
63
- /* SectionHeaderBinding.inflate(
64
- LayoutInflater.from(context),
65
- parent,
66
- false
67
- ).apply {
68
- headerView = root
69
- sectionTitleView = header
70
- } */
71
- }
72
-
73
- private fun fixLayoutSize(v: View, parent: ViewGroup) {
74
- val widthSpec = View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY)
75
- val heightSpec = View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED)
76
- val childWidth = ViewGroup.getChildMeasureSpec(widthSpec, parent.paddingStart + parent.paddingEnd, v.layoutParams.width)
77
- val childHeight = ViewGroup.getChildMeasureSpec(heightSpec, parent.paddingTop + parent.paddingBottom, v.layoutParams.height)
78
- v.measure(childWidth, childHeight)
79
- v.layout(0, 0, v.measuredWidth, v.measuredHeight)
80
- }
81
-
82
- private fun drawHeader(c: Canvas, child: View, headerView: View) {
83
- c.run {
84
- save()
85
- translate(0F, maxOf(0, child.top - headerView.height).toFloat())
86
- headerView.draw(this)
87
- restore()
88
- }
89
- }
90
-
91
- private fun isTopChild(child: View, children: List<View>): Boolean {
92
- var tmp = child.top
93
- children.forEach { c ->
94
- tmp = minOf(c.top, tmp)
95
- }
96
- return child.top == tmp
97
- }
98
- }
@@ -1,32 +0,0 @@
1
- package com.reactnativereadium.utils
2
-
3
- import android.view.View
4
-
5
-
6
- /**
7
- * Prevents from double clicks on a view, which could otherwise lead to unpredictable states. Useful
8
- * while transitioning to another activity for instance.
9
- */
10
- class SingleClickListener(private val click: (v: View) -> Unit) : View.OnClickListener {
11
-
12
- companion object {
13
- private const val DOUBLE_CLICK_TIMEOUT = 2500
14
- }
15
-
16
- private var lastClick: Long = 0
17
-
18
- override fun onClick(v: View) {
19
- if (getLastClickTimeout() > DOUBLE_CLICK_TIMEOUT) {
20
- lastClick = System.currentTimeMillis()
21
- click(v)
22
- }
23
- }
24
-
25
- private fun getLastClickTimeout(): Long {
26
- return System.currentTimeMillis() - lastClick
27
- }
28
- }
29
-
30
- fun View.singleClick(l: (View) -> Unit) {
31
- setOnClickListener(SingleClickListener(l))
32
- }
@@ -1,23 +0,0 @@
1
- package com.reactnativereadium.utils.extensions
2
-
3
- import android.graphics.Bitmap
4
- import android.util.Base64
5
- import timber.log.Timber
6
- import java.io.ByteArrayOutputStream
7
-
8
- /**
9
- * Converts the receiver bitmap into a data URL ready to be used in HTML or CSS.
10
- *
11
- * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
12
- */
13
- fun Bitmap.toDataUrl(): String? =
14
- try {
15
- val stream = ByteArrayOutputStream()
16
- compress(Bitmap.CompressFormat.PNG, 100, stream)
17
- .also { success -> if (!success) throw Exception("Can't compress image to PNG") }
18
- val b64 = Base64.encodeToString(stream.toByteArray(), Base64.DEFAULT)
19
- "data:image/png;base64,$b64"
20
- } catch (e: Exception) {
21
- Timber.e(e)
22
- null
23
- }
@@ -1,16 +0,0 @@
1
- package com.reactnativereadium.utils.extensions
2
-
3
- import android.content.Context
4
- import androidx.annotation.ColorInt
5
- import androidx.annotation.ColorRes
6
- import androidx.core.content.ContextCompat
7
-
8
-
9
- /**
10
- * Extensions
11
- */
12
-
13
- @ColorInt
14
- fun Context.color(@ColorRes id: Int): Int {
15
- return ContextCompat.getColor(this, id)
16
- }
@@ -1,22 +0,0 @@
1
- package com.reactnativereadium.utils.extensions
2
-
3
- import kotlinx.coroutines.Dispatchers
4
- import kotlinx.coroutines.withContext
5
- import java.io.File
6
- import java.io.FileFilter
7
- import java.io.IOException
8
-
9
- suspend fun File.moveTo(target: File) = withContext(Dispatchers.IO) {
10
- if (!this@moveTo.renameTo(target))
11
- throw IOException()
12
- }
13
-
14
-
15
- /**
16
- * As there are cases where [File.listFiles] returns null even though it is a directory, we return
17
- * an empty list instead.
18
- */
19
- fun File.listFilesSafely(filter: FileFilter? = null): List<File> {
20
- val array: Array<File>? = if (filter == null) listFiles() else listFiles(filter)
21
- return array?.toList() ?: emptyList()
22
- }
@@ -1,6 +0,0 @@
1
- package com.reactnativereadium.utils.extensions
2
-
3
- import org.readium.r2.shared.publication.Link
4
-
5
- val Link.outlineTitle: String
6
- get() = title ?: href
@@ -1,6 +0,0 @@
1
- package com.reactnativereadium.utils.extensions
2
-
3
- import org.readium.r2.shared.publication.Metadata
4
-
5
- val Metadata.authorName: String get() =
6
- authors.firstOrNull()?.name ?: ""
@@ -1,29 +0,0 @@
1
- package com.reactnativereadium.utils.extensions
2
-
3
- import kotlinx.coroutines.Dispatchers
4
- import kotlinx.coroutines.withContext
5
- import org.readium.r2.shared.extensions.extension
6
- import org.readium.r2.shared.extensions.tryOr
7
- import org.readium.r2.shared.extensions.tryOrNull
8
- import java.io.File
9
- import java.io.FileOutputStream
10
- import java.net.URL
11
- import java.util.*
12
-
13
- suspend fun URL.download(path: String): File? = tryOr(null) {
14
- val file = File(path)
15
- withContext(Dispatchers.IO) {
16
- openStream().use { input ->
17
- FileOutputStream(file).use { output ->
18
- input.copyTo(output)
19
- }
20
- }
21
- }
22
- file
23
- }
24
-
25
- suspend fun URL.copyToTempFile(dir: String): File? = tryOrNull {
26
- val filename = UUID.randomUUID().toString()
27
- val path = "$dir$filename.$extension"
28
- download(path)
29
- }
@@ -1,17 +0,0 @@
1
- package com.reactnativereadium.utils.extensions
2
-
3
- import android.content.Context
4
- import android.net.Uri
5
- import org.readium.r2.shared.extensions.tryOrNull
6
- import org.readium.r2.shared.util.mediatype.MediaType
7
- import com.reactnativereadium.utils.ContentResolverUtil
8
- import java.io.File
9
- import java.util.*
10
-
11
- suspend fun Uri.copyToTempFile(context: Context, dir: String): File? = tryOrNull {
12
- val filename = UUID.randomUUID().toString()
13
- val mediaType = MediaType.ofUri(this, context.contentResolver)
14
- val path = "$dir$filename.${mediaType?.fileExtension ?: "tmp"}"
15
- ContentResolverUtil.getContentInputStream(context, this, path)
16
- return@tryOrNull File(path)
17
- }
@@ -1,39 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?><!--
2
- ~ Module: r2-navigator-kotlin
3
- ~ Developers: Aferdita Muriqi, Clément Baumann
4
- ~
5
- ~ Copyright (c) 2018. Readium Foundation. All rights reserved.
6
- ~ Use of this source code is governed by a BSD-style license which is detailed in the
7
- ~ LICENSE file present in the project repository where this source code is maintained.
8
- -->
9
-
10
- <androidx.constraintlayout.widget.ConstraintLayout
11
- xmlns:android="http://schemas.android.com/apk/res/android"
12
- xmlns:app="http://schemas.android.com/apk/res-auto"
13
- android:id="@+id/search_overlay"
14
- android:layout_width="match_parent"
15
- android:layout_height="match_parent"
16
- android:background="@color/colorAccent">
17
-
18
- <androidx.recyclerview.widget.RecyclerView
19
- android:id="@+id/search_recyclerView"
20
- android:layout_width="0dp"
21
- android:layout_height="0dp"
22
- android:background="@android:color/white"
23
- app:layout_constraintBottom_toBottomOf="@id/search_overlay"
24
- app:layout_constraintEnd_toEndOf="@id/search_overlay"
25
- app:layout_constraintStart_toStartOf="@id/search_overlay"
26
- app:layout_constraintTop_toTopOf="@id/search_overlay" />
27
-
28
- <TextView
29
- android:id="@+id/noResultLabel"
30
- android:layout_width="wrap_content"
31
- android:layout_height="wrap_content"
32
- android:layout_marginTop="24dp"
33
- android:text="@string/no_result"
34
- app:layout_constraintEnd_toEndOf="parent"
35
- app:layout_constraintStart_toStartOf="parent"
36
- app:layout_constraintTop_toTopOf="parent"
37
- android:visibility="gone"/>
38
-
39
- </androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,14 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
- android:orientation="horizontal" android:layout_width="match_parent"
4
- android:layout_height="wrap_content"
5
- android:padding="8dp">
6
-
7
- <TextView
8
- android:id="@+id/text"
9
- android:layout_width="match_parent"
10
- android:layout_height="wrap_content"
11
- android:gravity="start|top"
12
- android:textAlignment="textStart"/>
13
-
14
- </LinearLayout>
@@ -1,8 +0,0 @@
1
- //
2
- // EPUBPreferences.swift
3
- // react-native-readium
4
- //
5
- // Created by Christopher Wilkinson on 11/09/2023.
6
- //
7
-
8
- import Foundation