Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,15 @@ class Builder(val context: Context) {
is String -> SpannableString(s).apply {
setSpan(o, 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}

is SpannableStringBuilder -> s.apply {
setSpan(o, 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}

is SpannableString -> s.apply {
setSpan(o, 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}

else -> throw IllegalArgumentException("unhandled type $o")
}

Expand Down Expand Up @@ -92,14 +95,20 @@ class Builder(val context: Context) {

fun highlight(span: CharSequence, search: String?): CharSequence {
if (search.isNullOrEmpty()) return span
val normalizedText = Normalizer.normalize(span, Normalizer.Form.NFD)
.replace("\\p{InCombiningDiacriticalMarks}+".toRegex(), "")
.lowercase()
val normalizedText = span.normalise().lowercase()

val startIndexes = normalizedText.allOccurrences(search)
if (startIndexes.isNotEmpty()) {
return highlight(span, search, startIndexes)
}
return span
}

fun highlight(span: CharSequence, search: String?, indexes: List<Int>): CharSequence {
if (search.isNullOrEmpty()) return span
if (indexes.isNotEmpty()) {
val highlighted: Spannable = SpannableString(span)
startIndexes.forEach {
indexes.forEach {
highlighted.setSpan(
BackgroundColorSpan(context.color(R.color.pluto___text_highlight)),
it,
Expand All @@ -112,6 +121,12 @@ class Builder(val context: Context) {
return span
}

fun occurrences(span: CharSequence, search: String?): List<Int> {
if (search.isNullOrEmpty()) return emptyList()
val normalizedText = span.normalise().lowercase()
return normalizedText.allOccurrences(search)
}

fun clickable(span: CharSequence, listener: ClickableSpan): CharSequence {
return span(span, listener)
}
Expand All @@ -124,6 +139,11 @@ class Builder(val context: Context) {
return span(span, StyleSpan(Typeface.ITALIC))
}

private fun CharSequence.normalise(): String {
return Normalizer.normalize(this, Normalizer.Form.NFD)
.replace("\\p{InCombiningDiacriticalMarks}+".toRegex(), "")
}

fun build(): CharSequence {
return spanBuilder
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ internal class ContentFragment : Fragment(R.layout.pluto_network___fragment_cont
private val argumentData: ContentFormatterData?
get() = arguments?.getParcelable(DATA)

private var currentHighlightIndex = 0
private var occurrences = emptyList<Int>()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
onBackPressed { handleBackPress() }
Expand All @@ -50,20 +53,33 @@ internal class ContentFragment : Fragment(R.layout.pluto_network___fragment_cont
binding.editSearch.doOnTextChanged { text, _, _, _ ->
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
text?.toString()?.let { search ->
argumentData?.let {
binding.content.setSpan {
append(highlight(it.content, search.trim()))
append("\n")
}
}

scrollToText(search.trim())
processSearch(search)
}
}
}

binding.previousHighlight.setOnDebounceClickListener {
if (occurrences.isNotEmpty()) {
currentHighlightIndex = (currentHighlightIndex - 1 + occurrences.size) % occurrences.size
scrollToText(occurrences[currentHighlightIndex], binding.editSearch.text.toString())
}
}

binding.nextHighlight.setOnDebounceClickListener {
if (occurrences.isNotEmpty()) {
currentHighlightIndex = (currentHighlightIndex + 1) % occurrences.size
scrollToText(occurrences[currentHighlightIndex], binding.editSearch.text.toString())
}
}

binding.share.setOnDebounceClickListener {
argumentData?.let {
contentSharer.share(Shareable(title = "Share content", content = it.content.toString()))
contentSharer.share(
Shareable(
title = "Share content",
content = it.content.toString()
)
)
}
}
argumentData?.let {
Expand All @@ -88,16 +104,34 @@ internal class ContentFragment : Fragment(R.layout.pluto_network___fragment_cont
}
}

private fun processSearch(search: String) {
currentHighlightIndex = 0
argumentData?.let {
binding.content.setSpan {
occurrences = occurrences(it.content, search.trim())
append(highlight(it.content, search.trim(), occurrences))
append("\n")
binding.searchCount.visibility = if (search.isEmpty()) View.GONE else VISIBLE
binding.searchCount.text = occurrences.size.toString()
val highlightsVisibility = if (occurrences.size < 2) View.GONE else VISIBLE
binding.previousHighlight.visibility = highlightsVisibility
binding.nextHighlight.visibility = highlightsVisibility
}
}

scrollToText(currentHighlightIndex, search.trim())
}

/**
* helps to auto scroll to target search
*/
private fun scrollToText(targetText: String) {
private fun scrollToText(startIndex: Int, targetText: String) {
if (targetText.isEmpty()) {
return
}

val contentText = binding.content.getText().toString().lowercase()
val index = contentText.indexOf(targetText.lowercase())
val index = contentText.indexOf(targetText.lowercase(), startIndex)

if (index != -1) {
binding.content.post {
Expand All @@ -108,7 +142,7 @@ internal class ContentFragment : Fragment(R.layout.pluto_network___fragment_cont
val y = layout.getLineTop(lineNumber)

binding.horizontalScroll.smoothScrollTo(x / 2, 0)
binding.contentNestedScrollView.smoothScrollTo(0, y / 2)
binding.contentNestedScrollView.smoothScrollTo(0, y)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">

<path
android:fillColor="@color/pluto___dark_80"
android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z" />

</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">

<path
android:fillColor="@color/pluto___dark_80"
android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z" />

</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,57 @@
android:textColorHint="@color/pluto___text_dark_40"
android:textSize="@dimen/pluto___text_small"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/clearSearch"
app:layout_constraintEnd_toStartOf="@+id/nextHighlight"
app:layout_constraintStart_toEndOf="@+id/closeSearch"
app:layout_constraintTop_toTopOf="parent" />

<ImageView
android:id="@+id/nextHighlight"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:contentDescription="@string/pluto_network___search_next_highlight"
android:foreground="?android:attr/selectableItemBackground"
android:paddingHorizontal="@dimen/pluto___margin_mini"
android:src="@drawable/pluto_network___ic_arrow_down"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/previousHighlight"
app:layout_constraintStart_toEndOf="@id/editSearch"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />

<ImageView
android:id="@+id/previousHighlight"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:contentDescription="@string/pluto_network___search_previous_highlight"
android:foreground="?android:attr/selectableItemBackground"
android:paddingHorizontal="@dimen/pluto___margin_mini"
android:src="@drawable/pluto_network___ic_arrow_up"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/searchCount"
app:layout_constraintStart_toEndOf="@id/nextHighlight"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />

<TextView
android:id="@+id/searchCount"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:fontFamily="@font/muli_semibold"
android:gravity="center"
android:paddingHorizontal="@dimen/pluto___margin_xsmall"
android:textColor="@color/pluto___text_dark_40"
android:textSize="@dimen/pluto___text_small"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/clearSearch"
app:layout_constraintStart_toEndOf="@id/previousHighlight"
app:layout_constraintTop_toTopOf="parent"
tools:text="10"
tools:visibility="visible" />

<ImageView
android:id="@+id/clearSearch"
android:layout_width="wrap_content"
Expand All @@ -167,6 +214,7 @@
android:paddingHorizontal="@dimen/pluto___margin_xsmall"
android:src="@drawable/pluto_network___ic_close_gray"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/searchCount"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,6 @@
<item quantity="one">1 items</item>
<item quantity="other">%d items</item>
</plurals>
<string name="pluto_network___search_next_highlight">Next highlight</string>
<string name="pluto_network___search_previous_highlight">Previous highlight</string>
</resources>