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.
- package/README.md +93 -9
- package/android/build.gradle +32 -29
- package/android/gradle.properties +3 -3
- package/android/src/main/java/com/reactnativereadium/ReadiumView.kt +88 -28
- package/android/src/main/java/com/reactnativereadium/ReadiumViewManager.kt +20 -19
- package/android/src/main/java/com/reactnativereadium/reader/BaseReaderFragment.kt +27 -6
- package/android/src/main/java/com/reactnativereadium/reader/EpubReaderFragment.kt +53 -69
- package/android/src/main/java/com/reactnativereadium/reader/PositionLabelManager.kt +132 -0
- package/android/src/main/java/com/reactnativereadium/reader/ReaderService.kt +64 -65
- package/android/src/main/java/com/reactnativereadium/reader/ReaderViewModel.kt +6 -85
- package/android/src/main/java/com/reactnativereadium/reader/VisualReaderFragment.kt +32 -2
- package/android/src/main/java/com/reactnativereadium/utils/FragmentFactory.kt +2 -3
- package/android/src/main/java/com/reactnativereadium/utils/JsonExtensions.kt +61 -0
- package/android/src/main/java/com/reactnativereadium/utils/MetadataNormalizer.kt +183 -0
- package/android/src/main/java/com/reactnativereadium/utils/NormalizedMetadata.kt +179 -0
- package/android/src/main/java/com/reactnativereadium/utils/extensions/InputStream.kt +0 -9
- package/ios/App/AppModule.swift +3 -9
- package/ios/Common/Toolkit/Extensions/Locator.swift +1 -1
- package/ios/Data/Bookmark.swift +1 -1
- package/ios/Reader/Common/ReaderViewController.swift +118 -21
- package/ios/Reader/EPUB/AssociatedColors.swift +1 -1
- package/ios/Reader/EPUB/EPUBHTTPServer.swift +13 -0
- package/ios/Reader/EPUB/EPUBModule.swift +1 -1
- package/ios/Reader/EPUB/EPUBViewController.swift +3 -4
- package/ios/Reader/ReaderFormatModule.swift +1 -1
- package/ios/Reader/ReaderModule.swift +1 -1
- package/ios/Reader/ReaderService.swift +70 -35
- package/ios/ReadiumView.swift +62 -25
- package/ios/ReadiumViewManager.m +1 -1
- package/lib/src/ReadiumViewNativeComponent.d.ts +19 -0
- package/lib/src/ReadiumViewNativeComponent.js +10 -0
- package/lib/src/components/BaseReadiumView.d.ts +1 -2
- package/lib/src/components/BaseReadiumView.js +3 -7
- package/lib/src/components/ReadiumView.js +15 -15
- package/lib/src/components/ReadiumView.web.js +100 -21
- package/lib/src/interfaces/BaseReadiumViewProps.d.ts +2 -1
- package/lib/src/interfaces/Preferences.d.ts +3 -2
- package/lib/src/interfaces/PublicationMetadata.d.ts +114 -0
- package/lib/src/interfaces/PublicationMetadata.js +1 -0
- package/lib/src/interfaces/PublicationReady.d.ts +15 -0
- package/lib/src/interfaces/PublicationReady.js +1 -0
- package/lib/src/interfaces/index.d.ts +2 -0
- package/lib/src/interfaces/index.js +2 -0
- package/lib/src/utils/index.d.ts +0 -1
- package/lib/src/utils/index.js +0 -1
- package/lib/web/hooks/index.d.ts +3 -2
- package/lib/web/hooks/index.js +3 -2
- package/lib/web/hooks/useLocationObserver.d.ts +2 -1
- package/lib/web/hooks/useLocationObserver.js +18 -11
- package/lib/web/hooks/useNavigator.d.ts +12 -0
- package/lib/web/hooks/useNavigator.js +87 -0
- package/lib/web/hooks/usePositionLabel.d.ts +9 -0
- package/lib/web/hooks/usePositionLabel.js +33 -0
- package/lib/web/hooks/usePreferencesObserver.d.ts +2 -0
- package/lib/web/hooks/usePreferencesObserver.js +54 -0
- package/lib/web/utils/manifestFetcher.d.ts +8 -0
- package/lib/web/utils/manifestFetcher.js +28 -0
- package/lib/web/utils/manifestNormalizer.d.ts +8 -0
- package/lib/web/utils/manifestNormalizer.js +70 -0
- package/lib/web/utils/metadataNormalizer.d.ts +53 -0
- package/lib/web/utils/metadataNormalizer.js +220 -0
- package/lib/web/utils/navigatorListeners.d.ts +6 -0
- package/lib/web/utils/navigatorListeners.js +50 -0
- package/lib/web/utils/publicationUtils.d.ts +15 -0
- package/lib/web/utils/publicationUtils.js +39 -0
- package/package.json +24 -14
- package/react-native-readium.podspec +7 -5
- package/src/ReadiumViewNativeComponent.ts +35 -0
- package/src/components/BaseReadiumView.tsx +3 -10
- package/src/components/ReadiumView.tsx +15 -15
- package/src/components/ReadiumView.web.tsx +120 -27
- package/src/interfaces/BaseReadiumViewProps.ts +2 -1
- package/src/interfaces/Preferences.ts +3 -2
- package/src/interfaces/PublicationMetadata.ts +141 -0
- package/src/interfaces/PublicationReady.ts +18 -0
- package/src/interfaces/index.ts +2 -0
- package/src/utils/index.ts +0 -1
- package/web/hooks/index.ts +3 -2
- package/web/hooks/useLocationObserver.ts +24 -11
- package/web/hooks/useNavigator.ts +146 -0
- package/web/hooks/usePositionLabel.ts +51 -0
- package/web/hooks/usePreferencesObserver.ts +69 -0
- package/web/utils/manifestFetcher.ts +38 -0
- package/web/utils/manifestNormalizer.ts +74 -0
- package/web/utils/metadataNormalizer.ts +238 -0
- package/web/utils/navigatorListeners.ts +60 -0
- package/web/utils/publicationUtils.ts +47 -0
- package/android/src/main/java/com/reactnativereadium/search/SearchFragment.kt +0 -100
- package/android/src/main/java/com/reactnativereadium/search/SearchPagingSource.kt +0 -44
- package/android/src/main/java/com/reactnativereadium/search/SearchResultAdapter.kt +0 -68
- package/android/src/main/java/com/reactnativereadium/utils/R2DispatcherActivity.kt +0 -45
- package/android/src/main/java/com/reactnativereadium/utils/SectionDecoration.kt +0 -98
- package/android/src/main/java/com/reactnativereadium/utils/SingleClickListener.kt +0 -32
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Bitmap.kt +0 -23
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Context.kt +0 -16
- package/android/src/main/java/com/reactnativereadium/utils/extensions/File.kt +0 -22
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Link.kt +0 -6
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Metadata.kt +0 -6
- package/android/src/main/java/com/reactnativereadium/utils/extensions/URL.kt +0 -29
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Uri.kt +0 -17
- package/android/src/main/res/layout/fragment_search.xml +0 -39
- package/android/src/main/res/layout/item_recycle_search.xml +0 -14
- package/ios/Common/EPUBPreferences.swift +0 -8
- package/ios/Common/Paths.swift +0 -52
- package/ios/Common/Publication.swift +0 -15
- package/ios/Common/Toolkit/Extensions/HTTPClient.swift +0 -65
- package/ios/Common/Toolkit/Extensions/UIImage.swift +0 -12
- package/ios/Common/Toolkit/Extensions/UIViewController.swift +0 -19
- package/ios/Common/Toolkit/ScreenOrientation.swift +0 -13
- package/lib/src/utils/createFragment.d.ts +0 -1
- package/lib/src/utils/createFragment.js +0 -10
- package/lib/web/hooks/useReaderRef.d.ts +0 -3
- package/lib/web/hooks/useReaderRef.js +0 -85
- package/lib/web/hooks/useSettingsObserver.d.ts +0 -2
- package/lib/web/hooks/useSettingsObserver.js +0 -44
- package/src/utils/createFragment.ts +0 -15
- package/web/hooks/useReaderRef.ts +0 -109
- 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,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>
|