mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
#1771 Crash Report 3.2: java.lang.IllegalArgumentException CompatFindActionModeCallback.findAll - don't use null and correct searchActivity view states
This commit is contained in:
parent
fe5a94fe80
commit
80f3294782
3
.idea/codeStyles/Project.xml
generated
3
.idea/codeStyles/Project.xml
generated
@ -45,9 +45,6 @@
|
|||||||
<option name="IMPORT_NESTED_CLASSES" value="true" />
|
<option name="IMPORT_NESTED_CLASSES" value="true" />
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<MarkdownNavigatorCodeStyleSettings>
|
|
||||||
<option name="RIGHT_MARGIN" value="72" />
|
|
||||||
</MarkdownNavigatorCodeStyleSettings>
|
|
||||||
<XML>
|
<XML>
|
||||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||||
</XML>
|
</XML>
|
||||||
|
@ -132,12 +132,12 @@ public class CompatFindActionModeCallback
|
|||||||
throw new AssertionError("No WebView for CompatFindActionModeCallback::findAll");
|
throw new AssertionError("No WebView for CompatFindActionModeCallback::findAll");
|
||||||
}
|
}
|
||||||
CharSequence find = editText.getText();
|
CharSequence find = editText.getText();
|
||||||
if (find.length() == 0) {
|
if (find == null || find.length() == 0) {
|
||||||
webView.clearMatches();
|
webView.clearMatches();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
webView.findAllAsync(null);
|
webView.findAllAsync("");
|
||||||
} else {
|
} else {
|
||||||
webView.findAll(null);
|
webView.findAll("");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
@ -169,9 +169,7 @@ public class CompatFindActionModeCallback
|
|||||||
editText.requestFocus();
|
editText.requestFocus();
|
||||||
//show the keyboard
|
//show the keyboard
|
||||||
input.showSoftInput(editText, 0);
|
input.showSoftInput(editText, 0);
|
||||||
|
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,8 +52,7 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemClick
|
|||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.SearchViewModel
|
import org.kiwix.kiwixmobile.core.search.viewmodel.SearchViewModel
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State
|
import org.kiwix.kiwixmobile.core.search.viewmodel.State
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Empty
|
import org.kiwix.kiwixmobile.core.search.viewmodel.State.NoResults
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Initialising
|
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Results
|
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Results
|
||||||
import org.kiwix.kiwixmobile.core.utils.SimpleTextListener
|
import org.kiwix.kiwixmobile.core.utils.SimpleTextListener
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -136,15 +135,19 @@ class SearchActivity : BaseActivity() {
|
|||||||
is Results -> {
|
is Results -> {
|
||||||
searchViewAnimator.setDistinctDisplayedChild(0)
|
searchViewAnimator.setDistinctDisplayedChild(0)
|
||||||
searchAdapter.items = state.values
|
searchAdapter.items = state.values
|
||||||
searchView.setQuery(state.searchString, false)
|
render(state.searchString)
|
||||||
searchInTextMenuItem.isVisible = state.searchString.isNotBlank()
|
|
||||||
}
|
}
|
||||||
Empty -> searchViewAnimator.setDistinctDisplayedChild(1)
|
is NoResults -> {
|
||||||
Initialising -> {
|
searchViewAnimator.setDistinctDisplayedChild(1)
|
||||||
// do nothing
|
render(state.searchString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun render(searchString: String) {
|
||||||
|
searchView.setQuery(searchString, false)
|
||||||
|
searchInTextMenuItem.isEnabled = searchString.isNotBlank()
|
||||||
|
}
|
||||||
|
|
||||||
private fun onItemClick(it: SearchListItem) {
|
private fun onItemClick(it: SearchListItem) {
|
||||||
searchViewModel.actions.offer(OnItemClick(it))
|
searchViewModel.actions.offer(OnItemClick(it))
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,7 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemClick
|
|||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ReceivedPromptForSpeechInput
|
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ReceivedPromptForSpeechInput
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.StartSpeechInputFailed
|
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.StartSpeechInputFailed
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Empty
|
import org.kiwix.kiwixmobile.core.search.viewmodel.State.NoResults
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Initialising
|
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Results
|
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Results
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.DeleteRecentSearch
|
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.DeleteRecentSearch
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.Finish
|
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.Finish
|
||||||
@ -64,7 +63,7 @@ class SearchViewModel @Inject constructor(
|
|||||||
private val searchResultGenerator: SearchResultGenerator
|
private val searchResultGenerator: SearchResultGenerator
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val state = MutableLiveData<State>().apply { value = Initialising }
|
val state = MutableLiveData<State>().apply { value = NoResults("") }
|
||||||
val effects = PublishProcessor.create<SideEffect<*>>()
|
val effects = PublishProcessor.create<SideEffect<*>>()
|
||||||
val actions = PublishProcessor.create<Action>()
|
val actions = PublishProcessor.create<Action>()
|
||||||
private val filter = BehaviorProcessor.createDefault("")
|
private val filter = BehaviorProcessor.createDefault("")
|
||||||
@ -108,10 +107,7 @@ class SearchViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun searchPreviousScreenWhenStateIsValid(): Any =
|
private fun searchPreviousScreenWhenStateIsValid(): Any =
|
||||||
when (val currentState = state.value) {
|
effects.offer(SearchInPreviousScreen(state.value!!.searchString))
|
||||||
is Results -> effects.offer(SearchInPreviousScreen(currentState.searchString))
|
|
||||||
else -> Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showDeleteDialog(longClick: OnItemLongClick) {
|
private fun showDeleteDialog(longClick: OnItemLongClick) {
|
||||||
effects.offer(ShowDeleteSearchDialog(longClick.searchListItem, actions))
|
effects.offer(ShowDeleteSearchDialog(longClick.searchListItem, actions))
|
||||||
@ -144,7 +140,7 @@ class SearchViewModel @Inject constructor(
|
|||||||
Results(searchString, zimSearchResults)
|
Results(searchString, zimSearchResults)
|
||||||
searchString.isEmpty() && recentSearchResults.isNotEmpty() ->
|
searchString.isEmpty() && recentSearchResults.isNotEmpty() ->
|
||||||
Results(searchString, recentSearchResults)
|
Results(searchString, recentSearchResults)
|
||||||
else -> Empty
|
else -> NoResults(searchString)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun searchResultsFromZimReader() = filter
|
private fun searchResultsFromZimReader() = filter
|
||||||
|
@ -21,7 +21,8 @@ package org.kiwix.kiwixmobile.core.search.viewmodel
|
|||||||
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem
|
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem
|
||||||
|
|
||||||
sealed class State {
|
sealed class State {
|
||||||
data class Results(val searchString: String, val values: List<SearchListItem>) : State()
|
abstract val searchString: String
|
||||||
object Empty : State()
|
|
||||||
object Initialising : State()
|
data class Results(override val searchString: String, val values: List<SearchListItem>) : State()
|
||||||
|
data class NoResults(override val searchString: String) : State()
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,7 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemClick
|
|||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ReceivedPromptForSpeechInput
|
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ReceivedPromptForSpeechInput
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.StartSpeechInputFailed
|
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.StartSpeechInputFailed
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Empty
|
import org.kiwix.kiwixmobile.core.search.viewmodel.State.NoResults
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Initialising
|
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Results
|
import org.kiwix.kiwixmobile.core.search.viewmodel.State.Results
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.DeleteRecentSearch
|
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.DeleteRecentSearch
|
||||||
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.Finish
|
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.Finish
|
||||||
@ -99,7 +98,7 @@ internal class SearchViewModelTest {
|
|||||||
inner class StateTests {
|
inner class StateTests {
|
||||||
@Test
|
@Test
|
||||||
fun `initial state is Initialising`() {
|
fun `initial state is Initialising`() {
|
||||||
viewModel.state.test().assertValue(Initialising)
|
viewModel.state.test().assertValue(NoResults(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -115,13 +114,13 @@ internal class SearchViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `non empty search string with no search results is Empty`() {
|
fun `non empty search string with no search results is NoResults`() {
|
||||||
emissionOf(
|
emissionOf(
|
||||||
searchTerm = "a",
|
searchTerm = "a",
|
||||||
searchResults = emptyList(),
|
searchResults = emptyList(),
|
||||||
databaseResults = listOf(RecentSearchListItem(""))
|
databaseResults = listOf(RecentSearchListItem(""))
|
||||||
)
|
)
|
||||||
resultsIn(Empty)
|
resultsIn(NoResults("a"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -136,13 +135,13 @@ internal class SearchViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `empty search string with no database results is Empty`() {
|
fun `empty search string with no database results is NoResults`() {
|
||||||
emissionOf(
|
emissionOf(
|
||||||
searchTerm = "",
|
searchTerm = "",
|
||||||
searchResults = listOf(ZimSearchResultListItem("")),
|
searchResults = listOf(ZimSearchResultListItem("")),
|
||||||
databaseResults = emptyList()
|
databaseResults = emptyList()
|
||||||
)
|
)
|
||||||
resultsIn(Empty)
|
resultsIn(NoResults(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -157,7 +156,7 @@ internal class SearchViewModelTest {
|
|||||||
viewModel.actions.offer(Filter(searchString))
|
viewModel.actions.offer(Filter(searchString))
|
||||||
viewModel.state.test()
|
viewModel.state.test()
|
||||||
.also { testScheduler.advanceTimeBy(100, MILLISECONDS) }
|
.also { testScheduler.advanceTimeBy(100, MILLISECONDS) }
|
||||||
.assertValueHistory(Initialising, Results(searchString, listOf(item)))
|
.assertValueHistory(NoResults(""), Results(searchString, listOf(item)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -175,7 +174,7 @@ internal class SearchViewModelTest {
|
|||||||
)
|
)
|
||||||
viewModel.state.test()
|
viewModel.state.test()
|
||||||
.also { testScheduler.advanceTimeBy(100, MILLISECONDS) }
|
.also { testScheduler.advanceTimeBy(100, MILLISECONDS) }
|
||||||
.assertValueHistory(Initialising, Results("b", listOf(item)))
|
.assertValueHistory(NoResults(""), Results("b", listOf(item)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,11 +204,6 @@ internal class SearchViewModelTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `ClickedSearchInText in invalid state does nothing`() {
|
|
||||||
actionResultsInEffects(ClickedSearchInText)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ClickedSearchInText in Result state offers SearchInPreviousScreen`() {
|
fun `ClickedSearchInText in Result state offers SearchInPreviousScreen`() {
|
||||||
val item = ZimSearchResultListItem("")
|
val item = ZimSearchResultListItem("")
|
||||||
@ -288,8 +282,7 @@ internal class SearchViewModelTest {
|
|||||||
searchResults: List<ZimSearchResultListItem>,
|
searchResults: List<ZimSearchResultListItem>,
|
||||||
databaseResults: List<RecentSearchListItem>
|
databaseResults: List<RecentSearchListItem>
|
||||||
) {
|
) {
|
||||||
val item =
|
every { searchResultGenerator.generateSearchResults(searchTerm) } returns searchResults
|
||||||
every { searchResultGenerator.generateSearchResults(searchTerm) } returns searchResults
|
|
||||||
viewModel.actions.offer(Filter(searchTerm))
|
viewModel.actions.offer(Filter(searchTerm))
|
||||||
recentsFromDb.offer(databaseResults)
|
recentsFromDb.offer(databaseResults)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user