Skip to content

Commit 1327077

Browse files
author
Axel
authored
Fix headerHeight and multiline or empty title sections in search result sections (#442)
1 parent db46dbd commit 1327077

File tree

6 files changed

+72
-46
lines changed

6 files changed

+72
-46
lines changed

test-app/r2-testapp/src/main/java/org/readium/r2/testapp/reader/ReaderViewModel.kt

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import androidx.lifecycle.viewModelScope
1414
import androidx.paging.*
1515
import kotlinx.coroutines.channels.Channel
1616
import kotlinx.coroutines.flow.Flow
17+
import kotlinx.coroutines.flow.MutableStateFlow
18+
import kotlinx.coroutines.flow.StateFlow
1719
import kotlinx.coroutines.launch
1820
import org.readium.r2.shared.Search
1921
import org.readium.r2.shared.UserException
@@ -89,25 +91,27 @@ class ReaderViewModel(context: Context, arguments: ReaderContract.Input) : ViewM
8991
}
9092

9193
fun search(query: String) = viewModelScope.launch {
92-
_searchLocators.clear()
94+
if (query == lastSearchQuery) return@launch
95+
lastSearchQuery = query
96+
_searchLocators.value = emptyList()
9397
searchIterator = publication.search(query)
9498
.onFailure { channel.send(Event.Failure(it)) }
9599
.getOrNull()
96-
97100
pagingSourceFactory.invalidate()
98101
channel.send(Event.StartNewSearch)
99102
}
100103

101-
fun cancelSearch() {
102-
viewModelScope.launch {
103-
searchIterator?.close()
104-
searchIterator = null
105-
pagingSourceFactory.invalidate()
106-
}
104+
fun cancelSearch() = viewModelScope.launch {
105+
_searchLocators.value = emptyList()
106+
searchIterator?.close()
107+
searchIterator = null
108+
pagingSourceFactory.invalidate()
107109
}
108110

109-
val searchLocators: List<Locator> get() = _searchLocators
110-
private var _searchLocators = mutableListOf<Locator>()
111+
val searchLocators: StateFlow<List<Locator>> get() = _searchLocators
112+
private var _searchLocators = MutableStateFlow<List<Locator>>(emptyList())
113+
114+
private var lastSearchQuery: String? = null
111115

112116
private var searchIterator: SearchIterator? = null
113117

@@ -119,7 +123,7 @@ class ReaderViewModel(context: Context, arguments: ReaderContract.Input) : ViewM
119123
override suspend fun next(): SearchTry<LocatorCollection?> {
120124
val iterator = searchIterator ?: return Try.success(null)
121125
return iterator.next().onSuccess {
122-
_searchLocators.addAll(it?.locators ?: emptyList())
126+
_searchLocators.value += (it?.locators ?: emptyList())
123127
}
124128
}
125129
}

test-app/r2-testapp/src/main/java/org/readium/r2/testapp/search/SearchFragment.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import android.os.Bundle
1010
import android.view.LayoutInflater
1111
import android.view.View
1212
import android.view.ViewGroup
13+
import androidx.core.view.isVisible
1314
import androidx.fragment.app.Fragment
1415
import androidx.fragment.app.activityViewModels
1516
import androidx.fragment.app.setFragmentResult
@@ -49,6 +50,10 @@ class SearchFragment : Fragment(R.layout.fragment_search) {
4950
.onEach { searchAdapter.submitData(it) }
5051
.launchIn(viewScope)
5152

53+
viewModel.searchLocators
54+
.onEach { binding.noResultLabel.isVisible = it.isEmpty() }
55+
.launchIn(viewScope)
56+
5257
viewModel.channel
5358
.receive(viewLifecycleOwner) { event ->
5459
when (event) {
@@ -63,7 +68,7 @@ class SearchFragment : Fragment(R.layout.fragment_search) {
6368
layoutManager = LinearLayoutManager(activity)
6469
addItemDecoration(SectionDecoration(context, object : SectionDecoration.Listener {
6570
override fun isStartOfSection(itemPos: Int): Boolean =
66-
viewModel.searchLocators.run {
71+
viewModel.searchLocators.value.run {
6772
when {
6873
itemPos == 0 -> true
6974
itemPos < 0 -> false
@@ -73,7 +78,7 @@ class SearchFragment : Fragment(R.layout.fragment_search) {
7378
}
7479

7580
override fun sectionTitle(itemPos: Int): String =
76-
viewModel.searchLocators.getOrNull(itemPos)?.title ?: ""
81+
viewModel.searchLocators.value.getOrNull(itemPos)?.title ?: ""
7782
}))
7883
addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
7984
}

test-app/r2-testapp/src/main/java/org/readium/r2/testapp/utils/SectionDecoration.kt

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ class SectionDecoration(
2929
}
3030

3131
private lateinit var headerView: View
32-
private lateinit var sectionTitle: TextView
33-
34-
private val headerHeight get() = headerView.height
32+
private lateinit var sectionTitleView: TextView
3533

3634
override fun getItemOffsets(
3735
outRect: Rect,
@@ -41,32 +39,42 @@ class SectionDecoration(
4139
) {
4240
super.getItemOffsets(outRect, view, parent, state)
4341
val pos = parent.getChildAdapterPosition(view)
44-
if (listener.isStartOfSection(pos))
45-
outRect.top = headerHeight
42+
initHeaderViewIfNeeded(parent)
43+
if (listener.sectionTitle(pos) != "" && listener.isStartOfSection(pos)) {
44+
sectionTitleView.text = listener.sectionTitle(pos)
45+
fixLayoutSize(headerView, parent)
46+
outRect.top = headerView.height
47+
}
4648
}
4749

4850
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
4951
super.onDrawOver(c, parent, state)
50-
SectionHeaderBinding.inflate(
51-
LayoutInflater.from(context),
52-
parent,
53-
false
54-
).apply {
55-
headerView = root
56-
sectionTitle = header
57-
}
58-
fixLayoutSize(headerView, parent)
52+
initHeaderViewIfNeeded(parent)
5953

6054
val children = parent.children.toList()
6155
children.forEach { child ->
6256
val pos = parent.getChildAdapterPosition(child)
63-
if (pos != NO_POSITION && (listener.isStartOfSection(pos) || isTopChild(child, children))) {
64-
sectionTitle.text = listener.sectionTitle(pos)
57+
if (pos != NO_POSITION && listener.sectionTitle(pos) != "" &&
58+
(listener.isStartOfSection(pos) || isTopChild(child, children))) {
59+
sectionTitleView.text = listener.sectionTitle(pos)
60+
fixLayoutSize(headerView, parent)
6561
drawHeader(c, child, headerView)
6662
}
6763
}
6864
}
6965

66+
private fun initHeaderViewIfNeeded(parent: RecyclerView) {
67+
if (::headerView.isInitialized) return
68+
SectionHeaderBinding.inflate(
69+
LayoutInflater.from(context),
70+
parent,
71+
false
72+
).apply {
73+
headerView = root
74+
sectionTitleView = header
75+
}
76+
}
77+
7078
private fun fixLayoutSize(v: View, parent: ViewGroup) {
7179
val widthSpec = View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY)
7280
val heightSpec = View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED)

test-app/r2-testapp/src/main/res/layout/fragment_search.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,16 @@
2424
app:layout_constraintEnd_toEndOf="@id/search_overlay"
2525
app:layout_constraintStart_toStartOf="@id/search_overlay"
2626
app:layout_constraintTop_toTopOf="@id/search_overlay" />
27-
</androidx.constraintlayout.widget.ConstraintLayout>
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>

test-app/r2-testapp/src/main/res/layout/section_header.xml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,17 @@
99
~ LICENSE file present in the project repository where this source code is maintained.
1010
-->
1111

12-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
12+
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
13+
android:id="@+id/header"
1314
android:layout_width="match_parent"
14-
android:layout_height="match_parent"
15+
android:layout_height="wrap_content"
1516
android:background="@color/colorAccent"
16-
android:orientation="vertical">
17-
18-
<TextView
19-
android:id="@+id/header"
20-
android:layout_width="match_parent"
21-
android:layout_height="wrap_content"
22-
android:paddingBottom="10dp"
23-
android:paddingEnd="20dp"
24-
android:paddingStart="20dp"
25-
android:paddingTop="10dp"
26-
android:textAllCaps="true"
27-
android:textStyle="bold" />
28-
29-
</LinearLayout>
17+
android:orientation="vertical"
18+
android:ellipsize="end"
19+
android:maxLines="3"
20+
android:paddingStart="20dp"
21+
android:paddingTop="10dp"
22+
android:paddingEnd="20dp"
23+
android:paddingBottom="10dp"
24+
android:textAllCaps="true"
25+
android:textStyle="bold" />

test-app/r2-testapp/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,5 @@
191191
<string name="brightness_higher">Brightness higher</string>
192192
<string name="tts_slower">TTS slower</string>
193193
<string name="tts_faster">TTS faster</string>
194+
<string name="no_result">No result</string>
194195
</resources>

0 commit comments

Comments
 (0)